mirror of https://github.com/VLSIDA/OpenRAM.git
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:
commit
7556872a75
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -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).")
|
||||||
|
|
|
||||||
|
|
@ -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"):
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Reference in New Issue