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

View File

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

View File

@ -11,42 +11,55 @@ from vector import vector
from tech import layer from tech import layer
import math import math
class pin_layout: class pin_layout:
""" """
A class to represent a rectangular design pin. It is limited to a A class to represent a rectangular design pin. It is limited to a
single shape. single shape.
""" """
def __init__(self, name, rect, layer_name_num): def __init__(self, name, rect, layer_name_pp):
self.name = name self.name = name
# repack the rect as a vector, just in case # repack the rect as a vector, just in case
if type(rect[0])==vector: if type(rect[0]) == vector:
self.rect = rect self.rect = rect
else: else:
self.rect = [vector(rect[0]),vector(rect[1])] self.rect = [vector(rect[0]), vector(rect[1])]
# snap the rect to the grid # snap the rect to the grid
self.rect = [x.snap_to_grid() for x in self.rect] self.rect = [x.snap_to_grid() for x in self.rect]
debug.check(self.width()>0,"Zero width pin.") debug.check(self.width() > 0, "Zero width pin.")
debug.check(self.height()>0,"Zero height 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 it's a string, use the name
if type(layer_name_num)==int: if type(layer_name_pp) == str:
self.layer = list(layer.keys())[list(layer.values()).index(layer_name_num)] self.layer = layer_name_pp
# else it is required to be a lpp
else: else:
self.layer=layer_name_num for (layer_name, lpp) in layer.items():
self.layer_num = layer[self.layer] 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): def __str__(self):
""" override print function output """ """ 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): 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) 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): def __hash__(self):
""" Implement the hash function for sets etc. """ """ Implement the hash function for sets etc. """
@ -65,15 +78,15 @@ class pin_layout:
def __eq__(self, other): def __eq__(self, other):
""" Check if these are the same pins for duplicate checks """ """ Check if these are the same pins for duplicate checks """
if isinstance(other, self.__class__): 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: else:
return False return False
def bbox(self, pin_list): def bbox(self, pin_list):
""" """
Given a list of layout pins, create a bounding box layout. Given a list of layout pins, create a bounding box layout.
""" """
(ll, ur) = self.rect (ll, ur) = self.rect
min_x = ll.x min_x = ll.x
max_x = ur.x max_x = ur.x
min_y = ll.y min_y = ll.y
@ -85,17 +98,17 @@ class pin_layout:
min_y = min(min_y, pin.ll().y) min_y = min(min_y, pin.ll().y)
max_y = max(max_y, pin.ur().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): def inflate(self, spacing=None):
""" """
Inflate the rectangle by the spacing (or other rule) Inflate the rectangle by the spacing (or other rule)
and return the new rectangle. and return the new rectangle.
""" """
if not spacing: if not spacing:
spacing = 0.5*drc("{0}_to_{0}".format(self.layer)) spacing = 0.5*drc("{0}_to_{0}".format(self.layer))
(ll,ur) = self.rect (ll, ur) = self.rect
spacing = vector(spacing, spacing) spacing = vector(spacing, spacing)
newll = ll - spacing newll = ll - spacing
newur = ur + spacing newur = ur + spacing
@ -104,20 +117,20 @@ class pin_layout:
def intersection(self, other): def intersection(self, other):
""" Check if a shape overlaps with a rectangle """ """ Check if a shape overlaps with a rectangle """
(ll,ur) = self.rect (ll, ur) = self.rect
(oll,our) = other.rect (oll, our) = other.rect
min_x = max(ll.x, oll.x) min_x = max(ll.x, oll.x)
max_x = min(ll.x, oll.x) max_x = min(ll.x, oll.x)
min_y = max(ll.y, oll.y) min_y = max(ll.y, oll.y)
max_y = min(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): def xoverlaps(self, other):
""" Check if shape has x overlap """ """ Check if shape has x overlap """
(ll,ur) = self.rect (ll, ur) = self.rect
(oll,our) = other.rect (oll, our) = other.rect
x_overlaps = False x_overlaps = False
# check if self is within other x range # 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): 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): def yoverlaps(self, other):
""" Check if shape has x overlap """ """ Check if shape has x overlap """
(ll,ur) = self.rect (ll, ur) = self.rect
(oll,our) = other.rect (oll, our) = other.rect
y_overlaps = False y_overlaps = False
# check if self is within other y range # check if self is within other y range
@ -145,15 +158,15 @@ class pin_layout:
def xcontains(self, other): def xcontains(self, other):
""" Check if shape contains the x overlap """ """ Check if shape contains the x overlap """
(ll,ur) = self.rect (ll, ur) = self.rect
(oll,our) = other.rect (oll, our) = other.rect
return (oll.x >= ll.x and our.x <= ur.x) return (oll.x >= ll.x and our.x <= ur.x)
def ycontains(self, other): def ycontains(self, other):
""" Check if shape contains the y overlap """ """ Check if shape contains the y overlap """
(ll,ur) = self.rect (ll, ur) = self.rect
(oll,our) = other.rect (oll, our) = other.rect
return (oll.y >= ll.y and our.y <= ur.y) return (oll.y >= ll.y and our.y <= ur.y)
@ -164,7 +177,7 @@ class pin_layout:
return True return True
# Can only overlap on the same layer # Can only overlap on the same layer
if self.layer != other.layer: if not self.same_lpp(self.lpp, other.lpp):
return False return False
if not self.xcontains(other): if not self.xcontains(other):
@ -182,11 +195,10 @@ class pin_layout:
return True return True
return False return False
def overlaps(self, other): def overlaps(self, other):
""" Check if a shape overlaps with a rectangle """ """ Check if a shape overlaps with a rectangle """
# Can only overlap on the same layer # Can only overlap on the same layer
if self.layer != other.layer: if not self.same_lpp(self.lpp, other.lpp):
return False return False
x_overlaps = self.xoverlaps(other) x_overlaps = self.xoverlaps(other)
@ -208,40 +220,45 @@ class pin_layout:
def normalize(self): def normalize(self):
""" Re-find the LL and UR points after a transform """ """ Re-find the LL and UR points after a transform """
(first,second)=self.rect (first, second) = self.rect
ll = vector(min(first[0],second[0]),min(first[1],second[1])) ll = vector(min(first[0], second[0]), min(first[1], second[1]))
ur = vector(max(first[0],second[0]),max(first[1],second[1])) ur = vector(max(first[0], second[0]), max(first[1], second[1]))
self.rect=[ll,ur] self.rect=[ll, ur]
def transform(self,offset,mirror,rotate): 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. """ Transform with offset, mirror and rotation
(ll,ur) = self.rect to get the absolute pin location.
if mirror=="MX": We must then re-find the ll and ur.
ll=ll.scale(1,-1) The master is the cell instance.
ur=ur.scale(1,-1) """
elif mirror=="MY": (ll, ur) = self.rect
ll=ll.scale(-1,1) if mirror == "MX":
ur=ur.scale(-1,1) ll = ll.scale(1, -1)
elif mirror=="XY": ur = ur.scale(1, -1)
ll=ll.scale(-1,-1) elif mirror == "MY":
ur=ur.scale(-1,-1) 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: if rotate == 90:
ll=ll.rotate_scale(-1,1) ll = ll.rotate_scale(-1, 1)
ur=ur.rotate_scale(-1,1) ur = ur.rotate_scale(-1, 1)
elif rotate==180: elif rotate == 180:
ll=ll.scale(-1,-1) ll = ll.scale(-1, -1)
ur=ur.scale(-1,-1) ur = ur.scale(-1, -1)
elif rotate==270: elif rotate == 270:
ll=ll.rotate_scale(1,-1) ll = ll.rotate_scale(1, -1)
ur=ur.rotate_scale(1,-1) ur = ur.rotate_scale(1, -1)
self.rect=[offset+ll,offset+ur] self.rect = [offset + ll, offset + ur]
self.normalize() self.normalize()
def center(self): 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): def cx(self):
""" Center x """ """ Center x """
@ -258,17 +275,17 @@ class pin_layout:
def ul(self): def ul(self):
""" Upper left point """ """ 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): def lr(self):
""" Lower right point """ """ 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): def ur(self):
""" Upper right point """ """ Upper right point """
return self.rect[1] return self.rect[1]
# The possible y edge values # The possible y edge values
def uy(self): def uy(self):
""" Upper y value """ """ Upper y value """
return self.rect[1].y return self.rect[1].y
@ -287,67 +304,71 @@ class pin_layout:
""" Right x value """ """ Right x value """
return self.rect[1].x return self.rect[1].x
# The edge centers # The edge centers
def rc(self): def rc(self):
""" Right center point """ """ 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): def lc(self):
""" Left center point """ """ 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): def uc(self):
""" Upper center point """ """ 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): def bc(self):
""" Bottom center point """ """ 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): def gds_write_file(self, newLayout):
"""Writes the pin shape and label to GDS""" """Writes the pin shape and label to GDS"""
debug.info(4, "writing pin (" + str(self.layer) + "):" debug.info(4, "writing pin (" + str(self.layer) + "):"
+ str(self.width()) + "x" + str(self.height()) + " @ " + str(self.ll())) + str(self.width()) + "x"
newLayout.addBox(layerNumber=layer[self.layer], + str(self.height()) + " @ " + str(self.ll()))
purposeNumber=0, (layer_num, purpose) = layer[self.layer]
newLayout.addBox(layerNumber=layer_num,
purposeNumber=purpose,
offsetInMicrons=self.ll(), offsetInMicrons=self.ll(),
width=self.width(), width=self.width(),
height=self.height(), height=self.height(),
center=False) center=False)
# Add the tet in the middle of the pin. # 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, newLayout.addText(text=self.name,
layerNumber=layer[self.layer], layerNumber=layer_num,
purposeNumber=0, purposeNumber=purpose,
offsetInMicrons=self.center(), offsetInMicrons=self.center(),
magnification=GDS["zoom"], magnification=GDS["zoom"],
rotate=None) rotate=None)
def compute_overlap(self, other): def compute_overlap(self, other):
""" Calculate the rectangular overlap of two rectangles. """ """ Calculate the rectangular overlap of two rectangles. """
(r1_ll,r1_ur) = self.rect (r1_ll, r1_ur) = self.rect
(r2_ll,r2_ur) = other.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_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_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) 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) dx = min(r1_ur.x, r2_ur.x) - max(r1_ll.x, r2_ll.x)
if dx>=0 and dy>=0: if dx >= 0 and dy >= 0:
return [dx,dy] return [dx, dy]
else: else:
return [0,0] return [0, 0]
def distance(self, other): def distance(self, other):
""" """
Calculate the distance to another pin layout. Calculate the distance to another pin layout.
""" """
(r1_ll,r1_ur) = self.rect (r1_ll, r1_ur) = self.rect
(r2_ll,r2_ur) = other.rect (r2_ll, r2_ur) = other.rect
def dist(x1, y1, x2, y2): def dist(x1, y1, x2, y2):
return math.sqrt((x2-x1)**2 + (y2-y1)**2) return math.sqrt((x2-x1)**2 + (y2-y1)**2)
@ -368,7 +389,7 @@ class pin_layout:
elif left: elif left:
return r1_ll.x - r2_ur.x return r1_ll.x - r2_ur.x
elif right: elif right:
return r2_ll.x - r1.ur.x return r2_ll.x - r1_ur.x
elif bottom: elif bottom:
return r1_ll.y - r2_ur.y return r1_ll.y - r2_ur.y
elif top: elif top:
@ -377,9 +398,8 @@ class pin_layout:
# rectangles intersect # rectangles intersect
return 0 return 0
def overlap_length(self, other): def overlap_length(self, other):
""" """
Calculate the intersection segment and determine its length Calculate the intersection segment and determine its length
""" """
@ -391,21 +411,21 @@ class pin_layout:
intersections = self.compute_overlap_segment(other) intersections = self.compute_overlap_segment(other)
# This is the common case where two pairs of edges overlap # This is the common case where two pairs of edges overlap
# at two points, so just find the distance between those two points # at two points, so just find the distance between those two points
if len(intersections)==2: if len(intersections) == 2:
(p1,p2) = intersections (p1, p2) = intersections
return math.sqrt(pow(p1[0]-p2[0],2) + pow(p1[1]-p2[1],2)) return math.sqrt(pow(p1[0]-p2[0], 2) + pow(p1[1]-p2[1], 2))
else: else:
# This is where we had a corner intersection or none # This is where we had a corner intersection or none
return 0 return 0
def compute_overlap_segment(self, other): def compute_overlap_segment(self, other):
""" """
Calculate the intersection segment of two rectangles Calculate the intersection segment of two rectangles
(if any) (if any)
""" """
(r1_ll,r1_ur) = self.rect (r1_ll, r1_ur) = self.rect
(r2_ll,r2_ur) = other.rect (r2_ll, r2_ur) = other.rect
# The other corners besides ll and ur # The other corners besides ll and ur
r1_ul = vector(r1_ll.x, r1_ur.y) 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) r2_lr = vector(r2_ur.x, r2_ll.y)
from itertools import tee from itertools import tee
def pairwise(iterable): def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..." "s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable) a, b = tee(iterable)
@ -423,14 +444,14 @@ class pin_layout:
# R1 edges CW # R1 edges CW
r1_cw_points = [r1_ll, r1_ul, r1_ur, r1_lr, r1_ll] r1_cw_points = [r1_ll, r1_ul, r1_ur, r1_lr, r1_ll]
r1_edges = [] r1_edges = []
for (p,q) in pairwise(r1_cw_points): for (p, q) in pairwise(r1_cw_points):
r1_edges.append([p,q]) r1_edges.append([p, q])
# R2 edges CW # R2 edges CW
r2_cw_points = [r2_ll, r2_ul, r2_ur, r2_lr, r2_ll] r2_cw_points = [r2_ll, r2_ul, r2_ur, r2_lr, r2_ll]
r2_edges = [] r2_edges = []
for (p,q) in pairwise(r2_cw_points): for (p, q) in pairwise(r2_cw_points):
r2_edges.append([p,q]) r2_edges.append([p, q])
# There are 4 edges on each rectangle # There are 4 edges on each rectangle
# so just brute force check intersection of each # so just brute force check intersection of each
@ -452,18 +473,18 @@ class pin_layout:
q.x >= min(p.x, r.x) and \ q.x >= min(p.x, r.x) and \
q.y <= max(p.y, r.y) and \ q.y <= max(p.y, r.y) and \
q.y >= min(p.y, r.y): q.y >= min(p.y, r.y):
return True return True
return False return False
def segment_intersection(self, s1, s2): def segment_intersection(self, s1, s2):
""" """
Determine the intersection point of two segments Determine the intersection point of two segments
Return the a segment if they overlap. Return the a segment if they overlap.
Return None if they don't. Return None if they don't.
""" """
(a,b) = s1 (a, b) = s1
(c,d) = s2 (c, d) = s2
# Line AB represented as a1x + b1y = c1 # Line AB represented as a1x + b1y = c1
a1 = b.y - a.y a1 = b.y - a.y
b1 = a.x - b.x b1 = a.x - b.x
@ -476,12 +497,22 @@ class pin_layout:
determinant = a1*b2 - a2*b1 determinant = a1*b2 - a2*b1
if determinant!=0: if determinant != 0:
x = (b2*c1 - b1*c2)/determinant x = (b2*c1 - b1*c2)/determinant
y = (a1*c2 - a2*c1)/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): if self.on_segment(a, r, b) and self.on_segment(c, r, d):
return r return r
return None 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) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import os
import gdsMill import gdsMill
import tech import tech
import math import math
@ -16,6 +15,7 @@ from pin_layout import pin_layout
OPTS = globals.OPTS OPTS = globals.OPTS
def ceil(decimal): def ceil(decimal):
""" """
Performs a ceiling function on the decimal place specified by the DRC grid. Performs a ceiling function on the decimal place specified by the DRC grid.
@ -23,29 +23,35 @@ def ceil(decimal):
grid = tech.drc["grid"] grid = tech.drc["grid"]
return math.ceil(decimal * 1 / grid) / (1 / grid) return math.ceil(decimal * 1 / grid) / (1 / grid)
def round_to_grid(number): def round_to_grid(number):
""" """
Rounds an arbitrary number to the grid. Rounds an arbitrary number to the grid.
""" """
grid = tech.drc["grid"] grid = tech.drc["grid"]
# this gets the nearest integer value # this gets the nearest integer value
number_grid = int(round(round((number / grid), 2), 0)) number_grid = int(round(round((number / grid), 2), 0))
number_off = number_grid * grid number_off = number_grid * grid
return number_off return number_off
def snap_to_grid(offset): def snap_to_grid(offset):
""" """
Changes the coodrinate to match the grid settings 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): def pin_center(boundary):
""" """
This returns the center of a pin shape in the vlsiLayout border format. 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. 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. 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) reader.loadFromFile(cell_gds)
cell = {} cell = {}
measure_result = cell_vlsi.getLayoutBorder(layer) measure_result = cell_vlsi.getLayoutBorder(lpp[0])
if measure_result == None: if measure_result:
measure_result = cell_vlsi.measureSize(name) measure_result = cell_vlsi.measureSize(name)
[cell["width"], cell["height"]] = measure_result [cell["width"], cell["height"]] = measure_result
for pin in pin_list: 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) cell[str(pin)] = pin_center(boundary)
return cell return cell
def get_gds_size(name, gds_filename, units, lpp):
def get_gds_size(name, gds_filename, units, layer):
""" """
Open a GDS file and return the size from either the Open a GDS file and return the size from either the
bounding box or a border layer. bounding box or a border layer.
""" """
debug.info(4,"Creating VLSI layout for {}".format(name)) debug.info(4, "Creating VLSI layout for {}".format(name))
cell_vlsi = gdsMill.VlsiLayout(units=units) cell_vlsi = gdsMill.VlsiLayout(units=units)
reader = gdsMill.Gds2reader(cell_vlsi) reader = gdsMill.Gds2reader(cell_vlsi)
reader.loadFromFile(gds_filename) reader.loadFromFile(gds_filename)
cell = {} measure_result = cell_vlsi.getLayoutBorder(lpp)
measure_result = cell_vlsi.getLayoutBorder(layer) if not measure_result:
if measure_result == None: debug.info(2, "Layout border failed. Trying to measure size for {}".format(name))
debug.info(2,"Layout border failed. Trying to measure size for {}".format(name))
measure_result = cell_vlsi.measureSize(name) measure_result = cell_vlsi.measureSize(name)
# returns width,height # returns width,height
return measure_result 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 Open a GDS file and return the library cell size from either the
bounding box or a border layer. bounding box or a border layer.
""" """
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds" cell_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): 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 = {} cell = {}
for pin_name in pin_names: for pin_name in pin_names:
cell[str(pin_name)]=[] cell[str(pin_name)] = []
pin_list=cell_vlsi.getPinShape(str(pin_name)) pin_list = cell_vlsi.getPinShape(str(pin_name))
for pin_shape in pin_list: for pin_shape in pin_list:
(layer,boundary)=pin_shape (lpp, boundary) = pin_shape
rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] rect = [vector(boundary[0], boundary[1]),
# this is a list because other cells/designs may have must-connect pins vector(boundary[2], boundary[3])]
cell[str(pin_name)].append(pin_layout(pin_name, rect, layer)) # 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 return cell
def get_libcell_pins(pin_list, name, units): 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. 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( log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str)) os.path.basename(filename), line_number, str))
if globals.OPTS.debug_level > 0:
import pdb
pdb.set_trace()
assert 0 assert 0
@ -37,6 +40,9 @@ def error(str, return_value=0):
log("ERROR: file {0}: line {1}: {2}\n".format( log("ERROR: file {0}: line {1}: {2}\n".format(
os.path.basename(filename), line_number, str)) os.path.basename(filename), line_number, str))
if globals.OPTS.debug_level > 0:
import pdb
pdb.set_trace()
assert return_value == 0 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 if idBits==('\x07','\x00'): break; #we've reached the end of the structure
elif(idBits==('\x06','\x06')): elif(idBits==('\x06','\x06')):
structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip() 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 thisStructure.name = structName
if(findStructName==thisStructure.name): if(findStructName==thisStructure.name):
wantedStruct=1 wantedStruct=1
@ -767,10 +763,6 @@ class Gds2reader:
if idBits==('\x07','\x00'): break; #we've reached the end of the structure if idBits==('\x07','\x00'): break; #we've reached the end of the structure
elif(idBits==('\x06','\x06')): elif(idBits==('\x06','\x06')):
structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip() 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 thisStructure.name = structName
if(self.debugToTerminal==1): if(self.debugToTerminal==1):
print("\tStructure Name: "+structName) print("\tStructure Name: "+structName)

View File

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

View File

@ -6,8 +6,8 @@
# All rights reserved. # All rights reserved.
# #
""" """
This is called globals.py, but it actually parses all the arguments and performs This is called globals.py, but it actually parses all the arguments
the global OpenRAM setup as well. and performs the global OpenRAM setup as well.
""" """
import os import os
import debug import debug
@ -19,12 +19,13 @@ import re
import copy import copy
import importlib import importlib
VERSION = "1.1.0" VERSION = "1.1.3"
NAME = "OpenRAM v{}".format(VERSION) NAME = "OpenRAM v{}".format(VERSION)
USAGE = "openram.py [options] <config file>\nUse -h for help.\n" USAGE = "openram.py [options] <config file>\nUse -h for help.\n"
OPTS = options.options() OPTS = options.options()
CHECKPOINT_OPTS=None CHECKPOINT_OPTS = None
def parse_args(): def parse_args():
""" Parse the optional arguments for OpenRAM """ """ Parse the optional arguments for OpenRAM """
@ -32,27 +33,55 @@ def parse_args():
global OPTS global OPTS
option_list = { 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"), help="Back annotate simulation"),
optparse.make_option("-o", "--output", dest="output_name", optparse.make_option("-o",
help="Base output file name(s) prefix", metavar="FILE"), "--output",
optparse.make_option("-p", "--outpath", dest="output_path", 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"), help="Output file(s) location"),
optparse.make_option("-i", "--inlinecheck", action="store_true", optparse.make_option("-i",
help="Enable inline LVS/DRC checks", dest="inline_lvsdrc"), "--inlinecheck",
optparse.make_option("-n", "--nocheck", action="store_false", action="store_true",
help="Disable all LVS/DRC checks", dest="check_lvsdrc"), help="Enable inline LVS/DRC checks",
optparse.make_option("-v", "--verbose", action="count", dest="debug_level", 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"), help="Increase the verbosity level"),
optparse.make_option("-t", "--tech", dest="tech_name", optparse.make_option("-t",
"--tech",
dest="tech_name",
help="Technology 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"), 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"), 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)"), 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") help="Don't purge the contents of the temp directory after a successful run")
# -h --help is implicit. # -h --help is implicit.
} }
@ -73,6 +102,7 @@ def parse_args():
return (options, args) return (options, args)
def print_banner(): def print_banner():
""" Conditionally print the banner to stdout """ """ Conditionally print the banner to stdout """
global OPTS global OPTS
@ -117,13 +147,13 @@ def check_versions():
except: except:
OPTS.coverage = 0 OPTS.coverage = 0
def init_openram(config_file, is_unit_test=True): def init_openram(config_file, is_unit_test=True):
"""Initialize the technology, paths, simulators, etc.""" """ Initialize the technology, paths, simulators, etc. """
check_versions() check_versions()
debug.info(1,"Initializing OpenRAM...") debug.info(1, "Initializing OpenRAM...")
setup_paths() 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 # This is a hack. If we are running a unit test and have checkpointed
# the options, load them rather than reading the config file. # the options, load them rather than reading the config file.
# This way, the configuration is reloaded at the start of every unit test. # 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. # that may have been tested.
if is_unit_test and CHECKPOINT_OPTS: if is_unit_test and CHECKPOINT_OPTS:
OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy() OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy()
return return
# Import these to find the executables for checkpointing # 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 # after each unit test
if not CHECKPOINT_OPTS: if not CHECKPOINT_OPTS:
CHECKPOINT_OPTS = copy.copy(OPTS) CHECKPOINT_OPTS = copy.copy(OPTS)
def setup_bitcell(): def setup_bitcell():
""" """
Determine the correct custom or parameterized bitcell for the design. Determine the correct custom or parameterized bitcell for the design.
@ -169,30 +201,29 @@ def setup_bitcell():
# If we have non-1rw ports, # If we have non-1rw ports,
# and the user didn't over-ride the bitcell manually, # and the user didn't over-ride the bitcell manually,
# figure out the right bitcell to use # 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.bitcell = "bitcell"
OPTS.replica_bitcell = "replica_bitcell" OPTS.replica_bitcell = "replica_bitcell"
OPTS.dummy_bitcell = "dummy_bitcell" OPTS.dummy_bitcell = "dummy_bitcell"
else: else:
ports = "" ports = ""
if OPTS.num_rw_ports>0: if OPTS.num_rw_ports > 0:
ports += "{}rw_".format(OPTS.num_rw_ports) 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) 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) ports += "{}r".format(OPTS.num_r_ports)
OPTS.bitcell = "bitcell_"+ports OPTS.bitcell = "bitcell_"+ports
OPTS.replica_bitcell = "replica_bitcell_"+ports OPTS.replica_bitcell = "replica_bitcell_"+ports
OPTS.dummy_bitcell = "dummy_bitcell_"+ports OPTS.dummy_bitcell = "dummy_bitcell_"+ports
else: else:
OPTS.replica_bitcell = "replica_" + OPTS.bitcell OPTS.replica_bitcell = "replica_" + OPTS.bitcell
OPTS.replica_bitcell = "dummy_" + OPTS.bitcell OPTS.replica_bitcell = "dummy_" + OPTS.bitcell
# See if bitcell exists # See if bitcell exists
from importlib import find_loader
try: try:
__import__(OPTS.bitcell) __import__(OPTS.bitcell)
__import__(OPTS.replica_bitcell) __import__(OPTS.replica_bitcell)
@ -206,7 +237,7 @@ def setup_bitcell():
OPTS.replica_bitcell = "dummy_pbitcell" OPTS.replica_bitcell = "dummy_pbitcell"
if not OPTS.is_unit_test: if not OPTS.is_unit_test:
debug.warning("Using the parameterized bitcell which may have suboptimal density.") 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): 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, one selected and its full path. If default is specified,
find that one only and error otherwise. 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: if default_name:
exe_name=find_exe(default_name) exe_name = find_exe(default_name)
if exe_name == None: 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: else:
debug.info(1, "Using {0}: {1}".format(tool_type,exe_name)) debug.info(1, "Using {0}: {1}".format(tool_type, exe_name))
return(default_name,exe_name) return(default_name, exe_name)
else: else:
for name in preferences: for name in preferences:
exe_name = find_exe(name) exe_name = find_exe(name)
if exe_name != None: if exe_name != None:
debug.info(1, "Using {0}: {1}".format(tool_type,exe_name)) debug.info(1, "Using {0}: {1}".format(tool_type, exe_name))
return(name,exe_name) return(name, exe_name)
else: 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: else:
return(None,"") return(None, "")
def read_config(config_file, is_unit_test=True): def read_config(config_file, is_unit_test=True):
""" """
Read the configuration file that defines a few parameters. The Read the configuration file that defines a few parameters. The
config file is just a Python file that defines some config config file is just a Python file that defines some config
options. This will only actually get read the first time. Subsequent options. This will only actually get read the first time. Subsequent
reads will just restore the previous copy (ask mrg) reads will just restore the previous copy (ask mrg)
""" """
global OPTS 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): if not os.path.isabs(config_file):
config_file = os.getcwd() + "/" + config_file config_file = os.getcwd() + "/" + config_file
# Make it a python file if the base name was only given # Make it a python file if the base name was only given
config_file = re.sub(r'\.py$', "", config_file) config_file = re.sub(r'\.py$', "", config_file)
# Expand the user if it is used # Expand the user if it is used
config_file = os.path.expanduser(config_file) 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) 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 # 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 # Import the configuration file of which modules to use
debug.info(1, "Configuration file is " + config_file + ".py") debug.info(1, "Configuration file is " + config_file + ".py")
try: try:
config = importlib.import_module(file_name) config = importlib.import_module(module_name)
except: except:
debug.error("Unable to read configuration file: {0}".format(config_file),2) 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 # The command line will over-ride the config file
# except in the case of the tech name! This is because the tech name # 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) # 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! # Note that if we re-read a config file, nothing will get read again!
if not k in OPTS.__dict__ or k=="tech_name": if k not in OPTS.__dict__ or k == "tech_name":
OPTS.__dict__[k]=v OPTS.__dict__[k] = v
# Massage the output path to be an absolute one # Massage the output path to be an absolute one
if not OPTS.output_path.endswith('/'): 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) debug.info(1, "Output saved in " + OPTS.output_path)
# Remember if we are running unit tests to reduce output # 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 we are only generating a netlist, we can't do DRC/LVS
if OPTS.netlist_only: if OPTS.netlist_only:
OPTS.check_lvsdrc=False OPTS.check_lvsdrc = False
# If config didn't set output name, make a reasonable default. # If config didn't set output name, make a reasonable default.
if (OPTS.output_name == ""): if (OPTS.output_name == ""):
ports = "" ports = ""
if OPTS.num_rw_ports>0: if OPTS.num_rw_ports > 0:
ports += "{}rw_".format(OPTS.num_rw_ports) 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) 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) ports += "{}r_".format(OPTS.num_r_ports)
OPTS.output_name = "sram_{0}b_{1}_{2}{3}".format(OPTS.word_size, OPTS.output_name = "sram_{0}b_{1}_{2}{3}".format(OPTS.word_size,
OPTS.num_words, OPTS.num_words,
@ -302,8 +343,6 @@ def read_config(config_file, is_unit_test=True):
OPTS.tech_name) OPTS.tech_name)
def end_openram(): def end_openram():
""" Clean up openram for a proper exit """ """ Clean up openram for a proper exit """
cleanup_paths() cleanup_paths()
@ -312,9 +351,7 @@ def end_openram():
import verify import verify
verify.print_drc_stats() verify.print_drc_stats()
verify.print_lvs_stats() verify.print_lvs_stats()
verify.print_pex_stats() verify.print_pex_stats()
def cleanup_paths(): def cleanup_paths():
@ -323,40 +360,44 @@ def cleanup_paths():
""" """
global OPTS global OPTS
if not OPTS.purge_temp: 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 return
elif os.path.exists(OPTS.openram_temp): elif os.path.exists(OPTS.openram_temp):
debug.info(1,"Purging temp directory: {}".format(OPTS.openram_temp)) debug.info(1,
# This annoyingly means you have to re-cd into the directory each debug iteration "Purging temp directory: {}".format(OPTS.openram_temp))
#shutil.rmtree(OPTS.openram_temp, ignore_errors=True) # 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)] contents = [os.path.join(OPTS.openram_temp, i) for i in os.listdir(OPTS.openram_temp)]
for i in contents: for i in contents:
if os.path.isfile(i) or os.path.islink(i): if os.path.isfile(i) or os.path.islink(i):
os.remove(i) os.remove(i)
else: else:
shutil.rmtree(i) shutil.rmtree(i)
def setup_paths(): def setup_paths():
""" Set up the non-tech related paths. """ """ Set up the non-tech related paths. """
debug.info(2,"Setting up paths...") debug.info(2, "Setting up paths...")
global OPTS global OPTS
try: try:
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
except: except:
debug.error("$OPENRAM_HOME is not properly defined.",1) 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.check(os.path.isdir(OPENRAM_HOME),
"$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME))
# Add all of the subdirs to the python path # 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)) ] subdirlist = [ item for item in os.listdir(OPENRAM_HOME) if os.path.isdir(os.path.join(OPENRAM_HOME, item)) ]
for subdir in subdirlist: 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), 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)) sys.path.append("{0}".format(full_path))
if not OPTS.openram_temp.endswith('/'): if not OPTS.openram_temp.endswith('/'):
@ -364,13 +405,16 @@ def setup_paths():
debug.info(1, "Temporary files saved in " + OPTS.openram_temp) debug.info(1, "Temporary files saved in " + OPTS.openram_temp)
def is_exe(fpath): def is_exe(fpath):
""" Return true if the given is an executable file that exists. """ """ Return true if the given is an executable file that exists. """
return os.path.exists(fpath) and os.access(fpath, os.X_OK) return os.path.exists(fpath) and os.access(fpath, os.X_OK)
def find_exe(check_exe): 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 # Check if the preferred spice option exists in the path
for path in os.environ["PATH"].split(os.pathsep): for path in os.environ["PATH"].split(os.pathsep):
exe = os.path.join(path, check_exe) exe = os.path.join(path, check_exe)
@ -379,12 +423,14 @@ def find_exe(check_exe):
return exe return exe
return None return None
def init_paths(): def init_paths():
""" Create the temp and output directory if it doesn't exist """ """ Create the temp and output directory if it doesn't exist """
# make the directory if it doesn't exist # make the directory if it doesn't exist
try: 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) os.makedirs(OPTS.openram_temp, 0o750)
except OSError as e: except OSError as e:
if e.errno == 17: # errno.EEXIST if e.errno == 17: # errno.EEXIST
@ -398,8 +444,9 @@ def init_paths():
if e.errno == 17: # errno.EEXIST if e.errno == 17: # errno.EEXIST
os.chmod(OPTS.output_path, 0o750) os.chmod(OPTS.output_path, 0o750)
except: except:
debug.error("Unable to make output directory.",-1) debug.error("Unable to make output directory.", -1)
def set_default_corner(): def set_default_corner():
""" Set the default corner. """ """ Set the default corner. """
@ -416,17 +463,19 @@ def import_tech():
""" Dynamically adds the tech directory to the path and imports it. """ """ Dynamically adds the tech directory to the path and imports it. """
global OPTS 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 # environment variable should point to the technology dir
try: try:
OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH")) OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH"))
except: 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 # Add all of the paths
for tech_path in OPENRAM_TECH.split(":"): 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) sys.path.append(tech_path)
debug.info(1, "Adding technology path: {}".format(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__) + "/" OPTS.openram_tech = os.path.dirname(tech_mod.__file__) + "/"
# Add the tech directory # Add the tech directory
tech_path = OPTS.openram_tech tech_path = OPTS.openram_tech
sys.path.append(tech_path) sys.path.append(tech_path)
@ -453,22 +501,25 @@ def print_time(name, now_time, last_time=None, indentation=2):
global OPTS global OPTS
# Don't print during testing # 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: if last_time:
time = str(round((now_time-last_time).total_seconds(),1)) + " seconds" time = str(round((now_time-last_time).total_seconds(),1)) + " seconds"
else: else:
time = now_time.strftime('%m/%d/%Y %H:%M:%S') 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(): 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 global OPTS
# Check if all arguments are integers for bits, size, banks # 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)) 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)) 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: 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)) 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.write_size is not None:
if (OPTS.word_size % OPTS.write_size != 0): if (OPTS.word_size % OPTS.write_size != 0):
debug.error("Write size needs to be an integer multiple of word size.") 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. # the whole word.
if (OPTS.write_size < 1 or OPTS.write_size > OPTS.word_size/2): 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)) debug.error("Write size needs to be between 1 bit and {0} bits/2.".format(OPTS.word_size))
if not OPTS.tech_name: if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.") debug.error("Tech name must be specified in config file.")
debug.print_raw("Technology: {0}".format(OPTS.tech_name)) debug.print_raw("Technology: {0}".format(OPTS.tech_name))
total_size = OPTS.word_size*OPTS.num_words*OPTS.num_banks total_size = OPTS.word_size*OPTS.num_words*OPTS.num_banks
debug.print_raw("Total size: {} bits".format(total_size)) 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) + debug.warning("Requesting such a large memory size ({0}) will have a large run-time. ".format(total_size) +
"Consider using multiple smaller banks.") "Consider using multiple smaller banks.")
debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size,
OPTS.num_words, OPTS.num_words,
OPTS.num_banks)) OPTS.num_banks))
if (OPTS.write_size != OPTS.word_size): if (OPTS.write_size != OPTS.word_size):
debug.print_raw("Write size: {}".format(OPTS.write_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, 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_r_ports,
OPTS.num_w_ports)) OPTS.num_w_ports))
if OPTS.netlist_only: if OPTS.netlist_only:
debug.print_raw("Netlist only mode (no physical design is being done, netlist_only=False to disable).") 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: if OPTS.analytical_delay:
debug.print_raw("Characterization is disabled (using analytical delay models) (analytical_delay=False to simulate).") debug.print_raw("Characterization is disabled (using analytical delay models) (analytical_delay=False to simulate).")
else: else:
if OPTS.spice_name!="": if OPTS.spice_name != "":
debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name)) debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name))
if OPTS.trim_netlist: if OPTS.trim_netlist:
debug.print_raw("Trimming netlist to speed up characterization (trim_netlist=False to disable).") 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) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import globals
import design import design
from math import log from tech import GDS, layer, spice, parameter
import design
from tech import GDS,layer,spice,parameter
import utils import utils
class dff(design.design): class dff(design.design):
""" """
Memory address flip-flop Memory address flip-flop
@ -19,7 +17,9 @@ class dff(design.design):
pin_names = ["D", "Q", "clk", "vdd", "gnd"] pin_names = ["D", "Q", "clk", "vdd", "gnd"]
type_list = ["INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] 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"]) pin_map = utils.get_libcell_pins(pin_names, "dff", GDS["unit"])
def __init__(self, name="dff"): def __init__(self, name="dff"):

View File

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

View File

@ -5,17 +5,14 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from tech import drc, parameter
import debug import debug
import design import design
import contact import contact
from math import log
from math import sqrt
import math
from vector import vector from vector import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
class wordline_driver(design.design): class wordline_driver(design.design):
""" """
Creates a Wordline Driver Creates a Wordline Driver
@ -58,26 +55,20 @@ class wordline_driver(design.design):
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
# This is just used for measurements,
# so don't add the module
self.inv = factory.create(module_type="pdriver", self.inv = factory.create(module_type="pdriver",
fanout=self.cols, fanout=self.cols,
neg_polarity=True) neg_polarity=True)
self.add_mod(self.inv) 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.nand2 = factory.create(module_type="pnand2")
self.add_mod(self.nand2) self.add_mod(self.nand2)
def route_vdd_gnd(self): 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 # Find the x offsets for where the vias/pins should be placed
a_xoffset = self.nand_inst[0].rx() 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 # this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the nand's too # 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 # Route both supplies
for name in ["vdd", "gnd"]: for name in ["vdd", "gnd"]:
@ -97,11 +90,9 @@ class wordline_driver(design.design):
pin_pos = vector(xoffset, supply_pin.cy()) pin_pos = vector(xoffset, supply_pin.cy())
self.add_power_pin(name, pin_pos) self.add_power_pin(name, pin_pos)
def create_drivers(self): def create_drivers(self):
self.nand_inst = [] self.nand_inst = []
self.inv2_inst = [] self.inv2_inst = []
for row in range(self.rows): for row in range(self.rows):
name_nand = "wl_driver_nand{}".format(row) name_nand = "wl_driver_nand{}".format(row)
name_inv2 = "wl_driver_inv{}".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), self.connect_inst(["wl_bar_{0}".format(row),
"wl_{0}".format(row), "wl_{0}".format(row),
"vdd", "gnd"]) "vdd", "gnd"])
def place_drivers(self): def place_drivers(self):
nand2_xoffset = 2*self.m1_width + 5*self.m1_space nand2_xoffset = 2*self.m1_width + 5*self.m1_space
inv2_xoffset = nand2_xoffset + self.nand2.width inv2_xoffset = nand2_xoffset + self.nand2.width
@ -136,8 +126,8 @@ class wordline_driver(design.design):
y_offset = self.inv.height*row y_offset = self.inv.height*row
inst_mirror = "R0" inst_mirror = "R0"
nand2_offset=[nand2_xoffset, y_offset] nand2_offset = [nand2_xoffset, y_offset]
inv2_offset=[inv2_xoffset, y_offset] inv2_offset = [inv2_xoffset, y_offset]
# add nand 2 # add nand 2
self.nand_inst[row].place(offset=nand2_offset, 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, self.inv2_inst[row].place(offset=inv2_offset,
mirror=inst_mirror) mirror=inst_mirror)
def route_layout(self): def route_layout(self):
""" Route all of the signals """ """ Route all of the signals """
# Wordline enable connection # Wordline enable connection
en_pin=self.add_layout_pin(text="en", en_offset = [self.m1_width + 2 * self.m1_space, 0]
layer="metal2", en_pin = self.add_layout_pin(text="en",
offset=[self.m1_width + 2*self.m1_space,0], layer="metal2",
width=self.m2_width, offset=en_offset,
height=self.height) width=self.m2_width,
height=self.height)
for row in range(self.rows): for row in range(self.rows):
nand_inst = self.nand_inst[row] nand_inst = self.nand_inst[row]
@ -165,7 +154,7 @@ class wordline_driver(design.design):
# en connection # en connection
a_pin = nand_inst.get_pin("A") a_pin = nand_inst.get_pin("A")
a_pos = a_pin.lc() 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", self.add_segment_center(layer="metal1",
start=clk_offset, start=clk_offset,
end=a_pos) end=a_pos)
@ -175,7 +164,7 @@ class wordline_driver(design.design):
# Nand2 out to 2nd inv # Nand2 out to 2nd inv
zr_pos = nand_inst.get_pin("Z").rc() zr_pos = nand_inst.get_pin("Z").rc()
al_pos = inv2_inst.get_pin("A").lc() 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) 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) 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]) 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 # connect the decoder input pin to nand2 B
b_pin = nand_inst.get_pin("B") b_pin = nand_inst.get_pin("B")
b_pos = b_pin.lc() b_pos = b_pin.lc()
# needs to move down since B nand input is nearly aligned with A inv input # needs to move down since B nand input is
up_or_down = self.m2_space if row%2 else -self.m2_space # nearly aligned with A inv input
input_offset = vector(0,b_pos.y + up_or_down) up_or_down = self.m2_space if row % 2 else -self.m2_space
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) 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 # must under the clk line in M1
self.add_layout_pin_segment_center(text="in_{0}".format(row), self.add_layout_pin_segment_center(text="in_{0}".format(row),
layer="metal1", layer="metal1",
@ -194,24 +187,27 @@ class wordline_driver(design.design):
end=mid_via_offset) end=mid_via_offset)
self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=mid_via_offset, offset=mid_via_offset,
directions=("V","V")) directions=("V", "V"))
# now connect to the nand2 B # now connect to the nand2 B
self.add_path("metal2", [mid_via_offset, b_pos]) 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"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=b_pos - vector(0.5*contact.m1m2.height,0), offset=contact_offset,
directions=("H","H")) directions=("H", "H"))
# output each WL on the right # output each WL on the right
wl_offset = inv2_inst.get_pin("Z").rc() wl_offset = inv2_inst.get_pin("Z").rc()
self.add_layout_pin_segment_center(text="wl_{0}".format(row), self.add_layout_pin_segment_center(text="wl_{0}".format(row),
layer="metal1", layer="metal1",
start=wl_offset, 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): 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 = [] stage_effort_list = []
stage1_cout = self.inv.get_cin() stage1_cout = self.inv.get_cin()
@ -225,7 +221,10 @@ class wordline_driver(design.design):
return stage_effort_list return stage_effort_list
def get_wl_en_cin(self): 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 total_cin = self.nand2.get_cin() * self.rows
return total_cin 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 direction import direction
from pin_layout import pin_layout from pin_layout import pin_layout
from vector3d import vector3d
from vector import vector from vector import vector
import grid_utils
from tech import drc
import debug import debug
class pin_group: class pin_group:
""" """
A class to represent a group of rectangular design pin. A class to represent a group of rectangular design pin.
It requires a router to define the track widths and blockages which It requires a router to define the track widths and blockages which
determine how pin shapes get mapped to tracks. determine how pin shapes get mapped to tracks.
It is initially constructed with a single set of (touching) pins. It is initially constructed with a single set of (touching) pins.
""" """
def __init__(self, name, pin_set, router): def __init__(self, name, pin_set, router):
self.name = name self.name = name
# Flag for when it is routed # Flag for when it is routed
self.routed = False self.routed = False
# Flag for when it is enclosed # Flag for when it is enclosed
self.enclosed = False self.enclosed = False
# Remove any redundant pins (i.e. contained in other pins) # Remove any redundant pins (i.e. contained in other pins)
irredundant_pin_set = self.remove_redundant_shapes(list(pin_set)) 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 # and these are represented by separate lists
self.pins = set(irredundant_pin_set) self.pins = set(irredundant_pin_set)
self.router = router self.router = router
# These are the corresponding pin grids for each pin group. # These are the corresponding pin grids for each pin group.
self.grids = set() 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() self.secondary_grids = set()
# The corresponding set of partially blocked grids for each pin group. # 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 blockages for other nets but unblocked
# These are also blockages if we used a simple enclosure to route to a rail. # for routing this group. These are also blockages if we
# used a simple enclosure to route to a rail.
self.blockages = set() self.blockages = set()
# This is a set of pin_layout shapes to cover the grids # This is a set of pin_layout shapes to cover the grids
@ -51,16 +53,16 @@ class pin_group:
def __str__(self): def __str__(self):
""" override print function output """ """ override print function output """
total_string = "(pg {} ".format(self.name) total_string = "(pg {} ".format(self.name)
pin_string = "\n pins={}".format(self.pins) pin_string = "\n pins={}".format(self.pins)
total_string += pin_string total_string += pin_string
grids_string = "\n grids={}".format(self.grids) grids_string = "\n grids={}".format(self.grids)
total_string += grids_string total_string += grids_string
grids_string = "\n secondary={}".format(self.secondary_grids) grids_string = "\n secondary={}".format(self.secondary_grids)
total_string += grids_string total_string += grids_string
if self.enclosed: if self.enclosed:
enclosure_string = "\n enclose={}".format(self.enclosures) enclosure_string = "\n enclose={}".format(self.enclosures)
total_string += enclosure_string total_string += enclosure_string
@ -71,7 +73,7 @@ class pin_group:
def __repr__(self): def __repr__(self):
""" override repr function output """ """ override repr function output """
return str(self) return str(self)
def size(self): def size(self):
return len(self.grids) return len(self.grids)
@ -80,7 +82,7 @@ class pin_group:
def is_routed(self): def is_routed(self):
return self.routed return self.routed
def remove_redundant_shapes(self, pin_list): def remove_redundant_shapes(self, pin_list):
""" """
Remove any pin layout that is contained within another. Remove any pin layout that is contained within another.
@ -88,39 +90,40 @@ class pin_group:
""" """
local_debug = False local_debug = False
if local_debug: 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 # Make a copy of the list to start
new_pin_list = pin_list.copy() new_pin_list = pin_list.copy()
remove_indices = set() remove_indices = set()
# This is n^2, but the number is small # 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 we remove this pin, it can't contain other pins
if index1 in remove_indices: if index1 in remove_indices:
continue continue
for index2,pin2 in enumerate(pin_list): for index2, pin2 in enumerate(pin_list):
# Can't contain yourself, but compare the indices and not the pins # Can't contain yourself,
# but compare the indices and not the pins
# so you can remove duplicate copies. # so you can remove duplicate copies.
if index1==index2: if index1 == index2:
continue continue
# If we already removed it, can't remove it again... # If we already removed it, can't remove it again...
if index2 in remove_indices: if index2 in remove_indices:
continue continue
if pin1.contains(pin2): if pin1.contains(pin2):
if local_debug: 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_indices.add(index2)
# Remove them in decreasing order to not invalidate the indices # Remove them in decreasing order to not invalidate the indices
for i in sorted(remove_indices, reverse=True): for i in sorted(remove_indices, reverse=True):
del new_pin_list[i] del new_pin_list[i]
if local_debug: if local_debug:
debug.info(0,"FINAL : {}".format(new_pin_list)) debug.info(0, "FINAL : {}".format(new_pin_list))
return new_pin_list return new_pin_list
def compute_enclosures(self): def compute_enclosures(self):
@ -130,23 +133,32 @@ class pin_group:
# Enumerate every possible enclosure # Enumerate every possible enclosure
pin_list = [] pin_list = []
for seed in self.grids: 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) enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
pin_list.append(enclosure) 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) enclosure = self.router.compute_pin_enclosure(ll, ur, ll.z)
pin_list.append(enclosure) 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) 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): 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. This assumes the shape will be the dimension of the pin.
""" """
if pin.xoverlaps(enclosure): if pin.xoverlaps(enclosure):
@ -154,9 +166,9 @@ class pin_group:
plc = pin.lc() plc = pin.lc()
prc = pin.rc() prc = pin.rc()
elc = enclosure.lc() elc = enclosure.lc()
erc = enclosure.rc() # erc = enclosure.rc()
ymin = min(plc.y,elc.y) ymin = min(plc.y, elc.y)
ymax = max(plc.y,elc.y) ymax = max(plc.y, elc.y)
ll = vector(plc.x, ymin) ll = vector(plc.x, ymin)
ur = vector(prc.x, ymax) ur = vector(prc.x, ymax)
elif pin.yoverlaps(enclosure): elif pin.yoverlaps(enclosure):
@ -164,9 +176,9 @@ class pin_group:
pbc = pin.bc() pbc = pin.bc()
puc = pin.uc() puc = pin.uc()
ebc = enclosure.bc() ebc = enclosure.bc()
euc = enclosure.uc() # euc = enclosure.uc()
xmin = min(pbc.x,ebc.x) xmin = min(pbc.x, ebc.x)
xmax = max(pbc.x,ebc.x) xmax = max(pbc.x, ebc.x)
ll = vector(xmin, pbc.y) ll = vector(xmin, pbc.y)
ur = vector(xmax, puc.y) ur = vector(xmax, puc.y)
else: else:
@ -180,7 +192,7 @@ class pin_group:
ll = vector(xmin, ymin) ll = vector(xmin, ymin)
ur = vector(xmax, ymax) 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 return None
p = pin_layout(pin.name, [ll, ur], pin.layer) p = pin_layout(pin.name, [ll, ur], pin.layer)
return p return p
@ -195,20 +207,20 @@ class pin_group:
for shape in enclosures: for shape in enclosures:
if shape.xcontains(pin): if shape.xcontains(pin):
edge_list.append(shape) edge_list.append(shape)
# Sort them by their bottom edge # Sort them by their bottom edge
edge_list.sort(key=lambda x: x.by(), reverse=True) edge_list.sort(key=lambda x: x.by(), reverse=True)
# Find the bottom edge that is next to the pin's top edge # Find the bottom edge that is next to the pin's top edge
above_item = None above_item = None
for item in edge_list: for item in edge_list:
if item.by()>=pin.uy(): if item.by() >= pin.uy():
above_item = item above_item = item
else: else:
break break
# There was nothing # There was nothing
if above_item==None: if not above_item:
return None return None
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if above_item.overlaps(pin): if above_item.overlaps(pin):
@ -219,7 +231,7 @@ class pin_group:
return p return p
def find_below_connector(self, pin, enclosures): def find_below_connector(self, pin, enclosures):
""" """
Find the enclosure that is below the pin Find the enclosure that is below the pin
and make a connector to it's upper edge. and make a connector to it's upper edge.
""" """
@ -228,31 +240,31 @@ class pin_group:
for shape in enclosures: for shape in enclosures:
if shape.xcontains(pin): if shape.xcontains(pin):
edge_list.append(shape) edge_list.append(shape)
# Sort them by their upper edge # Sort them by their upper edge
edge_list.sort(key=lambda x: x.uy()) edge_list.sort(key=lambda x: x.uy())
# Find the upper edge that is next to the pin's bottom edge # Find the upper edge that is next to the pin's bottom edge
bottom_item = None bottom_item = None
for item in edge_list: for item in edge_list:
if item.uy()<=pin.by(): if item.uy() <= pin.by():
bottom_item = item bottom_item = item
else: else:
break break
# There was nothing to the left # There was nothing to the left
if bottom_item==None: if not bottom_item:
return None return None
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if bottom_item.overlaps(pin): if bottom_item.overlaps(pin):
return None return None
# Otherwise, make a connector to the item # Otherwise, make a connector to the item
p = self.compute_connector(pin, bottom_item) p = self.compute_connector(pin, bottom_item)
return p return p
def find_left_connector(self, pin, enclosures): def find_left_connector(self, pin, enclosures):
""" """
Find the enclosure that is to the left of the pin Find the enclosure that is to the left of the pin
and make a connector to it's right edge. and make a connector to it's right edge.
""" """
@ -261,31 +273,31 @@ class pin_group:
for shape in enclosures: for shape in enclosures:
if shape.ycontains(pin): if shape.ycontains(pin):
edge_list.append(shape) edge_list.append(shape)
# Sort them by their right edge # Sort them by their right edge
edge_list.sort(key=lambda x: x.rx()) edge_list.sort(key=lambda x: x.rx())
# Find the right edge that is to the pin's left edge # Find the right edge that is to the pin's left edge
left_item = None left_item = None
for item in edge_list: for item in edge_list:
if item.rx()<=pin.lx(): if item.rx() <= pin.lx():
left_item = item left_item = item
else: else:
break break
# There was nothing to the left # There was nothing to the left
if left_item==None: if not left_item:
return None return None
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if left_item.overlaps(pin): if left_item.overlaps(pin):
return None return None
# Otherwise, make a connector to the item # Otherwise, make a connector to the item
p = self.compute_connector(pin, left_item) p = self.compute_connector(pin, left_item)
return p return p
def find_right_connector(self, pin, enclosures): def find_right_connector(self, pin, enclosures):
""" """
Find the enclosure that is to the right of the pin Find the enclosure that is to the right of the pin
and make a connector to it's left edge. and make a connector to it's left edge.
""" """
@ -294,79 +306,79 @@ class pin_group:
for shape in enclosures: for shape in enclosures:
if shape.ycontains(pin): if shape.ycontains(pin):
edge_list.append(shape) edge_list.append(shape)
# Sort them by their right edge # Sort them by their right edge
edge_list.sort(key=lambda x: x.lx(), reverse=True) edge_list.sort(key=lambda x: x.lx(), reverse=True)
# Find the left edge that is next to the pin's right edge # Find the left edge that is next to the pin's right edge
right_item = None right_item = None
for item in edge_list: for item in edge_list:
if item.lx()>=pin.rx(): if item.lx() >= pin.rx():
right_item = item right_item = item
else: else:
break break
# There was nothing to the right # There was nothing to the right
if right_item==None: if not right_item:
return None return None
# If it already overlaps, no connector needed # If it already overlaps, no connector needed
if right_item.overlaps(pin): if right_item.overlaps(pin):
return None return None
# Otherwise, make a connector to the item # Otherwise, make a connector to the item
p = self.compute_connector(pin, right_item) p = self.compute_connector(pin, right_item)
return p return p
def find_smallest_connector(self, pin_list, shape_list): 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. Return the smallest.
""" """
smallest = None smallest = None
for pin in pin_list: for pin in pin_list:
for enclosure in shape_list: for enclosure in shape_list:
new_enclosure = self.compute_connector(pin, enclosure) 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 smallest = new_enclosure
return smallest return smallest
def find_smallest_overlapping(self, pin_list, shape_list): 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. pin in pin_list by a min width.
""" """
smallest_shape = None smallest_shape = None
for pin in pin_list: 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: if overlap_shape:
overlap_length = pin.overlap_length(overlap_shape) # overlap_length = pin.overlap_length(overlap_shape)
if smallest_shape == None or overlap_shape.area()<smallest_shape.area(): if not smallest_shape or overlap_shape.area() < smallest_shape.area():
smallest_shape = overlap_shape smallest_shape = overlap_shape
return smallest_shape
return smallest_shape
def find_smallest_overlapping_pin(self, pin, shape_list): 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. pin in pin_list by a min width.
""" """
smallest_shape = None smallest_shape = None
zindex=self.router.get_zindex(pin.layer_num) zindex = self.router.get_zindex(pin.lpp[0])
(min_width,min_space) = self.router.get_layer_width_space(zindex) (min_width, min_space) = self.router.get_layer_width_space(zindex)
# Now compare it with every other shape to check how much they overlap # Now compare it with every other shape to check how much they overlap
for other in shape_list: for other in shape_list:
overlap_length = pin.overlap_length(other) overlap_length = pin.overlap_length(other)
if overlap_length > min_width: 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 smallest_shape = other
return smallest_shape return smallest_shape
def overlap_any_shape(self, pin_list, shape_list): def overlap_any_shape(self, pin_list, shape_list):
""" """
Does the given pin overlap any of the shapes in the pin list. Does the given pin overlap any of the shapes in the pin list.
@ -378,16 +390,15 @@ class pin_group:
return False return False
def max_pin_layout(self, pin_list): def max_pin_layout(self, pin_list):
""" """
Return the max area pin_layout Return the max area pin_layout
""" """
biggest = pin_list[0] biggest = pin_list[0]
for pin in pin_list: for pin in pin_list:
if pin.area() > biggest.area(): if pin.area() > biggest.area():
biggest = pin biggest = pin
return pin return pin
def enclose_pin_grids(self, ll, dir1=direction.NORTH, dir2=direction.EAST): 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. dir1 and dir2 should be two orthogonal directions.
""" """
offset1= direction.get_offset(dir1) offset1 = direction.get_offset(dir1)
offset2= direction.get_offset(dir2) offset2 = direction.get_offset(dir2)
# We may have started with an empty set # We may have started with an empty set
if not self.grids: debug.check(len(self.grids) > 0, "Cannot seed an grid empty set.")
return None
# Start with the ll and make the widest row # Start with the ll and make the widest row
row = [ll] row = [ll]
# Move in dir1 while we can # Move in dir1 while we can
while True: while True:
next_cell = row[-1] + offset1 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: if next_cell in self.grids and next_cell not in self.router.blocked_grids:
row.append(next_cell) row.append(next_cell)
else: else:
@ -419,7 +429,7 @@ class pin_group:
while True: while True:
next_row = [x+offset2 for x in row] next_row = [x+offset2 for x in row]
for cell in next_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: if cell not in self.grids or cell in self.router.blocked_grids:
break break
else: else:
@ -431,74 +441,87 @@ class pin_group:
# Add a shape from ll to ur # Add a shape from ll to ur
ur = row[-1] ur = row[-1]
return (ll,ur) return (ll, ur)
def enclose_pin(self): def enclose_pin(self):
""" """
If there is one set of connected pin shapes, If there is one set of connected pin shapes,
this will find the smallest rectangle enclosure that overlaps with any pin. this will find the smallest rectangle enclosure that
overlaps with any pin.
If there is not, it simply returns all the enclosures. If there is not, it simply returns all the enclosures.
""" """
self.enclosed = True self.enclosed = True
# Compute the enclosure pin_layout list of the set of tracks # Compute the enclosure pin_layout list of the set of tracks
self.enclosures = self.compute_enclosures() self.enclosures = self.compute_enclosures()
# Find a connector to every pin and add it to the enclosures # Find a connector to every pin and add it to the enclosures
for pin in self.pins: for pin in self.pins:
# If it is contained, it won't need a connector # If it is contained, it won't need a connector
if pin.contained_by_any(self.enclosures): if pin.contained_by_any(self.enclosures):
continue continue
# Find a connector in the cardinal directions # Find a connector in the cardinal directions
# If there is overlap, but it isn't contained, these could all be None # If there is overlap, but it isn't contained,
# These could also be none if the pin is diagonal from the enclosure # 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) left_connector = self.find_left_connector(pin, self.enclosures)
right_connector = self.find_right_connector(pin, self.enclosures) right_connector = self.find_right_connector(pin, self.enclosures)
above_connector = self.find_above_connector(pin, self.enclosures) above_connector = self.find_above_connector(pin, self.enclosures)
below_connector = self.find_below_connector(pin, self.enclosures) below_connector = self.find_below_connector(pin, self.enclosures)
connector_list = [left_connector, right_connector, above_connector, below_connector] connector_list = [left_connector,
filtered_list = list(filter(lambda x: x!=None, connector_list)) right_connector,
if (len(filtered_list)>0): above_connector,
below_connector]
filtered_list = list(filter(lambda x: x != None, connector_list))
if (len(filtered_list) > 0):
import copy import copy
bbox_connector = copy.copy(pin) bbox_connector = copy.copy(pin)
bbox_connector.bbox(filtered_list) bbox_connector.bbox(filtered_list)
self.enclosures.append(bbox_connector) self.enclosures.append(bbox_connector)
# Now, make sure each pin touches an enclosure. If not, add another (diagonal) connector. # Now, make sure each pin touches an enclosure.
# This could only happen when there was no enclosure in any cardinal direction from a pin # 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): if not self.overlap_any_shape(self.pins, self.enclosures):
connector = self.find_smallest_connector(self.pins, self.enclosures) connector = self.find_smallest_connector(self.pins,
if connector==None: self.enclosures)
debug.error("Could not find a connector for {} with {}".format(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") self.router.write_debug_gds("no_connector.gds")
import pdb; pdb.set_trace()
self.enclosures.append(connector) 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() overlap_set = set()
for pin in self.pins: for pin in self.pins:
overlap_set.update(self.transitive_overlap(pin, self.enclosures)) overlap_set.update(self.transitive_overlap(pin, self.enclosures))
# Use the new enclosures and recompute the grids that correspond to them # Use the new enclosures and recompute the grids
if len(overlap_set)<len(self.enclosures): # that correspond to them
if len(overlap_set) < len(self.enclosures):
self.enclosures = overlap_set self.enclosures = overlap_set
self.grids=set() self.grids = set()
# Also update the grid locations with the new (possibly pruned) enclosures # Also update the grid locations with the new
# (possibly pruned) enclosures
for enclosure in self.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) self.grids.update(sufficient)
debug.info(3, "Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name,
debug.info(3,"Computed enclosure(s) {0}\n {1}\n {2}\n {3}".format(self.name, self.pins,
self.pins, self.grids,
self.grids, self.enclosures))
self.enclosures))
def transitive_overlap(self, shape, shape_list): def transitive_overlap(self, shape, shape_list):
""" """
Given shape, find the elements in shape_list that overlap transitively. 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) augmented_shape_list = set(shape_list)
@ -512,31 +535,29 @@ class pin_group:
for cur_shape in augmented_shape_list: for cur_shape in augmented_shape_list:
if old_shape.overlaps(cur_shape): if old_shape.overlaps(cur_shape):
connected_set.add(cur_shape) connected_set.add(cur_shape)
# Remove the original shape # Remove the original shape
connected_set.remove(shape) connected_set.remove(shape)
# if len(connected_set)<len(shape_list): # if len(connected_set)<len(shape_list):
# import pprint # import pprint
# print("S: ",shape) # print("S: ",shape)
# pprint.pprint(shape_list) # pprint.pprint(shape_list)
# pprint.pprint(connected_set) # pprint.pprint(connected_set)
return connected_set return connected_set
def add_enclosure(self, cell): def add_enclosure(self, cell):
""" """
Add the enclosure shape to the given cell. Add the enclosure shape to the given cell.
""" """
for enclosure in self.enclosures: 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, cell.add_rect(layer=enclosure.layer,
offset=enclosure.ll(), offset=enclosure.ll(),
width=enclosure.width(), width=enclosure.width(),
height=enclosure.height()) height=enclosure.height())
def perimeter_grids(self): def perimeter_grids(self):
""" """
@ -551,11 +572,11 @@ class pin_group:
# If we aren't completely enclosed, we are on the perimeter # If we aren't completely enclosed, we are on the perimeter
if neighbor_count < 4: if neighbor_count < 4:
perimeter_set.add(g1) perimeter_set.add(g1)
return perimeter_set return perimeter_set
def adjacent(self, other): def adjacent(self, other):
""" """
Chck if the two pin groups have at least one adjacent pin grid. Chck if the two pin groups have at least one adjacent pin grid.
""" """
# We could optimize this to just check the boundaries # We could optimize this to just check the boundaries
@ -566,9 +587,8 @@ class pin_group:
return False return False
def adjacent_grids(self, other, separation): def adjacent_grids(self, other, separation):
""" """
Determine the sets of grids that are within a separation distance Determine the sets of grids that are within a separation distance
of any grid in the other set. of any grid in the other set.
""" """
@ -580,11 +600,11 @@ class pin_group:
adj_grids.add(g1) adj_grids.add(g1)
return adj_grids return adj_grids
def convert_pin(self): def convert_pin(self):
""" """
Convert the list of pin shapes into sets of routing grids. 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. should be either blocked or part of the pin.
""" """
pin_set = set() pin_set = set()
@ -592,53 +612,59 @@ class pin_group:
blockage_set = set() blockage_set = set()
for pin in self.pins: for pin in self.pins:
debug.info(2," Converting {0}".format(pin)) debug.info(2, " Converting {0}".format(pin))
# Determine which tracks the pin overlaps # Determine which tracks the pin overlaps
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin) (sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
pin)
pin_set.update(sufficient) pin_set.update(sufficient)
partial_set.update(insufficient) partial_set.update(insufficient)
# Blockages will be a super-set of pins since it uses the inflated pin shape. # Blockages will be a super-set of pins since
blockage_in_tracks = self.router.convert_blockage(pin) # it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin)
blockage_set.update(blockage_in_tracks) blockage_set.update(blockage_in_tracks)
# If we have a blockage, we must remove the grids # If we have a blockage, we must remove the grids
# Remember, this excludes the pin blockages already # Remember, this excludes the pin blockages already
shared_set = pin_set & self.router.blocked_grids shared_set = pin_set & self.router.blocked_grids
if len(shared_set)>0: if len(shared_set) > 0:
debug.info(2,"Removing pins {}".format(shared_set)) debug.info(2, "Removing pins {}".format(shared_set))
pin_set.difference_update(shared_set) pin_set.difference_update(shared_set)
shared_set = partial_set & self.router.blocked_grids shared_set = partial_set & self.router.blocked_grids
if len(shared_set)>0: if len(shared_set) > 0:
debug.info(2,"Removing pins {}".format(shared_set)) debug.info(2, "Removing pins {}".format(shared_set))
partial_set.difference_update(shared_set) partial_set.difference_update(shared_set)
shared_set = blockage_set & self.router.blocked_grids shared_set = blockage_set & self.router.blocked_grids
if len(shared_set)>0: if len(shared_set) > 0:
debug.info(2,"Removing blocks {}".format(shared_set)) debug.info(2, "Removing blocks {}".format(shared_set))
blockage_set.difference_update(shared_set) blockage_set.difference_update(shared_set)
# At least one of the groups must have some valid tracks # 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): 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)) # debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
for pin in self.pins: for pin in self.pins:
debug.warning(" Expanding conversion {0}".format(pin)) debug.warning(" Expanding conversion {0}".format(pin))
# Determine which tracks the pin overlaps # Determine which tracks the pin overlaps
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin, expansion=1) (sufficient, insufficient) = self.router.convert_pin_to_tracks(self.name,
pin,
expansion=1)
pin_set.update(sufficient) pin_set.update(sufficient)
partial_set.update(insufficient) partial_set.update(insufficient)
if len(pin_set)==0 and len(partial_set)==0: if len(pin_set) == 0 and len(partial_set) == 0:
debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins)) debug.error("Unable to find unblocked pin {} {}".format(self.name,
self.pins))
self.router.write_debug_gds("blocked_pin.gds") self.router.write_debug_gds("blocked_pin.gds")
# Consider all the grids that would be blocked # Consider all the grids that would be blocked
self.grids = pin_set | partial_set self.grids = pin_set | partial_set
# Remember the secondary grids for removing adjacent pins if len(self.grids) < 0:
self.secondary_grids = partial_set 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, " pins {}".format(self.grids))
debug.info(2," secondary {}".format(self.secondary_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) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from tech import drc,layer from tech import drc, layer
from contact import contact from contact import contact
from pin_group import pin_group
from vector import vector from vector import vector
import debug import debug
import math import math
class router_tech: class router_tech:
""" """
This is a class to hold the router tech constants. This is a class to hold the router tech constants.
@ -25,9 +25,9 @@ class router_tech:
self.layers = layers self.layers = layers
self.rail_track_width = rail_track_width 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_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.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) (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)) via_connect = contact(self.layers, (1, 1))
max_via_size = max(via_connect.width,via_connect.height) max_via_size = max(via_connect.width,via_connect.height)
self.horiz_layer_number = layer[self.horiz_layer_name] self.horiz_lpp = layer[self.horiz_layer_name]
self.vert_layer_number = layer[self.vert_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.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) (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) # 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] self.layer_widths = [self.track_wire, 1, self.track_wire]
def get_zindex(self,layer_num): def same_lpp(self, lpp1, lpp2):
if layer_num==self.horiz_layer_number: """
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 return 0
else: else:
return 1 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) self.rg = supply_grid.supply_grid(self.ll, self.ur, self.track_width)
def route(self, vdd_name="vdd", gnd_name="gnd"): def route(self, vdd_name="vdd", gnd_name="gnd"):
""" """
Add power supply rails and connect all pins to these rails. 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)) 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() start_time = datetime.now()
self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
print_time("Finding pins and blockages",datetime.now(), start_time, 3) 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 # Add the supply rails in a mesh network and connect H/V with vias
start_time = datetime.now() start_time = datetime.now()
# Block everything # Block everything

View File

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

View File

@ -17,7 +17,8 @@ import debug
class library_drc_test(openram_test): class library_drc_test(openram_test):
def runTest(self): 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 import verify
(gds_dir, gds_files) = setup_files() (gds_dir, gds_files) = setup_files()

View File

@ -17,7 +17,8 @@ import debug
class library_lvs_test(openram_test): class library_lvs_test(openram_test):
def runTest(self): 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 import verify
(gds_dir, sp_dir, allnames) = setup_files() (gds_dir, sp_dir, allnames) = setup_files()

View File

@ -18,7 +18,8 @@ import debug
class contact_test(openram_test): class contact_test(openram_test):
def runTest(self): 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")]: for layer_stack in [("metal1", "via1", "metal2"), ("poly", "contact", "metal1")]:
stack_name = ":".join(map(str, layer_stack)) stack_name = ":".join(map(str, layer_stack))

View File

@ -17,7 +17,8 @@ import debug
class path_test(openram_test): class path_test(openram_test):
def runTest(self): 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 wire_path
import tech import tech
import design import design

View File

@ -18,7 +18,8 @@ import debug
class ptx_1finger_nmos_test(openram_test): class ptx_1finger_nmos_test(openram_test):
def runTest(self): 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 import tech
debug.info(2, "Checking min size NMOS with 1 finger") 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): class ptx_1finger_pmos_test(openram_test):
def runTest(self): 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 import tech
debug.info(2, "Checking min size PMOS with 1 finger") 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): class ptx_3finger_nmos_test(openram_test):
def runTest(self): 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 import tech
debug.info(2, "Checking three fingers NMOS") debug.info(2, "Checking three fingers NMOS")

View File

@ -18,7 +18,8 @@ import debug
class ptx_3finger_pmos_test(openram_test): class ptx_3finger_pmos_test(openram_test):
def runTest(self): 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 import tech
debug.info(2, "Checking three fingers PMOS") debug.info(2, "Checking three fingers PMOS")

View File

@ -18,7 +18,8 @@ import debug
class ptx_4finger_nmos_test(openram_test): class ptx_4finger_nmos_test(openram_test):
def runTest(self): 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 import tech
debug.info(2, "Checking three fingers NMOS") debug.info(2, "Checking three fingers NMOS")

View File

@ -18,7 +18,8 @@ import debug
class ptx_test(openram_test): class ptx_test(openram_test):
def runTest(self): 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 import tech
debug.info(2, "Checking three fingers PMOS") debug.info(2, "Checking three fingers PMOS")

View File

@ -17,7 +17,8 @@ import debug
class wire_test(openram_test): class wire_test(openram_test):
def runTest(self): 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 wire
import tech import tech
import design import design

View File

@ -18,7 +18,8 @@ import debug
class replica_pbitcell_test(openram_test): class replica_pbitcell_test(openram_test):
def runTest(self): 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 import dummy_pbitcell
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"

View File

@ -18,7 +18,8 @@ import debug
class pand2_test(openram_test): class pand2_test(openram_test):
def runTest(self): 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 global verify
import verify import verify

View File

@ -18,7 +18,8 @@ import debug
class pand3_test(openram_test): class pand3_test(openram_test):
def runTest(self): 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 global verify
import verify import verify

View File

@ -19,7 +19,8 @@ from sram_factory import factory
class pbitcell_test(openram_test): class pbitcell_test(openram_test):
def runTest(self): 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_rw_ports=1
OPTS.num_w_ports=1 OPTS.num_w_ports=1

View File

@ -18,7 +18,8 @@ import debug
class pbuf_test(openram_test): class pbuf_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing inverter/buffer 4x 8x")
a = factory.create(module_type="pbuf", size=8) a = factory.create(module_type="pbuf", size=8)

View File

@ -18,7 +18,8 @@ import debug
class pdriver_test(openram_test): class pdriver_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing inverter/buffer 4x 8x")
# a tests the error message for specifying conflicting conditions # a tests the error message for specifying conflicting conditions

View File

@ -18,7 +18,8 @@ import debug
class pinv_test(openram_test): class pinv_test(openram_test):
def runTest(self): 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") debug.info(2, "Checking 8x inverter")
tx = factory.create(module_type="pinv", size=8) tx = factory.create(module_type="pinv", size=8)

View File

@ -18,7 +18,8 @@ import debug
class pinv_test(openram_test): class pinv_test(openram_test):
def runTest(self): 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") debug.info(2, "Checking 1x beta=3 size inverter")
tx = factory.create(module_type="pinv", size=1, beta=3) tx = factory.create(module_type="pinv", size=1, beta=3)

View File

@ -18,7 +18,8 @@ import debug
class pinv_test(openram_test): class pinv_test(openram_test):
def runTest(self): 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") debug.info(2, "Checking 1x size inverter")
tx = factory.create(module_type="pinv", size=1) tx = factory.create(module_type="pinv", size=1)

View File

@ -18,7 +18,8 @@ import debug
class pinv_test(openram_test): class pinv_test(openram_test):
def runTest(self): 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") debug.info(2, "Checking 2x size inverter")
tx = factory.create(module_type="pinv", size=2) tx = factory.create(module_type="pinv", size=2)

View File

@ -18,7 +18,8 @@ import debug
class pinvbuf_test(openram_test): class pinvbuf_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing inverter/buffer 4x 8x")
a = factory.create(module_type="pinvbuf", size=8) a = factory.create(module_type="pinvbuf", size=8)

View File

@ -18,7 +18,8 @@ import debug
class pnand2_test(openram_test): class pnand2_test(openram_test):
def runTest(self): 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") debug.info(2, "Checking 2-input nand gate")
tx = factory.create(module_type="pnand2", size=1) tx = factory.create(module_type="pnand2", size=1)

View File

@ -18,7 +18,8 @@ import debug
class pnand3_test(openram_test): class pnand3_test(openram_test):
def runTest(self): 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") debug.info(2, "Checking 3-input nand gate")
tx = factory.create(module_type="pnand3", size=1) tx = factory.create(module_type="pnand3", size=1)

View File

@ -18,7 +18,8 @@ import debug
class pnor2_test(openram_test): class pnor2_test(openram_test):
def runTest(self): 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") debug.info(2, "Checking 2-input nor gate")
tx = factory.create(module_type="pnor2", size=1) tx = factory.create(module_type="pnor2", size=1)

View File

@ -18,7 +18,8 @@ import debug
class precharge_test(openram_test): class precharge_test(openram_test):
def runTest(self): 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 # check precharge in single port
debug.info(2, "Checking precharge for handmade bitcell") 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): class replica_pbitcell_test(openram_test):
def runTest(self): 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 import replica_pbitcell
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"

View File

@ -20,7 +20,8 @@ import debug
class single_level_column_mux_test(openram_test): class single_level_column_mux_test(openram_test):
def runTest(self): 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 # check single level column mux in single port
debug.info(2, "Checking column mux") debug.info(2, "Checking column mux")

View File

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

View File

@ -20,7 +20,8 @@ import debug
class array_test(openram_test): class array_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing 4x4 array for 6t_cell")
a = factory.create(module_type="bitcell_array", cols=4, rows=4) 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): class dummy_row_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing dummy row for 6t_cell")
a = factory.create(module_type="dummy_array", rows=1, cols=4) 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): class pbitcell_array_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell")
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"

View File

@ -16,7 +16,8 @@ import debug
class replica_bitcell_array_test(openram_test): class replica_bitcell_array_test(openram_test):
def runTest(self): 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.bitcell = "pbitcell"
OPTS.replica_bitcell = "replica_pbitcell" OPTS.replica_bitcell = "replica_pbitcell"

View File

@ -18,7 +18,8 @@ import debug
class hierarchical_decoder_test(openram_test): class hierarchical_decoder_test(openram_test):
def runTest(self): 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 # Doesn't require hierarchical decoder
# debug.info(1, "Testing 4 row sample for hierarchical_decoder") # debug.info(1, "Testing 4 row sample for hierarchical_decoder")
# a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4) # 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) a = factory.create(module_type="hierarchical_decoder", rows=16)
self.local_check(a) 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") debug.info(1, "Testing 32 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=32) a = factory.create(module_type="hierarchical_decoder", rows=32)
self.local_check(a) 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") debug.info(1, "Testing 128 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=128) a = factory.create(module_type="hierarchical_decoder", rows=128)
self.local_check(a) 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") debug.info(1, "Testing 512 row sample for hierarchical_decoder")
a = factory.create(module_type="hierarchical_decoder", rows=512) a = factory.create(module_type="hierarchical_decoder", rows=512)
self.local_check(a) self.local_check(a)
@ -57,14 +74,34 @@ class hierarchical_decoder_test(openram_test):
a = factory.create(module_type="hierarchical_decoder", rows=16) a = factory.create(module_type="hierarchical_decoder", rows=16)
self.local_check(a) 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)") debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=32) a = factory.create(module_type="hierarchical_decoder", rows=32)
self.local_check(a) 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)") debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=128) a = factory.create(module_type="hierarchical_decoder", rows=128)
self.local_check(a) 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)") debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
a = factory.create(module_type="hierarchical_decoder", rows=512) a = factory.create(module_type="hierarchical_decoder", rows=512)
self.local_check(a) self.local_check(a)

View File

@ -18,7 +18,8 @@ import debug
class hierarchical_predecode2x4_test(openram_test): class hierarchical_predecode2x4_test(openram_test):
def runTest(self): 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 # checking hierarchical precode 2x4 for single port
debug.info(1, "Testing sample for hierarchy_predecode2x4") debug.info(1, "Testing sample for hierarchy_predecode2x4")

View File

@ -18,7 +18,8 @@ import debug
class hierarchical_predecode3x8_test(openram_test): class hierarchical_predecode3x8_test(openram_test):
def runTest(self): 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 # checking hierarchical precode 3x8 for single port
debug.info(1, "Testing sample for hierarchy_predecode3x8") debug.info(1, "Testing sample for hierarchy_predecode3x8")

View File

@ -17,7 +17,8 @@ import debug
class single_level_column_mux_test(openram_test): class single_level_column_mux_test(openram_test):
def runTest(self): 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 import single_level_column_mux_array
# check single level column mux array in single port # check single level column mux array in single port

View File

@ -18,7 +18,8 @@ import debug
class precharge_test(openram_test): class precharge_test(openram_test):
def runTest(self): 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 # check precharge array in single port
debug.info(2, "Checking 3 column precharge") debug.info(2, "Checking 3 column precharge")

View File

@ -20,7 +20,8 @@ import debug
class wordline_driver_test(openram_test): class wordline_driver_test(openram_test):
def runTest(self): 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 # check wordline driver for single port
debug.info(2, "Checking driver") debug.info(2, "Checking driver")

View File

@ -18,7 +18,8 @@ import debug
class sense_amp_test(openram_test): class sense_amp_test(openram_test):
def runTest(self): 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 # check sense amp array for single port
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2") 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): class write_driver_test(openram_test):
def runTest(self): 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 # check write driver array for single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8") 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): class write_driver_test(openram_test):
def runTest(self): 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 # check write driver array for single port
debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4") 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() (OPTS, args) = globals.parse_args()
del sys.argv[1:] del sys.argv[1:]
header(__file__, OPTS.tech_name) 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): class write_mask_and_array_test(openram_test):
def runTest(self): 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 # check write driver array for single port
debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4") 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): class dff_array_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing dff_array for 3x3")
a = factory.create(module_type="dff_array", rows=3, columns=3) 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): class dff_buf_array_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing dff_buf_array for 3x3")
a = factory.create(module_type="dff_buf_array", rows=3, columns=3) 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): class dff_buf_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing dff_buf 4x 8x")
a = factory.create(module_type="dff_buf", inv1_size=4, inv2_size=8) 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): class tri_gate_array_test(openram_test):
def runTest(self): 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") 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) 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): class delay_chain_test(openram_test):
def runTest(self): 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") debug.info(2, "Testing delay_chain")
a = factory.create(module_type="delay_chain", fanout_list=[4, 4, 4, 4]) 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): class replica_bitcell_array_test(openram_test):
def runTest(self): 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.bitcell = "bitcell_1rw_1r"
OPTS.replica_bitcell = "replica_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): class replica_bitcell_array_test(openram_test):
def runTest(self): 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") 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]) 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): class replica_column_test(openram_test):
def runTest(self): 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") 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) 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): class control_logic_test(openram_test):
def runTest(self): 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 control_logic
import tech import tech

View File

@ -18,7 +18,8 @@ import debug
class control_logic_test(openram_test): class control_logic_test(openram_test):
def runTest(self): 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 control_logic
import tech import tech

View File

@ -16,7 +16,8 @@ import debug
class port_address_test(openram_test): class port_address_test(openram_test):
def runTest(self): 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") debug.info(1, "Port address 16 rows")
a = factory.create("port_address", cols=16, rows=16) a = factory.create("port_address", cols=16, rows=16)

View File

@ -16,7 +16,8 @@ import debug
class port_data_test(openram_test): class port_data_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,

View File

@ -18,7 +18,8 @@ import debug
class port_data_test(openram_test): class port_data_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=16, c = sram_config(word_size=16,

View File

@ -18,7 +18,8 @@ import debug
class bank_select_test(openram_test): class bank_select_test(openram_test):
def runTest(self): 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") debug.info(1, "No column mux, rw control logic")
a = factory.create(module_type="bank_select", port="rw") a = factory.create(module_type="bank_select", port="rw")

View File

@ -19,7 +19,8 @@ import debug
class multi_bank_test(openram_test): class multi_bank_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,

View File

@ -19,7 +19,8 @@ import debug
class multi_bank_test(openram_test): class multi_bank_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"

View File

@ -19,7 +19,8 @@ import debug
class psingle_bank_test(openram_test): class psingle_bank_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"

View File

@ -18,7 +18,8 @@ import debug
class single_bank_1rw_1r_test(openram_test): class single_bank_1rw_1r_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r" OPTS.bitcell = "bitcell_1rw_1r"

View File

@ -18,7 +18,8 @@ import debug
class single_bank_1w_1r_test(openram_test): class single_bank_1w_1r_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "bitcell_1w_1r" OPTS.bitcell = "bitcell_1w_1r"

View File

@ -18,7 +18,8 @@ import debug
class single_bank_test(openram_test): class single_bank_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,

View File

@ -18,7 +18,8 @@ import debug
class single_bank_wmask_test(openram_test): class single_bank_wmask_test(openram_test):
def runTest(self): 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 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") #@unittest.skip("SKIPPING 20_psram_1bank_test, multiport layout not complete")
class psram_1bank_2mux_1rw_1w_test(openram_test): class psram_1bank_2mux_1rw_1w_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"

View File

@ -21,7 +21,8 @@ import debug
class psram_1bank_2mux_1rw_1w_wmask_test(openram_test): class psram_1bank_2mux_1rw_1w_wmask_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
@ -58,4 +59,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()
del sys.argv[1:] del sys.argv[1:]
header(__file__, OPTS.tech_name) 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") #@unittest.skip("SKIPPING 20_psram_1bank_2mux_1w_1r_test, odd supply routing error")
class psram_1bank_2mux_1w_1r_test(openram_test): class psram_1bank_2mux_1w_1r_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"

View File

@ -18,8 +18,9 @@ import debug
#@unittest.skip("SKIPPING 20_psram_1bank_2mux_test, wide metal supply routing error") #@unittest.skip("SKIPPING 20_psram_1bank_2mux_test, wide metal supply routing error")
class psram_1bank_2mux_test(openram_test): class psram_1bank_2mux_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"
OPTS.replica_bitcell="replica_pbitcell" OPTS.replica_bitcell="replica_pbitcell"

View File

@ -17,8 +17,9 @@ import debug
class psram_1bank_4mux_1rw_1r_test(openram_test): class psram_1bank_4mux_1rw_1r_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "pbitcell" OPTS.bitcell = "pbitcell"

View File

@ -18,7 +18,8 @@ import debug
class sram_1bank_2mux_1rw_1r_test(openram_test): class sram_1bank_2mux_1rw_1r_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r" 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") #@unittest.skip("SKIPPING 20_psram_1bank_2mux_1w_1r_test, odd supply routing error")
class psram_1bank_2mux_1w_1r_test(openram_test): class psram_1bank_2mux_1w_1r_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "bitcell_1w_1r" OPTS.bitcell = "bitcell_1w_1r"

View File

@ -19,7 +19,8 @@ import debug
class sram_1bank_2mux_test(openram_test): class sram_1bank_2mux_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=32, num_words=32,

View File

@ -21,7 +21,8 @@ import debug
class sram_1bank_2mux_wmask_test(openram_test): class sram_1bank_2mux_wmask_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=8, c = sram_config(word_size=8,
write_size=4, write_size=4,
@ -51,4 +52,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()
del sys.argv[1:] del sys.argv[1:]
header(__file__, OPTS.tech_name) 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): class sram_1bank_32b_1024_wmask_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=32, c = sram_config(word_size=32,
write_size=8, write_size=8,
@ -50,4 +51,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()
del sys.argv[1:] del sys.argv[1:]
header(__file__, OPTS.tech_name) 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): class sram_1bank_4mux_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=64, num_words=64,

View File

@ -18,7 +18,8 @@ import debug
class sram_1bank_8mux_1rw_1r_test(openram_test): class sram_1bank_8mux_1rw_1r_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r" OPTS.bitcell = "bitcell_1rw_1r"

View File

@ -19,7 +19,8 @@ import debug
class sram_1bank_8mux_test(openram_test): class sram_1bank_8mux_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=2, c = sram_config(word_size=2,
num_words=128, num_words=128,

View File

@ -18,7 +18,8 @@ import debug
class sram_1bank_nomux_1rw_1r_test(openram_test): class sram_1bank_nomux_1rw_1r_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
OPTS.bitcell = "bitcell_1rw_1r" OPTS.bitcell = "bitcell_1rw_1r"

View File

@ -19,7 +19,8 @@ import debug
class sram_1bank_nomux_test(openram_test): class sram_1bank_nomux_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=4, c = sram_config(word_size=4,
num_words=16, num_words=16,

View File

@ -21,7 +21,8 @@ import debug
class sram_1bank_nomux_wmask_test(openram_test): class sram_1bank_nomux_wmask_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=8, c = sram_config(word_size=8,
write_size=4, write_size=4,
@ -51,4 +52,4 @@ if __name__ == "__main__":
(OPTS, args) = globals.parse_args() (OPTS, args) = globals.parse_args()
del sys.argv[1:] del sys.argv[1:]
header(__file__, OPTS.tech_name) 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): class sram_2bank_test(openram_test):
def runTest(self): 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 from sram_config import sram_config
c = sram_config(word_size=16, c = sram_config(word_size=16,
num_words=32, num_words=32,

View File

@ -18,7 +18,8 @@ import debug
class timing_sram_test(openram_test): class timing_sram_test(openram_test):
def runTest(self): 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.spice_name="hspice"
OPTS.analytical_delay = False OPTS.analytical_delay = False
OPTS.netlist_only = True OPTS.netlist_only = True

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