OpenRAM v1.1.3

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

View File

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

View File

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

View File

@ -11,13 +11,14 @@ 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:
@ -30,23 +31,35 @@ class pin_layout:
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,7 +78,7 @@ 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
@ -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)
@ -214,8 +226,12 @@ class pin_layout:
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
to get the absolute pin location.
We must then re-find the ll and ur.
The master is the cell instance.
"""
(ll, ur) = self.rect (ll, ur) = self.rect
if mirror == "MX": if mirror == "MX":
ll = ll.scale(1, -1) ll = ll.scale(1, -1)
@ -241,7 +257,8 @@ class pin_layout:
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 """
@ -287,45 +304,49 @@ 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
@ -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,7 +398,6 @@ 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
@ -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)
@ -485,3 +506,13 @@ class pin_layout:
return r return r
return None return None
def same_lpp(self, lpp1, lpp2):
"""
Check if the layers and purposes are the same.
Ignore if purpose is a None.
"""
if lpp1[1] == None or lpp2[1] == None:
return lpp1[0] == lpp2[0]
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]

View File

@ -5,7 +5,6 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
import os
import gdsMill import gdsMill
import tech import tech
import math import math
@ -16,6 +15,7 @@ from pin_layout import pin_layout
OPTS = globals.OPTS OPTS = globals.OPTS
def ceil(decimal): def ceil(decimal):
""" """
Performs a ceiling function on the decimal place specified by the DRC grid. Performs a ceiling function on the decimal place specified by the DRC grid.
@ -23,6 +23,7 @@ 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.
@ -33,19 +34,24 @@ def round_to_grid(number):
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,19 +62,18 @@ 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.
@ -78,21 +83,21 @@ def get_gds_size(name, gds_filename, units, layer):
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):
@ -109,12 +114,15 @@ def get_gds_pins(pin_names, name, gds_filename, units):
cell[str(pin_name)] = [] cell[str(pin_name)] = []
pin_list = cell_vlsi.getPinShape(str(pin_name)) pin_list = cell_vlsi.getPinShape(str(pin_name))
for pin_shape in pin_list: for pin_shape in pin_list:
(layer,boundary)=pin_shape (lpp, boundary) = pin_shape
rect=[vector(boundary[0],boundary[1]),vector(boundary[2],boundary[3])] rect = [vector(boundary[0], boundary[1]),
# this is a list because other cells/designs may have must-connect pins vector(boundary[2], boundary[3])]
cell[str(pin_name)].append(pin_layout(pin_name, rect, layer)) # this is a list because other cells/designs
# may have must-connect pins
cell[str(pin_name)].append(pin_layout(pin_name, rect, lpp))
return cell return cell
def get_libcell_pins(pin_list, name, units): def get_libcell_pins(pin_list, name, units):
""" """
Open a GDS file and find the pins in pin_list as text on a given layer. Open a GDS file and find the pins in pin_list as text on a given layer.

View File

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

View File

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

View File

@ -19,7 +19,8 @@ class VlsiLayout:
self.layerNumbersInUse = [] self.layerNumbersInUse = []
self.debug = False self.debug = False
if name: if name:
self.rootStructureName=name #take the root structure and copy it to a new structure with the new name
self.rootStructureName=self.padText(name)
#create the ROOT structure #create the ROOT structure
self.structures[self.rootStructureName] = GdsStructure() self.structures[self.rootStructureName] = GdsStructure()
self.structures[self.rootStructureName].name = name self.structures[self.rootStructureName].name = name
@ -82,13 +83,9 @@ class VlsiLayout:
return coordinatesRotate return coordinatesRotate
def rename(self,newName): def rename(self,newName):
#make sure the newName is a multiple of 2 characters
if(len(newName)%2 == 1):
#pad with a zero
newName = newName + '\x00'
#take the root structure and copy it to a new structure with the new name #take the root structure and copy it to a new structure with the new name
self.structures[newName] = self.structures[self.rootStructureName] self.structures[newName] = self.structures[self.rootStructureName]
self.structures[newName].name = newName self.structures[newName].name = self.padText(newName)
#and delete the old root #and delete the old root
del self.structures[self.rootStructureName] del self.structures[self.rootStructureName]
self.rootStructureName = newName self.rootStructureName = newName
@ -159,6 +156,7 @@ 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
@ -193,6 +191,7 @@ 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!
try:
if(len(self.structures[startingStructureName].srefs)>0): #does this structure reference any others? if(len(self.structures[startingStructureName].srefs)>0): #does this structure reference any others?
#if so, go through each and call this function again #if so, go through each and call this function again
#if not, return back to the caller (caller can be this function) #if not, return back to the caller (caller can be this function)
@ -204,6 +203,9 @@ class VlsiLayout:
rotateAngle = sref.rotateAngle, rotateAngle = sref.rotateAngle,
transFlags = sref.transFlags, transFlags = sref.transFlags,
coordinates = sref.coordinates) 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]
@ -215,7 +217,7 @@ class VlsiLayout:
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):
@ -246,7 +248,7 @@ class VlsiLayout:
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
@ -256,7 +258,10 @@ class VlsiLayout:
# 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,
# "userUnitsPerMicron",userUnitsPerMicron,
# "layoutUnitsPerMicron",layoutUnitsPerMicron,
# [microns,microns*layoutUnitsPerMicron])
return round(microns*layoutUnitsPerMicron, 0) return round(microns*layoutUnitsPerMicron, 0)
def changeRoot(self,newRoot, create=False): def changeRoot(self,newRoot, create=False):
@ -411,9 +416,7 @@ class VlsiLayout:
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:
@ -422,6 +425,12 @@ class VlsiLayout:
#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
@ -673,7 +691,7 @@ class VlsiLayout:
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)
@ -695,17 +713,17 @@ class VlsiLayout:
return shape_list return shape_list
def processLabelPins(self, lpp):
def processLabelPins(self, layer):
""" """
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]
@ -713,9 +731,10 @@ class VlsiLayout:
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]
@ -726,31 +745,34 @@ class VlsiLayout:
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, lpp):
def getBlockages(self,layer):
""" """
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 = []
@ -761,17 +783,23 @@ class VlsiLayout:
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 Go through all the shapes in a structure and
the form [llx, lly, urx, ury] for rectangles and [coordinate 1, coordinate 2,...] for polygons. 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 (structureName, structureOrigin,
#print(structureName,"u",structureuVector.transpose(),"v",structurevVector.transpose(),"o",structureOrigin.transpose()) 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),
lpp):
if len(boundary.coordinates) != 5: if len(boundary.coordinates) != 5:
# if shape is a polygon (used in DFF) # if shape is a polygon (used in DFF)
boundaryPolygon = [] boundaryPolygon = []
@ -780,7 +808,9 @@ class VlsiLayout:
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,
structureuVector,
structurevVector)
# add the offset # add the offset
polygon = [] polygon = []
for i in range(0, len(boundaryPolygon), 2): for i in range(0, len(boundaryPolygon), 2):
@ -794,12 +824,17 @@ class VlsiLayout:
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
@ -862,6 +897,17 @@ class VlsiLayout:
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):
""" """
Returns boundary area for sorting. Returns boundary area for sorting.

View File

@ -6,8 +6,8 @@
# All rights reserved. # All rights reserved.
# #
""" """
This is called globals.py, but it actually parses all the arguments and performs This is called globals.py, but it actually parses all the arguments
the global OpenRAM setup as well. and performs the global OpenRAM setup as well.
""" """
import os import os
import debug import debug
@ -19,40 +19,69 @@ 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 """
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,10 +147,10 @@ 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...")
@ -146,7 +176,8 @@ 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()
@ -160,6 +191,7 @@ def init_openram(config_file, is_unit_test=True):
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.
@ -192,7 +224,6 @@ def setup_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)
@ -220,7 +251,9 @@ def get_tool(tool_type, preferences, default_name=None):
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)
@ -231,7 +264,9 @@ def get_tool(tool_type, preferences, default_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, "")
@ -245,23 +280,29 @@ def read_config(config_file, is_unit_test=True):
""" """
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)
@ -270,7 +311,7 @@ def read_config(config_file, is_unit_test=True):
# 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
@ -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()
@ -315,19 +354,20 @@ def end_openram():
verify.print_pex_stats() verify.print_pex_stats()
def cleanup_paths(): def cleanup_paths():
""" """
We should clean up the temp directory after execution. We should clean up the temp directory after execution.
""" """
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))
# This annoyingly means you have to re-cd into
# the directory each debug iteration
# shutil.rmtree(OPTS.openram_temp, ignore_errors=True) # 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:
@ -337,7 +377,6 @@ def cleanup_paths():
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...")
@ -348,10 +387,12 @@ def setup_paths():
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)
@ -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
@ -400,6 +446,7 @@ def init_paths():
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,7 +463,8 @@ 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:
@ -426,7 +474,8 @@ def import_tech():
# 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)
@ -462,7 +510,10 @@ def print_time(name, now_time, last_time=None, indentation=2):
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
@ -478,13 +529,12 @@ 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.")

View File

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

View File

@ -10,6 +10,7 @@ import debug
import design import design
from math import log from math import log
from math import sqrt from math import sqrt
from math import ceil
import math import math
import contact import contact
from sram_factory import factory from sram_factory import factory
@ -31,7 +32,7 @@ class hierarchical_decoder(design.design):
self.cell_height = height self.cell_height = height
self.rows = rows self.rows = rows
self.num_inputs = int(math.log(self.rows, 2)) self.num_inputs = math.ceil(math.log(self.rows, 2))
(self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs) (self.no_of_pre2x4,self.no_of_pre3x8)=self.determine_predecodes(self.num_inputs)
self.create_netlist() self.create_netlist()
@ -338,6 +339,7 @@ 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
if (row < self.rows):
name = self.NAND_FORMAT.format(row) name = self.NAND_FORMAT.format(row)
self.nand_inst.append(self.add_inst(name=name, self.nand_inst.append(self.add_inst(name=name,
mod=self.nand2)) mod=self.nand2))
@ -356,6 +358,7 @@ 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
if (row < self.rows):
name = self.NAND_FORMAT.format(row) name = self.NAND_FORMAT.format(row)
self.nand_inst.append(self.add_inst(name=name, self.nand_inst.append(self.add_inst(name=name,
mod=self.nand3)) mod=self.nand3))
@ -527,6 +530,7 @@ 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?
if (row_index < self.rows):
predecode_name = "predecode_{}".format(index_A) predecode_name = "predecode_{}".format(index_A)
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("A"))
predecode_name = "predecode_{}".format(index_B) predecode_name = "predecode_{}".format(index_B)
@ -538,6 +542,7 @@ 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?
if (row_index < self.rows):
predecode_name = "predecode_{}".format(index_A) predecode_name = "predecode_{}".format(index_A)
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("A"))
predecode_name = "predecode_{}".format(index_B) predecode_name = "predecode_{}".format(index_B)

View File

@ -5,17 +5,14 @@
# (acting for and on behalf of Oklahoma State University) # (acting for and on behalf of Oklahoma State University)
# All rights reserved. # All rights reserved.
# #
from tech import drc, parameter
import debug import debug
import design import design
import contact import contact
from math import log
from math import sqrt
import math
from vector import vector from vector import vector
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
class wordline_driver(design.design): class wordline_driver(design.design):
""" """
Creates a Wordline Driver Creates a Wordline Driver
@ -58,26 +55,20 @@ class wordline_driver(design.design):
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def add_modules(self): def add_modules(self):
# This is just used for measurements,
# so don't add the module
self.inv = factory.create(module_type="pdriver", self.inv = factory.create(module_type="pdriver",
fanout=self.cols, fanout=self.cols,
neg_polarity=True) neg_polarity=True)
self.add_mod(self.inv) self.add_mod(self.inv)
self.inv_no_output = factory.create(module_type="pinv",
route_output=False)
self.add_mod(self.inv_no_output)
self.nand2 = factory.create(module_type="pnand2") self.nand2 = factory.create(module_type="pnand2")
self.add_mod(self.nand2) self.add_mod(self.nand2)
def route_vdd_gnd(self): def route_vdd_gnd(self):
""" Add a pin for each row of vdd/gnd which are must-connects next level up. """ """
Add a pin for each row of vdd/gnd which
are must-connects next level up.
"""
# Find the x offsets for where the vias/pins should be placed # Find the x offsets for where the vias/pins should be placed
a_xoffset = self.nand_inst[0].rx() a_xoffset = self.nand_inst[0].rx()
@ -86,7 +77,9 @@ class wordline_driver(design.design):
# this will result in duplicate polygons for rails, but who cares # this will result in duplicate polygons for rails, but who cares
# use the inverter offset even though it will be the nand's too # use the inverter offset even though it will be the nand's too
(gate_offset, y_dir) = self.get_gate_offset(0, self.inv.height, num) (gate_offset, y_dir) = self.get_gate_offset(0,
self.inv.height,
num)
# Route both supplies # Route both supplies
for name in ["vdd", "gnd"]: for name in ["vdd", "gnd"]:
@ -97,8 +90,6 @@ 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 = []
@ -120,7 +111,6 @@ class wordline_driver(design.design):
"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
@ -146,18 +136,17 @@ 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_offset = [self.m1_width + 2 * self.m1_space, 0]
en_pin = self.add_layout_pin(text="en", en_pin = self.add_layout_pin(text="en",
layer="metal2", layer="metal2",
offset=[self.m1_width + 2*self.m1_space,0], offset=en_offset,
width=self.m2_width, width=self.m2_width,
height=self.height) 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]
inv2_inst = self.inv2_inst[row] inv2_inst = self.inv2_inst[row]
@ -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
# nearly aligned with A inv input
up_or_down = self.m2_space if row % 2 else -self.m2_space up_or_down = self.m2_space if row % 2 else -self.m2_space
input_offset = vector(0, b_pos.y + up_or_down) input_offset = vector(0, b_pos.y + up_or_down)
mid_via_offset = vector(clk_offset.x,input_offset.y) + vector(0.5*self.m2_width+self.m2_space+0.5*contact.m1m2.width,0) 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",
@ -198,11 +191,11 @@ class wordline_driver(design.design):
# 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),
@ -211,7 +204,10 @@ class wordline_driver(design.design):
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""" """
Get the relative capacitance of all
the enable connections in the bank
"""
# The enable is connected to a nand2 for every row. # The enable is connected to a nand2 for every row.
total_cin = self.nand2.get_cin() * self.rows total_cin = self.nand2.get_cin() * self.rows
return total_cin return total_cin

View File

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

View File

@ -7,12 +7,10 @@
# #
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.
@ -20,6 +18,7 @@ class pin_group:
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
@ -30,19 +29,22 @@ class pin_group:
# 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
@ -101,7 +103,8 @@ class pin_group:
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
@ -130,18 +133,27 @@ 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)
debug.check(len(new_pin_list) > 0,
"Did not find any enclosures.")
return new_pin_list return new_pin_list
def compute_connector(self, pin, enclosure): def compute_connector(self, pin, enclosure):
@ -154,7 +166,7 @@ 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)
@ -164,7 +176,7 @@ 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)
@ -208,7 +220,7 @@ class pin_group:
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):
@ -241,7 +253,7 @@ class pin_group:
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):
@ -274,7 +286,7 @@ class pin_group:
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):
@ -307,7 +319,7 @@ class pin_group:
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):
@ -319,14 +331,15 @@ class pin_group:
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
@ -341,13 +354,12 @@ class pin_group:
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
@ -355,14 +367,14 @@ class pin_group:
""" """
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
@ -378,7 +390,6 @@ 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
@ -402,8 +413,7 @@ class pin_group:
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]
@ -433,11 +443,11 @@ class pin_group:
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
@ -453,13 +463,18 @@ class pin_group:
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,
right_connector,
above_connector,
below_connector]
filtered_list = list(filter(lambda x: x != None, connector_list)) filtered_list = list(filter(lambda x: x != None, connector_list))
if (len(filtered_list) > 0): if (len(filtered_list) > 0):
import copy import copy
@ -467,29 +482,37 @@ class pin_group:
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
# that correspond to them
if len(overlap_set) < len(self.enclosures): 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,
@ -513,7 +536,6 @@ class pin_group:
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)
@ -525,19 +547,18 @@ class pin_group:
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):
""" """
Return a list of the grids on the perimeter. Return a list of the grids on the perimeter.
@ -566,7 +587,6 @@ 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
@ -584,7 +604,7 @@ class pin_group:
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()
@ -594,11 +614,13 @@ class pin_group:
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
# it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin) blockage_in_tracks = self.router.convert_blockage(pin)
blockage_set.update(blockage_in_tracks) blockage_set.update(blockage_in_tracks)
@ -624,21 +646,25 @@ class pin_group:
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
if len(self.grids) < 0:
debug.error("Did not find any unblocked grids: {}".format(str(self.pins)))
self.router.write_debug_gds("blocked_pin.gds")
# Remember the secondary grids for removing adjacent pins # Remember the secondary grids for removing adjacent pins
self.secondary_grids = partial_set 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))

View File

@ -5,7 +5,7 @@
# (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 sys
import gdsMill import gdsMill
from tech import drc, GDS from tech import drc, GDS
from tech import layer as techlayer from tech import layer as techlayer
@ -17,21 +17,21 @@ from pin_group import pin_group
from vector import vector from vector import vector
from vector3d import vector3d from vector3d import vector3d
from globals import OPTS, print_time from globals import OPTS, print_time
from pprint import pformat
import grid_utils import grid_utils
from datetime import datetime from datetime import datetime
class router(router_tech): class router(router_tech):
""" """
A router class to read an obstruction map from a gds and plan a A router class to read an obstruction map from a gds and plan a
route on a given layer. This is limited to two layer routes. route on a given layer. This is limited to two layer routes.
It populates blockages on a grid class. It populates blockages on a grid class.
""" """
def __init__(self, layers, design, gds_filename=None, rail_track_width=1): def __init__(self, layers, design, gds_filename=None, rail_track_width=1):
""" """
This will instantiate a copy of the gds file or the module at (0,0) and This will instantiate a copy of the gds file or the module at (0,0) and
route on top of this. The blockages from the gds/module will be considered. route on top of this. The blockages from the gds/module will be
considered.
""" """
router_tech.__init__(self, layers, rail_track_width) router_tech.__init__(self, layers, rail_track_width)
@ -51,30 +51,35 @@ class router(router_tech):
self.top_name = self.layout.rootStructureName self.top_name = self.layout.rootStructureName
# print_time("GDS read",datetime.now(), start_time) # print_time("GDS read",datetime.now(), start_time)
### The pin data structures # The pin data structures
# A map of pin names to a set of pin_layout structures # A map of pin names to a set of pin_layout structures
# (i.e. pins with a given label) # (i.e. pins with a given label)
self.pins = {} self.pins = {}
# This is a set of all pins (ignoring names) so that can quickly not create blockages for pins # This is a set of all pins (ignoring names) so that can quickly
# (They will be blocked when we are routing other nets based on their name.) # not create blockages for pins
# (They will be blocked when we are routing other
# nets based on their name.)
self.all_pins = set() self.all_pins = set()
# The labeled pins above categorized into pin groups that are touching/connected. # The labeled pins above categorized into pin groups
# that are touching/connected.
self.pin_groups = {} self.pin_groups = {}
### The blockage data structures # The blockage data structures
# A list of metal shapes (using the same pin_layout structure) that are not pins but blockages. # A list of metal shapes (using the same pin_layout structure)
# that are not pins but blockages.
self.blockages = [] self.blockages = []
# The corresponding set of blocked grids for above pin shapes # The corresponding set of blocked grids for above pin shapes
self.blocked_grids = set() self.blocked_grids = set()
### The routed data structures # The routed data structures
# A list of paths that have been "routed" # A list of paths that have been "routed"
self.paths = [] self.paths = []
# A list of path blockages (they might be expanded for wide metal DRC) # A list of path blockages (they might be expanded for wide metal DRC)
self.path_blockages = [] self.path_blockages = []
# The boundary will determine the limits to the size of the routing grid # The boundary will determine the limits to the size
# of the routing grid
self.boundary = self.layout.measureBoundary(self.top_name) self.boundary = self.layout.measureBoundary(self.top_name)
# These must be un-indexed to get rid of the matrix type # These must be un-indexed to get rid of the matrix type
self.ll = vector(self.boundary[0][0], self.boundary[0][1]) self.ll = vector(self.boundary[0][0], self.boundary[0][1])
@ -91,19 +96,17 @@ class router(router_tech):
# DO NOT clear the blockages as these don't change # DO NOT clear the blockages as these don't change
self.rg.reinit() self.rg.reinit()
def set_top(self, top_name): def set_top(self, top_name):
""" If we want to route something besides the top-level cell.""" """ If we want to route something besides the top-level cell."""
self.top_name = top_name self.top_name = top_name
def is_wave(self, path): def is_wave(self, path):
""" """
Determines if this is a multi-track width wave (True) or a normal route (False) Determines if this is a multi-track width wave (True)
# or a normal route (False)
""" """
return len(path[0]) > 1 return len(path[0]) > 1
def retrieve_pins(self, pin_name): def retrieve_pins(self, pin_name):
""" """
Retrieve the pin shapes on metal 3 from the layout. Retrieve the pin shapes on metal 3 from the layout.
@ -121,7 +124,8 @@ class router(router_tech):
pin = pin_layout(pin_name, rect, layer) pin = pin_layout(pin_name, rect, layer)
pin_set.add(pin) pin_set.add(pin)
debug.check(len(pin_set)>0,"Did not find any pin shapes for {0}.".format(str(pin_name))) debug.check(len(pin_set) > 0,
"Did not find any pin shapes for {0}.".format(str(pin_name)))
self.pins[pin_name] = pin_set self.pins[pin_name] = pin_set
self.all_pins.update(pin_set) self.all_pins.update(pin_set)
@ -129,23 +133,23 @@ class router(router_tech):
for pin in self.pins[pin_name]: for pin in self.pins[pin_name]:
debug.info(3, "Retrieved pin {}".format(str(pin))) debug.info(3, "Retrieved pin {}".format(str(pin)))
def find_blockages(self): def find_blockages(self):
""" """
Iterate through all the layers and write the obstacles to the routing grid. Iterate through all the layers and write the obstacles to the routing grid.
This doesn't consider whether the obstacles will be pins or not. They get reset later This doesn't consider whether the obstacles will be pins or not.
if they are not actually a blockage. They get reset later if they are not actually a blockage.
""" """
debug.info(1, "Finding blockages.") debug.info(1, "Finding blockages.")
for layer in [self.vert_layer_number,self.horiz_layer_number]: for lpp in [self.vert_lpp, self.horiz_lpp]:
self.retrieve_blockages(layer) self.retrieve_blockages(lpp)
def find_pins_and_blockages(self, pin_list): def find_pins_and_blockages(self, pin_list):
""" """
Find the pins and blockages in the design Find the pins and blockages in the design
""" """
# This finds the pin shapes and sorts them into "groups" that are connected # This finds the pin shapes and sorts them into "groups" that
# This must come before the blockages, so we can not count the pins themselves # are connected. This must come before the blockages, so we
# can not count the pins themselves
# as blockages. # as blockages.
start_time = datetime.now() start_time = datetime.now()
for pin_name in pin_list: for pin_name in pin_list:
@ -169,7 +173,8 @@ class router(router_tech):
print_time("Converting blockages", datetime.now(), start_time, 4) print_time("Converting blockages", datetime.now(), start_time, 4)
# This will convert the pins to grid units # This will convert the pins to grid units
# It must be done after blockages to ensure no DRCs between expanded pins and blocked grids # It must be done after blockages to ensure no DRCs
# between expanded pins and blocked grids
start_time = datetime.now() start_time = datetime.now()
for pin in pin_list: for pin in pin_list:
self.convert_pins(pin) self.convert_pins(pin)
@ -184,18 +189,19 @@ class router(router_tech):
# print_time("Combining adjacent pins",datetime.now(), start_time, 4) # print_time("Combining adjacent pins",datetime.now(), start_time, 4)
# Separate any adjacent grids of differing net names that overlap # Separate any adjacent grids of differing net names
# that overlap
# Must be done before enclosing pins # Must be done before enclosing pins
start_time = datetime.now() start_time = datetime.now()
self.separate_adjacent_pins(0) self.separate_adjacent_pins(0)
print_time("Separating adjacent pins", datetime.now(), start_time, 4) print_time("Separating adjacent pins", datetime.now(), start_time, 4)
# Enclose the continguous grid units in a metal rectangle to fix some DRCs # Enclose the continguous grid units in a metal
# rectangle to fix some DRCs
start_time = datetime.now() start_time = datetime.now()
self.enclose_pins() self.enclose_pins()
print_time("Enclosing pins", datetime.now(), start_time, 4) print_time("Enclosing pins", datetime.now(), start_time, 4)
# MRG: Removing this code for now. The later compute enclosure code # MRG: Removing this code for now. The later compute enclosure code
# assumes that all pins are touching and this may produce sets of pins # assumes that all pins are touching and this may produce sets of pins
# that are not connected. # that are not connected.
@ -249,15 +255,15 @@ class router(router_tech):
# # Use the new pin group! # # Use the new pin group!
# self.pin_groups[pin_name] = new_pin_groups # self.pin_groups[pin_name] = new_pin_groups
# removed_pairs = old_size - len(new_pin_groups) # removed_pairs = old_size - len(new_pin_groups)
# debug.info(1, "Combined {0} pin groups for {1}".format(removed_pairs,pin_name)) # debug.info(1,
# "Combined {0} pin groups for {1}".format(removed_pairs,pin_name))
# return removed_pairs # return removed_pairs
def separate_adjacent_pins(self, separation): def separate_adjacent_pins(self, separation):
""" """
This will try to separate all grid pins by the supplied number of separation This will try to separate all grid pins by the supplied
tracks (default is to prevent adjacency). number of separation tracks (default is to prevent adjacency).
""" """
# Commented out to debug with SCMOS # Commented out to debug with SCMOS
# if separation==0: # if separation==0:
@ -279,7 +285,9 @@ class router(router_tech):
If so, reduce the pin group grid to not include the adjacent grid. If so, reduce the pin group grid to not include the adjacent grid.
Try to do this intelligently to keep th pins enclosed. Try to do this intelligently to keep th pins enclosed.
""" """
debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2)) debug.info(1,
"Comparing {0} and {1} adjacency".format(pin_name1,
pin_name2))
removed_grids = 0 removed_grids = 0
for index1, pg1 in enumerate(self.pin_groups[pin_name1]): for index1, pg1 in enumerate(self.pin_groups[pin_name1]):
for index2, pg2 in enumerate(self.pin_groups[pin_name2]): for index2, pg2 in enumerate(self.pin_groups[pin_name2]):
@ -287,7 +295,10 @@ class router(router_tech):
removed_grids += len(adj_grids) removed_grids += len(adj_grids)
# These should have the same length, so... # These should have the same length, so...
if len(adj_grids) > 0: if len(adj_grids) > 0:
debug.info(3,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids)) debug.info(3,
"Adjacent grids {0} {1} adj={2}".format(index1,
index2,
adj_grids))
self.remove_adjacent_grid(pg1, pg2, adj_grids) self.remove_adjacent_grid(pg1, pg2, adj_grids)
@ -296,7 +307,8 @@ class router(router_tech):
def remove_adjacent_grid(self, pg1, pg2, adj_grids): def remove_adjacent_grid(self, pg1, pg2, adj_grids):
""" """
Remove one of the adjacent grids in a heuristic manner. Remove one of the adjacent grids in a heuristic manner.
This will try to keep the groups similar sized by removing from the bigger group. This will try to keep the groups similar sized by
removing from the bigger group.
""" """
if pg1.size() > pg2.size(): if pg1.size() > pg2.size():
@ -309,31 +321,33 @@ class router(router_tech):
for adj in adj_grids: for adj in adj_grids:
# If the adjacent grids are a subset of the secondary grids (i.e. not necessary) # If the adjacent grids are a subset of the secondary
# remove them from each # grids (i.e. not necessary) remove them from each
if adj in bigger.secondary_grids: if adj in bigger.secondary_grids:
debug.info(3,"Removing {} from bigger secondary {}".format(adj, bigger)) debug.info(3,"Removing {} from bigger secondary {}".format(adj,
bigger))
bigger.grids.remove(adj) bigger.grids.remove(adj)
bigger.secondary_grids.remove(adj) bigger.secondary_grids.remove(adj)
self.blocked_grids.add(adj) self.blocked_grids.add(adj)
elif adj in smaller.secondary_grids: elif adj in smaller.secondary_grids:
debug.info(3,"Removing {} from smaller secondary {}".format(adj, smaller)) debug.info(3,"Removing {} from smaller secondary {}".format(adj,
smaller))
smaller.grids.remove(adj) smaller.grids.remove(adj)
smaller.secondary_grids.remove(adj) smaller.secondary_grids.remove(adj)
self.blocked_grids.add(adj) self.blocked_grids.add(adj)
else: else:
# If we couldn't remove from a secondary grid, we must remove from the primary # If we couldn't remove from a secondary grid,
# we must remove from the primary
# grid of at least one pin # grid of at least one pin
if adj in bigger.grids: if adj in bigger.grids:
debug.info(3,"Removing {} from bigger primary {}".format(adj, bigger)) debug.info(3,"Removing {} from bigger primary {}".format(adj,
bigger))
bigger.grids.remove(adj) bigger.grids.remove(adj)
elif adj in smaller.grids: elif adj in smaller.grids:
debug.info(3,"Removing {} from smaller primary {}".format(adj, smaller)) debug.info(3,"Removing {} from smaller primary {}".format(adj,
smaller))
smaller.grids.remove(adj) smaller.grids.remove(adj)
def prepare_blockages(self, pin_name): def prepare_blockages(self, pin_name):
""" """
Reset and add all of the blockages in the design. Reset and add all of the blockages in the design.
@ -347,10 +361,12 @@ class router(router_tech):
#print("BLOCKING:", self.blocked_grids) #print("BLOCKING:", self.blocked_grids)
self.set_blockages(self.blocked_grids, True) self.set_blockages(self.blocked_grids, True)
# Block all of the supply rails (some will be unblocked if they're a target) # Block all of the supply rails
# (some will be unblocked if they're a target)
self.set_supply_rail_blocked(True) self.set_supply_rail_blocked(True)
# Block all of the pin components (some will be unblocked if they're a source/target) # Block all of the pin components
# (some will be unblocked if they're a source/target)
# Also block the previous routes # Also block the previous routes
for name in self.pin_groups: for name in self.pin_groups:
blockage_grids = {y for x in self.pin_groups[name] for y in x.grids} blockage_grids = {y for x in self.pin_groups[name] for y in x.grids}
@ -368,7 +384,6 @@ class router(router_tech):
blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids} blockage_grids = {y for x in self.pin_groups[pin_name] for y in x.grids}
self.set_blockages(blockage_grids, False) self.set_blockages(blockage_grids, False)
def convert_shape_to_units(self, shape): def convert_shape_to_units(self, shape):
""" """
Scale a shape (two vector list) to user units Scale a shape (two vector list) to user units
@ -378,7 +393,6 @@ class router(router_tech):
ur = shape[1].scale(unit_factor) ur = shape[1].scale(unit_factor)
return [ll, ur] return [ll, ur]
def min_max_coord(self, coord): def min_max_coord(self, coord):
""" """
Find the lowest and highest corner of a Rectangle Find the lowest and highest corner of a Rectangle
@ -432,7 +446,7 @@ class router(router_tech):
""" """
# Inflate the blockage by half a spacing rule # Inflate the blockage by half a spacing rule
[ll, ur] = self.convert_blockage_to_tracks(blockage.inflate()) [ll, ur] = self.convert_blockage_to_tracks(blockage.inflate())
zlayer = self.get_zindex(blockage.layer_num) zlayer = self.get_zindex(blockage.lpp)
blockage_tracks = self.get_blockage_tracks(ll, ur, zlayer) blockage_tracks = self.get_blockage_tracks(ll, ur, zlayer)
return blockage_tracks return blockage_tracks
@ -444,24 +458,25 @@ class router(router_tech):
blockage_list = self.convert_blockage(blockage) blockage_list = self.convert_blockage(blockage)
self.blocked_grids.update(blockage_list) self.blocked_grids.update(blockage_list)
def retrieve_blockages(self, lpp):
def retrieve_blockages(self, layer_num):
""" """
Recursive find boundaries as blockages to the routing grid. Recursive find boundaries as blockages to the routing grid.
""" """
shapes = self.layout.getAllShapes(layer_num) shapes = self.layout.getAllShapes(lpp)
for boundary in shapes: for boundary in shapes:
ll = vector(boundary[0], boundary[1]) ll = vector(boundary[0], boundary[1])
ur = vector(boundary[2], boundary[3]) ur = vector(boundary[2], boundary[3])
rect = [ll, ur] rect = [ll, ur]
new_pin = pin_layout("blockage{}".format(len(self.blockages)),rect,layer_num) new_pin = pin_layout("blockage{}".format(len(self.blockages)),
rect,
lpp)
# If there is a rectangle that is the same in the pins, it isn't a blockage! # If there is a rectangle that is the same in the pins,
# it isn't a blockage!
if new_pin not in self.all_pins: if new_pin not in self.all_pins:
self.blockages.append(new_pin) self.blockages.append(new_pin)
def convert_point_to_units(self, p): def convert_point_to_units(self, p):
""" """
Convert a path set of tracks to center line path. Convert a path set of tracks to center line path.
@ -476,7 +491,6 @@ class router(router_tech):
""" """
return [self.convert_point_to_units(i) for i in wave] return [self.convert_point_to_units(i) for i in wave]
def convert_blockage_to_tracks(self, shape): def convert_blockage_to_tracks(self, shape):
""" """
Convert a rectangular blockage shape into track units. Convert a rectangular blockage shape into track units.
@ -487,8 +501,6 @@ class router(router_tech):
# to scale coordinates to tracks # to scale coordinates to tracks
debug.info(3, "Converting [ {0} , {1} ]".format(ll, ur)) debug.info(3, "Converting [ {0} , {1} ]".format(ll, ur))
old_ll = ll
old_ur = ur
ll = ll.scale(self.track_factor) ll = ll.scale(self.track_factor)
ur = ur.scale(self.track_factor) ur = ur.scale(self.track_factor)
# We can round since we are using inflated shapes # We can round since we are using inflated shapes
@ -500,8 +512,10 @@ class router(router_tech):
def convert_pin_to_tracks(self, pin_name, pin, expansion=0): def convert_pin_to_tracks(self, pin_name, pin, expansion=0):
""" """
Convert a rectangular pin shape into a list of track locations,layers. Convert a rectangular pin shape into a list of track locations,layers.
If no pins are "on-grid" (i.e. sufficient overlap) it makes the one with most overlap if it is not blocked. If no pins are "on-grid" (i.e. sufficient overlap)
If expansion>0, expamine areas beyond the current pin when it is blocked. it makes the one with most overlap if it is not blocked.
If expansion>0, expamine areas beyond the current pin
when it is blocked.
""" """
(ll, ur) = pin.rect (ll, ur) = pin.rect
debug.info(3, "Converting pin [ {0} , {1} ]".format(ll, ur)) debug.info(3, "Converting pin [ {0} , {1} ]".format(ll, ur))
@ -514,20 +528,25 @@ class router(router_tech):
sufficient_list = set() sufficient_list = set()
insufficient_list = set() insufficient_list = set()
zindex=self.get_zindex(pin.layer_num) zindex = self.get_zindex(pin.lpp)
for x in range(int(ll[0]) + expansion, int(ur[0]) + 1 + expansion): for x in range(int(ll[0]) + expansion, int(ur[0]) + 1 + expansion):
for y in range(int(ll[1] + expansion), int(ur[1]) + 1 + expansion): for y in range(int(ll[1] + expansion), int(ur[1]) + 1 + expansion):
(full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex)) (full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin,
vector3d(x,
y,
zindex))
if full_overlap: if full_overlap:
sufficient_list.update([full_overlap]) sufficient_list.update([full_overlap])
if partial_overlap: if partial_overlap:
insufficient_list.update([partial_overlap]) insufficient_list.update([partial_overlap])
debug.info(2,"Converting [ {0} , {1} ] full={2}".format(x,y, full_overlap)) debug.info(2,
"Converting [ {0} , {1} ] full={2}".format(x,
y,
full_overlap))
# Return all grids with any potential overlap (sufficient or not) # Return all grids with any potential overlap (sufficient or not)
return (sufficient_list, insufficient_list) return (sufficient_list, insufficient_list)
def get_all_offgrid_pin(self, pin, insufficient_list): def get_all_offgrid_pin(self, pin, insufficient_list):
""" """
Find a list of all pins with some overlap. Find a list of all pins with some overlap.
@ -598,23 +617,30 @@ class router(router_tech):
return set([best_coord]) return set([best_coord])
def convert_pin_coord_to_tracks(self, pin, coord): def convert_pin_coord_to_tracks(self, pin, coord):
""" """
Return all tracks that an inflated pin overlaps Return all tracks that an inflated pin overlaps
""" """
# This is using the full track shape rather
# This is using the full track shape rather than a single track pin shape # than a single track pin shape
# because we will later patch a connector if there isn't overlap. # because we will later patch a connector if there isn't overlap.
track_pin = self.convert_track_to_shape_pin(coord) track_pin = self.convert_track_to_shape_pin(coord)
# This is the normal pin inflated by a minimum design rule # This is the normal pin inflated by a minimum design rule
inflated_pin = pin_layout(pin.name, pin.inflate(0.5*self.track_space), pin.layer) inflated_pin = pin_layout(pin.name,
pin.inflate(0.5 * self.track_space),
pin.layer)
overlap_length = pin.overlap_length(track_pin) overlap_length = pin.overlap_length(track_pin)
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length)) debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord,
pin.rect,
track_pin,
overlap_length))
inflated_overlap_length = inflated_pin.overlap_length(track_pin) inflated_overlap_length = inflated_pin.overlap_length(track_pin)
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, inflated_pin.rect, track_pin, inflated_overlap_length)) debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord,
inflated_pin.rect,
track_pin,
inflated_overlap_length))
# If it overlaps with the pin, it is sufficient # If it overlaps with the pin, it is sufficient
if overlap_length == math.inf or overlap_length > 0: if overlap_length == math.inf or overlap_length > 0:
@ -628,7 +654,6 @@ class router(router_tech):
debug.info(2, " No overlap: {0} {1}".format(overlap_length, 0)) debug.info(2, " No overlap: {0} {1}".format(overlap_length, 0))
return (None, None) return (None, None)
def convert_track_to_pin(self, track): def convert_track_to_pin(self, track):
""" """
Convert a grid point into a rectangle shape that is centered Convert a grid point into a rectangle shape that is centered
@ -649,8 +674,8 @@ class router(router_tech):
def convert_track_to_shape_pin(self, track): def convert_track_to_shape_pin(self, track):
""" """
Convert a grid point into a rectangle shape that occupies the entire centered Convert a grid point into a rectangle shape
track. that occupies the entire centered track.
""" """
# to scale coordinates to tracks # to scale coordinates to tracks
x = track[0]*self.track_width - 0.5*self.track_width x = track[0]*self.track_width - 0.5*self.track_width
@ -664,8 +689,8 @@ class router(router_tech):
def convert_track_to_shape(self, track): def convert_track_to_shape(self, track):
""" """
Convert a grid point into a rectangle shape that occupies the entire centered Convert a grid point into a rectangle shape
track. that occupies the entire centered track.
""" """
# to scale coordinates to tracks # to scale coordinates to tracks
try: try:
@ -681,7 +706,8 @@ class router(router_tech):
def convert_track_to_inflated_pin(self, track): def convert_track_to_inflated_pin(self, track):
""" """
Convert a grid point into a rectangle shape that is inflated by a half DRC space. Convert a grid point into a rectangle shape
that is inflated by a half DRC space.
""" """
# calculate lower left # calculate lower left
x = track.x*self.track_width - 0.5*self.track_width - 0.5*self.track_space x = track.x*self.track_width - 0.5*self.track_width - 0.5*self.track_space
@ -698,7 +724,8 @@ class router(router_tech):
def analyze_pins(self, pin_name): def analyze_pins(self, pin_name):
""" """
Analyze the shapes of a pin and combine them into pin_groups which are connected. Analyze the shapes of a pin and combine
them into pin_groups which are connected.
""" """
debug.info(2, "Analyzing pin groups for {}.".format(pin_name)) debug.info(2, "Analyzing pin groups for {}.".format(pin_name))
pin_set = self.pins[pin_name] pin_set = self.pins[pin_name]
@ -714,7 +741,7 @@ class router(router_tech):
# Map the pins to the lower indices # Map the pins to the lower indices
bottom_index_map = {x[1]: i for i, x in enumerate(y_coordinates) if x[2] == "bottom"} bottom_index_map = {x[1]: i for i, x in enumerate(y_coordinates) if x[2] == "bottom"}
top_index_map = {x[1]:i for i,x in enumerate(y_coordinates) if x[2]=="bottom"} # top_index_map = {x[1]: i for i, x in enumerate(y_coordinates) if x[2] == "bottom"}
# Sort the pin list by x coordinate # Sort the pin list by x coordinate
pin_list = list(pin_set) pin_list = list(pin_set)
@ -754,19 +781,19 @@ class router(router_tech):
if group_id[pin] == group_id[p2]: if group_id[pin] == group_id[p2]:
group_id[pin] = group_id[p1] group_id[pin] = group_id[p1]
# For each pin add it to it's group # For each pin add it to it's group
group_map = {} group_map = {}
for pin in pin_list: for pin in pin_list:
gid = group_id[pin] gid = group_id[pin]
if gid not in group_map: if gid not in group_map:
group_map[gid] = pin_group(name=pin_name, pin_set=[], router=self) group_map[gid] = pin_group(name=pin_name,
pin_set=[],
router=self)
# We always add it to the first set since they are touching # We always add it to the first set since they are touching
group_map[gid].pins.add(pin) group_map[gid].pins.add(pin)
self.pin_groups[pin_name] = list(group_map.values()) self.pin_groups[pin_name] = list(group_map.values())
def convert_pins(self, pin_name): def convert_pins(self, pin_name):
""" """
Convert the pin groups into pin tracks and blockage tracks. Convert the pin groups into pin tracks and blockage tracks.
@ -775,13 +802,11 @@ class router(router_tech):
for pg in self.pin_groups[pin_name]: for pg in self.pin_groups[pin_name]:
pg.convert_pin() pg.convert_pin()
def enclose_pins(self): def enclose_pins(self):
""" """
This will find the biggest rectangle enclosing some grid squares and This will find the biggest rectangle enclosing some grid squares and
put a rectangle over it. It does not enclose grid squares that are blocked put a rectangle over it. It does not enclose grid squares
by other shapes. that are blocked by other shapes.
""" """
for pin_name in self.pin_groups: for pin_name in self.pin_groups:
debug.info(1, "Enclosing pins for {}".format(pin_name)) debug.info(1, "Enclosing pins for {}".format(pin_name))
@ -813,10 +838,12 @@ class router(router_tech):
def add_pin_component_source(self, pin_name, index): def add_pin_component_source(self, pin_name, index):
""" """
This will mark only the pin tracks from the indexed pin component as a source. This will mark only the pin tracks
from the indexed pin component as a source.
It also unsets it as a blockage. It also unsets it as a blockage.
""" """
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.") debug.check(index<self.num_pin_components(pin_name),
"Pin component index too large.")
pin_in_tracks = self.pin_groups[pin_name][index].grids pin_in_tracks = self.pin_groups[pin_name][index].grids
debug.info(2,"Set source: " + str(pin_name) + " " + str(pin_in_tracks)) debug.info(2,"Set source: " + str(pin_name) + " " + str(pin_in_tracks))
@ -832,7 +859,8 @@ class router(router_tech):
def add_pin_component_target(self, pin_name, index): def add_pin_component_target(self, pin_name, index):
""" """
This will mark only the pin tracks from the indexed pin component as a target. This will mark only the pin tracks
from the indexed pin component as a target.
It also unsets it as a blockage. It also unsets it as a blockage.
""" """
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.") debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
@ -841,7 +869,6 @@ class router(router_tech):
debug.info(2, "Set target: " + str(pin_name) + " " + str(pin_in_tracks)) debug.info(2, "Set target: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.add_target(pin_in_tracks) self.rg.add_target(pin_in_tracks)
def add_pin_component_target_except(self, pin_name, index): def add_pin_component_target_except(self, pin_name, index):
""" """
This will mark the grids for all *other* pin components as a target. This will mark the grids for all *other* pin components as a target.
@ -859,11 +886,11 @@ class router(router_tech):
for pg in self.pin_groups[pin_name]: for pg in self.pin_groups[pin_name]:
self.set_blockages(pg.grids, value) self.set_blockages(pg.grids, value)
def prepare_path(self,path): def prepare_path(self,path):
""" """
Prepare a path or wave for routing ebedding. Prepare a path or wave for routing ebedding.
This tracks the path, simplifies the path and marks it as a path for debug output. This tracks the path, simplifies the path and
marks it as a path for debug output.
""" """
debug.info(4, "Set path: " + str(path)) debug.info(4, "Set path: " + str(path))
@ -871,8 +898,8 @@ class router(router_tech):
path.set_path() path.set_path()
# For debugging... if the path failed to route. # For debugging... if the path failed to route.
if False or path==None: # if False or path == None:
self.write_debug_gds() # self.write_debug_gds()
# First, simplify the path for # First, simplify the path for
# debug.info(1, str(self.path)) # debug.info(1, str(self.path))
@ -881,7 +908,6 @@ class router(router_tech):
return contracted_path return contracted_path
def add_route(self, path): def add_route(self, path):
""" """
Add the current wire route to the given design instance. Add the current wire route to the given design instance.
@ -908,7 +934,8 @@ class router(router_tech):
def add_single_enclosure(self, track): def add_single_enclosure(self, track):
""" """
Add a metal enclosure that is the size of the routing grid minus a spacing on each side. Add a metal enclosure that is the size of
the routing grid minus a spacing on each side.
""" """
pin = self.convert_track_to_pin(track) pin = self.convert_track_to_pin(track)
(ll, ur) = pin.rect (ll, ur) = pin.rect
@ -917,8 +944,6 @@ class router(router_tech):
width=ur.x-ll.x, width=ur.x-ll.x,
height=ur.y-ll.y) height=ur.y-ll.y)
def add_via(self, loc, size=1): def add_via(self, loc, size=1):
""" """
Add a via centered at the current location Add a via centered at the current location
@ -935,7 +960,8 @@ class router(router_tech):
""" """
layer = self.get_layer(zindex) layer = self.get_layer(zindex)
# This finds the pin shape enclosed by the track with DRC spacing on the sides # This finds the pin shape enclosed by the
# track with DRC spacing on the sides
pin = self.convert_track_to_pin(ll) pin = self.convert_track_to_pin(ll)
(abs_ll, unused) = pin.rect (abs_ll, unused) = pin.rect
pin = self.convert_track_to_pin(ur) pin = self.convert_track_to_pin(ur)
@ -967,8 +993,6 @@ class router(router_tech):
newpath.append(path[-1]) newpath.append(path[-1])
return newpath return newpath
def run_router(self, detour_scale): def run_router(self, detour_scale):
""" """
This assumes the blockages, source, and target are all set up. This assumes the blockages, source, and target are all set up.
@ -998,7 +1022,6 @@ class router(router_tech):
return False return False
return True return True
def annotate_pin_and_tracks(self, pin, tracks): def annotate_pin_and_tracks(self, pin, tracks):
"""" """"
Annotate some shapes for debug purposes Annotate some shapes for debug purposes
@ -1023,7 +1046,8 @@ class router(router_tech):
def write_debug_gds(self, gds_name="debug_route.gds", stop_program=True): def write_debug_gds(self, gds_name="debug_route.gds", stop_program=True):
""" """
Write out a GDS file with the routing grid and search information annotated on it. Write out a GDS file with the routing grid and
search information annotated on it.
""" """
debug.info(0, "Writing annotated router gds file to {}".format(gds_name)) debug.info(0, "Writing annotated router gds file to {}".format(gds_name))
self.del_router_info() self.del_router_info()
@ -1062,7 +1086,7 @@ class router(router_tech):
t = self.rg.map[g].get_cost() t = self.rg.map[g].get_cost()
partial_track = vector(self.track_width/6.0, 0) partial_track = vector(self.track_width/6.0, 0)
if t!=None: if t:
if g[2] == 1: if g[2] == 1:
# Upper layer is right label # Upper layer is right label
type_off = off + partial_track type_off = off + partial_track
@ -1086,7 +1110,6 @@ class router(router_tech):
layer_num = techlayer["text"] layer_num = techlayer["text"]
self.cell.objs = [x for x in self.cell.objs if x.layerNumber != layer_num] self.cell.objs = [x for x in self.cell.objs if x.layerNumber != layer_num]
def add_router_info(self): def add_router_info(self):
""" """
Write the routing grid and router cost, blockage, pins on Write the routing grid and router cost, blockage, pins on
@ -1125,14 +1148,18 @@ class router(router_tech):
if not pg.enclosed: if not pg.enclosed:
continue continue
for pin in pg.enclosures: for pin in pg.enclosures:
#print("enclosure: ",pin.name,pin.ll(),pin.width(),pin.height()) # print("enclosure: ",
# pin.name,
# pin.ll(),
# pin.width(),
# pin.height())
self.cell.add_rect(layer="text", self.cell.add_rect(layer="text",
offset=pin.ll(), offset=pin.ll(),
width=pin.width(), width=pin.width(),
height=pin.height()) height=pin.height())
# FIXME: This should be replaced with vector.snap_to_grid at some point
# FIXME: This should be replaced with vector.snap_to_grid at some point
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
@ -1141,6 +1168,7 @@ def snap_to_grid(offset):
yoff = snap_val_to_grid(offset[1]) yoff = snap_val_to_grid(offset[1])
return vector(xoff, yoff) return vector(xoff, yoff)
def snap_val_to_grid(x): def snap_val_to_grid(x):
grid = drc("grid") grid = drc("grid")
xgrid = int(round(round((x / grid), 2), 0)) xgrid = int(round(round((x / grid), 2), 0))

View File

@ -7,11 +7,11 @@
# #
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.
@ -27,7 +27,7 @@ class router_tech:
if len(self.layers) == 1: if len(self.layers) == 1:
self.horiz_layer_name = self.vert_layer_name = self.layers[0] self.horiz_layer_name = self.vert_layer_name = self.layers[0]
self.horiz_layer_number = self.vert_layer_number = layer[self.layers[0]] self.horiz_lpp = self.vert_lpp = layer[self.layers[0]]
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1) (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0) (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
@ -40,8 +40,8 @@ class router_tech:
via_connect = contact(self.layers, (1, 1)) via_connect = contact(self.layers, (1, 1))
max_via_size = max(via_connect.width,via_connect.height) max_via_size = max(via_connect.width,via_connect.height)
self.horiz_layer_number = layer[self.horiz_layer_name] self.horiz_lpp = layer[self.horiz_layer_name]
self.vert_layer_number = layer[self.vert_layer_name] self.vert_lpp = layer[self.vert_layer_name]
(self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1) (self.vert_layer_minwidth, self.vert_layer_spacing) = self.get_supply_layer_width_space(1)
(self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0) (self.horiz_layer_minwidth, self.horiz_layer_spacing) = self.get_supply_layer_width_space(0)
@ -68,8 +68,18 @@ class router_tech:
# When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side) # When we actually create the routes, make them the width of the track (minus 1/2 spacing on each side)
self.layer_widths = [self.track_wire, 1, self.track_wire] self.layer_widths = [self.track_wire, 1, self.track_wire]
def get_zindex(self,layer_num): def same_lpp(self, lpp1, lpp2):
if layer_num==self.horiz_layer_number: """
Check if the layers and purposes are the same.
Ignore if purpose is a None.
"""
if lpp1[1] == None or lpp2[1] == None:
return lpp1[0] == lpp2[0]
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
def get_zindex(self, lpp):
if self.same_lpp(lpp, self.horiz_lpp):
return 0 return 0
else: else:
return 1 return 1

View File

@ -75,7 +75,6 @@ class supply_grid_router(router):
start_time = datetime.now() start_time = datetime.now()
self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
print_time("Finding pins and blockages",datetime.now(), start_time, 3) print_time("Finding pins and blockages",datetime.now(), start_time, 3)
# Add the supply rails in a mesh network and connect H/V with vias # Add the supply rails in a mesh network and connect H/V with vias
start_time = datetime.now() start_time = datetime.now()
# Block everything # Block everything

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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