mirror of https://github.com/VLSIDA/OpenRAM.git
OpenRAM v1.1.3
Mucho PEP8 corrections. Add layer-purpose to tech files. Enable colon delimited OPENRAM_TECH list. Add general config files for unit tests.
This commit is contained in:
commit
7556872a75
|
|
@ -167,7 +167,7 @@ class instance(geometry):
|
||||||
|
|
||||||
debug.info(4, "creating instance: " + self.name)
|
debug.info(4, "creating instance: " + self.name)
|
||||||
|
|
||||||
def get_blockages(self, layer, top=False):
|
def get_blockages(self, lpp, top=False):
|
||||||
""" Retrieve blockages of all modules in this instance.
|
""" Retrieve blockages of all modules in this instance.
|
||||||
Apply the transform of the instance placement to give absolute blockages."""
|
Apply the transform of the instance placement to give absolute blockages."""
|
||||||
angle = math.radians(float(self.rotate))
|
angle = math.radians(float(self.rotate))
|
||||||
|
|
@ -191,11 +191,11 @@ class instance(geometry):
|
||||||
if self.mod.is_library_cell:
|
if self.mod.is_library_cell:
|
||||||
# Writes library cell blockages as shapes instead of a large metal blockage
|
# Writes library cell blockages as shapes instead of a large metal blockage
|
||||||
blockages = []
|
blockages = []
|
||||||
blockages = self.mod.gds.getBlockages(layer)
|
blockages = self.mod.gds.getBlockages(lpp)
|
||||||
for b in blockages:
|
for b in blockages:
|
||||||
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
|
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
|
||||||
else:
|
else:
|
||||||
blockages = self.mod.get_blockages(layer)
|
blockages = self.mod.get_blockages(lpp)
|
||||||
for b in blockages:
|
for b in blockages:
|
||||||
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
|
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
|
||||||
return new_blockages
|
return new_blockages
|
||||||
|
|
@ -266,11 +266,12 @@ class instance(geometry):
|
||||||
class path(geometry):
|
class path(geometry):
|
||||||
"""Represents a Path"""
|
"""Represents a Path"""
|
||||||
|
|
||||||
def __init__(self, layerNumber, coordinates, path_width):
|
def __init__(self, lpp, coordinates, path_width):
|
||||||
"""Initializes a path for the specified layer"""
|
"""Initializes a path for the specified layer"""
|
||||||
geometry.__init__(self)
|
geometry.__init__(self)
|
||||||
self.name = "path"
|
self.name = "path"
|
||||||
self.layerNumber = layerNumber
|
self.layerNumber = lpp[0]
|
||||||
|
self.layerPurpose = lpp[1]
|
||||||
self.coordinates = map(lambda x: [x[0], x[1]], coordinates)
|
self.coordinates = map(lambda x: [x[0], x[1]], coordinates)
|
||||||
self.coordinates = vector(self.coordinates).snap_to_grid()
|
self.coordinates = vector(self.coordinates).snap_to_grid()
|
||||||
self.path_width = path_width
|
self.path_width = path_width
|
||||||
|
|
@ -283,7 +284,7 @@ class path(geometry):
|
||||||
"""Writes the path to GDS"""
|
"""Writes the path to GDS"""
|
||||||
debug.info(4, "writing path (" + str(self.layerNumber) + "): " + self.coordinates)
|
debug.info(4, "writing path (" + str(self.layerNumber) + "): " + self.coordinates)
|
||||||
new_layout.addPath(layerNumber=self.layerNumber,
|
new_layout.addPath(layerNumber=self.layerNumber,
|
||||||
purposeNumber=0,
|
purposeNumber=self.layerPurpose,
|
||||||
coordinates=self.coordinates,
|
coordinates=self.coordinates,
|
||||||
width=self.path_width)
|
width=self.path_width)
|
||||||
|
|
||||||
|
|
@ -303,12 +304,13 @@ class path(geometry):
|
||||||
class label(geometry):
|
class label(geometry):
|
||||||
"""Represents a text label"""
|
"""Represents a text label"""
|
||||||
|
|
||||||
def __init__(self, text, layerNumber, offset, zoom=-1):
|
def __init__(self, text, lpp, offset, zoom=-1):
|
||||||
"""Initializes a text label for specified layer"""
|
"""Initializes a text label for specified layer"""
|
||||||
geometry.__init__(self)
|
geometry.__init__(self)
|
||||||
self.name = "label"
|
self.name = "label"
|
||||||
self.text = text
|
self.text = text
|
||||||
self.layerNumber = layerNumber
|
self.layerNumber = lpp[0]
|
||||||
|
self.layerPurpose = lpp[1]
|
||||||
self.offset = vector(offset).snap_to_grid()
|
self.offset = vector(offset).snap_to_grid()
|
||||||
|
|
||||||
if zoom<0:
|
if zoom<0:
|
||||||
|
|
@ -325,7 +327,7 @@ class label(geometry):
|
||||||
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
|
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
|
||||||
new_layout.addText(text=self.text,
|
new_layout.addText(text=self.text,
|
||||||
layerNumber=self.layerNumber,
|
layerNumber=self.layerNumber,
|
||||||
purposeNumber=0,
|
purposeNumber=self.layerPurpose,
|
||||||
offsetInMicrons=self.offset,
|
offsetInMicrons=self.offset,
|
||||||
magnification=self.zoom,
|
magnification=self.zoom,
|
||||||
rotate=None)
|
rotate=None)
|
||||||
|
|
@ -346,11 +348,12 @@ class label(geometry):
|
||||||
class rectangle(geometry):
|
class rectangle(geometry):
|
||||||
"""Represents a rectangular shape"""
|
"""Represents a rectangular shape"""
|
||||||
|
|
||||||
def __init__(self, layerNumber, offset, width, height):
|
def __init__(self, lpp, offset, width, height):
|
||||||
"""Initializes a rectangular shape for specified layer"""
|
"""Initializes a rectangular shape for specified layer"""
|
||||||
geometry.__init__(self)
|
geometry.__init__(self)
|
||||||
self.name = "rect"
|
self.name = "rect"
|
||||||
self.layerNumber = layerNumber
|
self.layerNumber = lpp[0]
|
||||||
|
self.layerPurpose = lpp[1]
|
||||||
self.offset = vector(offset).snap_to_grid()
|
self.offset = vector(offset).snap_to_grid()
|
||||||
self.size = vector(width, height).snap_to_grid()
|
self.size = vector(width, height).snap_to_grid()
|
||||||
self.width = round_to_grid(self.size.x)
|
self.width = round_to_grid(self.size.x)
|
||||||
|
|
@ -374,7 +377,7 @@ class rectangle(geometry):
|
||||||
debug.info(4, "writing rectangle (" + str(self.layerNumber) + "):"
|
debug.info(4, "writing rectangle (" + str(self.layerNumber) + "):"
|
||||||
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
||||||
new_layout.addBox(layerNumber=self.layerNumber,
|
new_layout.addBox(layerNumber=self.layerNumber,
|
||||||
purposeNumber=0,
|
purposeNumber=self.layerPurpose,
|
||||||
offsetInMicrons=self.offset,
|
offsetInMicrons=self.offset,
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=self.height,
|
height=self.height,
|
||||||
|
|
|
||||||
|
|
@ -150,9 +150,9 @@ class layout():
|
||||||
if not height:
|
if not height:
|
||||||
height=drc["minwidth_{}".format(layer)]
|
height=drc["minwidth_{}".format(layer)]
|
||||||
# negative layers indicate "unused" layers in a given technology
|
# negative layers indicate "unused" layers in a given technology
|
||||||
layer_num = techlayer[layer]
|
lpp = techlayer[layer]
|
||||||
if layer_num >= 0:
|
if lpp[0] >= 0:
|
||||||
self.objs.append(geometry.rectangle(layer_num, offset, width, height))
|
self.objs.append(geometry.rectangle(lpp, offset, width, height))
|
||||||
return self.objs[-1]
|
return self.objs[-1]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -165,10 +165,10 @@ class layout():
|
||||||
if not height:
|
if not height:
|
||||||
height=drc["minwidth_{}".format(layer)]
|
height=drc["minwidth_{}".format(layer)]
|
||||||
# negative layers indicate "unused" layers in a given technology
|
# negative layers indicate "unused" layers in a given technology
|
||||||
layer_num = techlayer[layer]
|
lpp = techlayer[layer]
|
||||||
corrected_offset = offset - vector(0.5*width,0.5*height)
|
corrected_offset = offset - vector(0.5*width,0.5*height)
|
||||||
if layer_num >= 0:
|
if lpp[0] >= 0:
|
||||||
self.objs.append(geometry.rectangle(layer_num, corrected_offset, width, height))
|
self.objs.append(geometry.rectangle(lpp, corrected_offset, width, height))
|
||||||
return self.objs[-1]
|
return self.objs[-1]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -334,9 +334,9 @@ class layout():
|
||||||
"""Adds a text label on the given layer,offset, and zoom level"""
|
"""Adds a text label on the given layer,offset, and zoom level"""
|
||||||
# negative layers indicate "unused" layers in a given technology
|
# negative layers indicate "unused" layers in a given technology
|
||||||
debug.info(5,"add label " + str(text) + " " + layer + " " + str(offset))
|
debug.info(5,"add label " + str(text) + " " + layer + " " + str(offset))
|
||||||
layer_num = techlayer[layer]
|
lpp = techlayer[layer]
|
||||||
if layer_num >= 0:
|
if lpp[0] >= 0:
|
||||||
self.objs.append(geometry.label(text, layer_num, offset, zoom))
|
self.objs.append(geometry.label(text, lpp, offset, zoom))
|
||||||
return self.objs[-1]
|
return self.objs[-1]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -347,9 +347,9 @@ class layout():
|
||||||
import wire_path
|
import wire_path
|
||||||
# NOTE: (UNTESTED) add_path(...) is currently not used
|
# NOTE: (UNTESTED) add_path(...) is currently not used
|
||||||
# negative layers indicate "unused" layers in a given technology
|
# negative layers indicate "unused" layers in a given technology
|
||||||
#layer_num = techlayer[layer]
|
#lpp = techlayer[layer]
|
||||||
#if layer_num >= 0:
|
#if lpp[0] >= 0:
|
||||||
# self.objs.append(geometry.path(layer_num, coordinates, width))
|
# self.objs.append(geometry.path(lpp, coordinates, width))
|
||||||
|
|
||||||
wire_path.wire_path(obj=self,
|
wire_path.wire_path(obj=self,
|
||||||
layer=layer,
|
layer=layer,
|
||||||
|
|
@ -539,21 +539,21 @@ class layout():
|
||||||
Do not write the pins since they aren't obstructions.
|
Do not write the pins since they aren't obstructions.
|
||||||
"""
|
"""
|
||||||
if type(layer)==str:
|
if type(layer)==str:
|
||||||
layer_num = techlayer[layer]
|
lpp = techlayer[layer]
|
||||||
else:
|
else:
|
||||||
layer_num = layer
|
lpp = layer
|
||||||
|
|
||||||
blockages = []
|
blockages = []
|
||||||
for i in self.objs:
|
for i in self.objs:
|
||||||
blockages += i.get_blockages(layer_num)
|
blockages += i.get_blockages(lpp)
|
||||||
for i in self.insts:
|
for i in self.insts:
|
||||||
blockages += i.get_blockages(layer_num)
|
blockages += i.get_blockages(lpp)
|
||||||
# Must add pin blockages to non-top cells
|
# Must add pin blockages to non-top cells
|
||||||
if not top_level:
|
if not top_level:
|
||||||
blockages += self.get_pin_blockages(layer_num)
|
blockages += self.get_pin_blockages(lpp)
|
||||||
return blockages
|
return blockages
|
||||||
|
|
||||||
def get_pin_blockages(self, layer_num):
|
def get_pin_blockages(self, lpp):
|
||||||
""" Return the pin shapes as blockages for non-top-level blocks. """
|
""" Return the pin shapes as blockages for non-top-level blocks. """
|
||||||
# FIXME: We don't have a body contact in ptx, so just ignore it for now
|
# FIXME: We don't have a body contact in ptx, so just ignore it for now
|
||||||
import copy
|
import copy
|
||||||
|
|
@ -565,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):
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ def check(check, str):
|
||||||
log("ERROR: file {0}: line {1}: {2}\n".format(
|
log("ERROR: file {0}: line {1}: {2}\n".format(
|
||||||
os.path.basename(filename), line_number, str))
|
os.path.basename(filename), line_number, str))
|
||||||
|
|
||||||
|
if globals.OPTS.debug_level > 0:
|
||||||
|
import pdb
|
||||||
|
pdb.set_trace()
|
||||||
assert 0
|
assert 0
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -37,6 +40,9 @@ def error(str, return_value=0):
|
||||||
log("ERROR: file {0}: line {1}: {2}\n".format(
|
log("ERROR: file {0}: line {1}: {2}\n".format(
|
||||||
os.path.basename(filename), line_number, str))
|
os.path.basename(filename), line_number, str))
|
||||||
|
|
||||||
|
if globals.OPTS.debug_level > 0:
|
||||||
|
import pdb
|
||||||
|
pdb.set_trace()
|
||||||
assert return_value == 0
|
assert return_value == 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -686,10 +686,6 @@ class Gds2reader:
|
||||||
if idBits==('\x07','\x00'): break; #we've reached the end of the structure
|
if idBits==('\x07','\x00'): break; #we've reached the end of the structure
|
||||||
elif(idBits==('\x06','\x06')):
|
elif(idBits==('\x06','\x06')):
|
||||||
structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip()
|
structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip()
|
||||||
# print(''.[x for x in structName if ord(x) < 128])
|
|
||||||
# stripped = (c for c in structName if 0 < ord(c) < 127)
|
|
||||||
# structName = "".join(stripped)
|
|
||||||
# print(self.stripNonASCII(structName)) ##FIXME: trimming by Tom g. ##could be an issue here with string trimming!
|
|
||||||
thisStructure.name = structName
|
thisStructure.name = structName
|
||||||
if(findStructName==thisStructure.name):
|
if(findStructName==thisStructure.name):
|
||||||
wantedStruct=1
|
wantedStruct=1
|
||||||
|
|
@ -767,10 +763,6 @@ class Gds2reader:
|
||||||
if idBits==('\x07','\x00'): break; #we've reached the end of the structure
|
if idBits==('\x07','\x00'): break; #we've reached the end of the structure
|
||||||
elif(idBits==('\x06','\x06')):
|
elif(idBits==('\x06','\x06')):
|
||||||
structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip()
|
structName = self.stripNonASCII(record[2::]) #(record[2:1] + record[1::]).rstrip()
|
||||||
# print(''.[x for x in structName if ord(x) < 128])
|
|
||||||
# stripped = (c for c in structName if 0 < ord(c) < 127)
|
|
||||||
# structName = "".join(stripped)
|
|
||||||
# print(self.stripNonASCIIx(structName)) ##FIXME: trimming by Tom g. ##could be an issue here with string trimming!
|
|
||||||
thisStructure.name = structName
|
thisStructure.name = structName
|
||||||
if(self.debugToTerminal==1):
|
if(self.debugToTerminal==1):
|
||||||
print("\tStructure Name: "+structName)
|
print("\tStructure Name: "+structName)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ class VlsiLayout:
|
||||||
self.layerNumbersInUse = []
|
self.layerNumbersInUse = []
|
||||||
self.debug = False
|
self.debug = False
|
||||||
if name:
|
if name:
|
||||||
self.rootStructureName=name
|
#take the root structure and copy it to a new structure with the new name
|
||||||
|
self.rootStructureName=self.padText(name)
|
||||||
#create the ROOT structure
|
#create the ROOT structure
|
||||||
self.structures[self.rootStructureName] = GdsStructure()
|
self.structures[self.rootStructureName] = GdsStructure()
|
||||||
self.structures[self.rootStructureName].name = name
|
self.structures[self.rootStructureName].name = name
|
||||||
|
|
@ -82,13 +83,9 @@ class VlsiLayout:
|
||||||
return coordinatesRotate
|
return coordinatesRotate
|
||||||
|
|
||||||
def rename(self,newName):
|
def rename(self,newName):
|
||||||
#make sure the newName is a multiple of 2 characters
|
|
||||||
if(len(newName)%2 == 1):
|
|
||||||
#pad with a zero
|
|
||||||
newName = newName + '\x00'
|
|
||||||
#take the root structure and copy it to a new structure with the new name
|
#take the root structure and copy it to a new structure with the new name
|
||||||
self.structures[newName] = self.structures[self.rootStructureName]
|
self.structures[newName] = self.structures[self.rootStructureName]
|
||||||
self.structures[newName].name = newName
|
self.structures[newName].name = self.padText(newName)
|
||||||
#and delete the old root
|
#and delete the old root
|
||||||
del self.structures[self.rootStructureName]
|
del self.structures[self.rootStructureName]
|
||||||
self.rootStructureName = newName
|
self.rootStructureName = newName
|
||||||
|
|
@ -159,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.
|
||||||
|
|
|
||||||
|
|
@ -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.")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"):
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,304 @@
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
#Copyright (c) 2019 Regents of the University of California and The Board
|
||||||
|
#of Regents for the Oklahoma Agricultural and Mechanical College
|
||||||
|
#(acting for and on behalf of Oklahoma State University)
|
||||||
|
#All rights reserved.
|
||||||
|
#
|
||||||
|
import design
|
||||||
|
from tech import drc, parameter, spice
|
||||||
|
import debug
|
||||||
|
import math
|
||||||
|
from tech import drc
|
||||||
|
from vector import vector
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
|
||||||
|
class pwrite_driver(design.design):
|
||||||
|
"""
|
||||||
|
The pwrite_driver is two tristate inverters that drive the bitlines.
|
||||||
|
The data input is first inverted before one tristate.
|
||||||
|
The inverted enable is also generated to control one tristate.
|
||||||
|
"""
|
||||||
|
def __init__(self, name, size=0):
|
||||||
|
debug.error("pwrite_driver not implemented yet.", -1)
|
||||||
|
debug.info(1, "creating pwrite_driver {}".format(name))
|
||||||
|
design.design.__init__(self, name)
|
||||||
|
self.size = size
|
||||||
|
self.beta = parameter["beta"]
|
||||||
|
self.pmos_width = self.beta*self.size*parameter["min_tx_size"]
|
||||||
|
self.nmos_width = self.size*parameter["min_tx_size"]
|
||||||
|
|
||||||
|
# The tech M2 pitch is based on old via orientations
|
||||||
|
self.m2_pitch = self.m2_space + self.m2_width
|
||||||
|
|
||||||
|
# Width is matched to the bitcell,
|
||||||
|
# Height will be variable
|
||||||
|
self.bitcell = factory.create(module_type="bitcell")
|
||||||
|
self.width = self.bitcell.width
|
||||||
|
|
||||||
|
# Creates the netlist and layout
|
||||||
|
# Since it has variable height, it is not a pgate.
|
||||||
|
self.create_netlist()
|
||||||
|
if not OPTS.netlist_only:
|
||||||
|
self.create_layout()
|
||||||
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
self.add_pins()
|
||||||
|
self.add_modules()
|
||||||
|
self.create_insts()
|
||||||
|
|
||||||
|
def create_layout(self):
|
||||||
|
self.place_modules()
|
||||||
|
self.route_wires()
|
||||||
|
self.route_supplies()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def add_pins(self):
|
||||||
|
self.add_pin("din", "INPUT")
|
||||||
|
self.add_pin("bl", "OUTPUT")
|
||||||
|
self.add_pin("br", "OUTPUT")
|
||||||
|
self.add_pin("en", "INPUT")
|
||||||
|
self.add_pin("vdd", "POWER")
|
||||||
|
self.add_pin("gnd", "GROUND")
|
||||||
|
|
||||||
|
|
||||||
|
def add_modules(self):
|
||||||
|
|
||||||
|
# Tristate inverter
|
||||||
|
self.tri = factory.create(module_type="ptristate_inv", height="min")
|
||||||
|
self.add_mod(self.tri)
|
||||||
|
debug.check(self.tri.width<self.width,"Could not create tristate inverter to match bitcell width")
|
||||||
|
|
||||||
|
#self.tbuf = factory.create(module_type="ptristate_buf", height="min")
|
||||||
|
#self.add_mod(self.tbuf)
|
||||||
|
#debug.check(self.tbuf.width<self.width,"Could not create tristate buffer to match bitcell width")
|
||||||
|
|
||||||
|
# Inverter for din and en
|
||||||
|
self.inv = factory.create(module_type="pinv", under_rail_vias=True)
|
||||||
|
self.add_mod(self.inv)
|
||||||
|
|
||||||
|
def create_insts(self):
|
||||||
|
# Enable inverter
|
||||||
|
self.en_inst = self.add_inst(name="en_inv", mod=self.inv)
|
||||||
|
self.connect_inst(["en", "en_bar", "vdd", "gnd"])
|
||||||
|
|
||||||
|
# Din inverter
|
||||||
|
self.din_inst = self.add_inst(name="din_inv", mod=self.inv)
|
||||||
|
self.connect_inst(["din", "din_bar", "vdd", "gnd"])
|
||||||
|
|
||||||
|
# Bitline tristate
|
||||||
|
self.bl_inst = self.add_inst(name="bl_tri", mod=self.tri)
|
||||||
|
self.connect_inst(["din_bar", "bl", "en", "en_bar", "vdd", "gnd"])
|
||||||
|
|
||||||
|
# Bitline bar tristate
|
||||||
|
self.br_inst = self.add_inst(name="br_tri", mod=self.tri)
|
||||||
|
self.connect_inst(["din", "br", "en", "en_bar", "vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
|
def place_modules(self):
|
||||||
|
|
||||||
|
# Add enable to the right
|
||||||
|
self.din_inst.place(vector(0, 0))
|
||||||
|
|
||||||
|
# Add BR tristate above
|
||||||
|
self.br_inst.place(vector(0, self.en_inst.uy()+self.br_inst.height), mirror="MX")
|
||||||
|
|
||||||
|
# Add BL tristate buffer
|
||||||
|
#print(self.bl_inst.width,self.width)
|
||||||
|
self.bl_inst.place(vector(self.width,self.br_inst.uy()), mirror="MY")
|
||||||
|
|
||||||
|
# Add din to the left
|
||||||
|
self.en_inst.place(vector(self.width, self.bl_inst.uy()+self.en_inst.height), rotate=180)
|
||||||
|
|
||||||
|
self.height = self.en_inst.uy()
|
||||||
|
|
||||||
|
|
||||||
|
def route_bitlines(self):
|
||||||
|
"""
|
||||||
|
Route the bitlines to the spacing of the bitcell
|
||||||
|
( even though there may be a column mux )
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Second from left track and second from right track
|
||||||
|
right_x = self.width + self.m2_pitch
|
||||||
|
left_x = -self.m2_pitch
|
||||||
|
|
||||||
|
bl_xoffset = left_x
|
||||||
|
bl_out=vector(bl_xoffset, self.height)
|
||||||
|
bl_in=self.bl_inst.get_pin("out").center()
|
||||||
|
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||||
|
offset=bl_in)
|
||||||
|
|
||||||
|
bl_mid = vector(bl_out.x,bl_in.y)
|
||||||
|
self.add_path("metal2", [bl_in, bl_mid, bl_out])
|
||||||
|
|
||||||
|
self.add_layout_pin_rect_center(text="bl",
|
||||||
|
layer="metal2",
|
||||||
|
offset=bl_out)
|
||||||
|
|
||||||
|
br_xoffset = right_x
|
||||||
|
br_out=vector(br_xoffset, self.height)
|
||||||
|
br_in=self.br_inst.get_pin("out").center()
|
||||||
|
self.add_via_center(layers=("metal1","via1","metal2"),
|
||||||
|
offset=br_in)
|
||||||
|
|
||||||
|
br_mid = vector(br_out.x,br_in.y)
|
||||||
|
self.add_path("metal2", [br_in, br_mid, br_out])
|
||||||
|
self.add_layout_pin_rect_center(text="br",
|
||||||
|
layer="metal2",
|
||||||
|
offset=br_out)
|
||||||
|
|
||||||
|
#br_xoffset = b.get_pin("br".cx()
|
||||||
|
#self.br_inst.get_pin("br")
|
||||||
|
|
||||||
|
def route_din(self):
|
||||||
|
|
||||||
|
# Left
|
||||||
|
track_xoff = self.get_m2_track(1)
|
||||||
|
|
||||||
|
din_loc = self.din_inst.get_pin("A").center()
|
||||||
|
self.add_via_stack("metal1", "metal2", din_loc)
|
||||||
|
din_track = vector(track_xoff,din_loc.y)
|
||||||
|
|
||||||
|
br_in = self.br_inst.get_pin("in").center()
|
||||||
|
self.add_via_stack("metal1", "metal2", br_in)
|
||||||
|
br_track = vector(track_xoff,br_in.y)
|
||||||
|
|
||||||
|
din_in = vector(track_xoff,0)
|
||||||
|
|
||||||
|
self.add_path("metal2", [din_in, din_track, din_loc, din_track, br_track, br_in])
|
||||||
|
|
||||||
|
self.add_layout_pin_rect_center(text="din",
|
||||||
|
layer="metal2",
|
||||||
|
offset=din_in)
|
||||||
|
|
||||||
|
def route_din_bar(self):
|
||||||
|
|
||||||
|
# Left
|
||||||
|
track_xoff = self.get_m4_track(self.din_bar_track)
|
||||||
|
|
||||||
|
din_bar_in = self.din_inst.get_pin("Z").center()
|
||||||
|
self.add_via_stack("metal1", "metal3", din_bar_in)
|
||||||
|
din_bar_track = vector(track_xoff,din_bar_in.y)
|
||||||
|
|
||||||
|
bl_in = self.bl_inst.get_pin("in").center()
|
||||||
|
self.add_via_stack("metal1", "metal3", bl_in)
|
||||||
|
bl_track = vector(track_xoff,bl_in.y)
|
||||||
|
|
||||||
|
din_in = vector(track_xoff,0)
|
||||||
|
|
||||||
|
self.add_wire(("metal3","via3","metal4"), [din_bar_in, din_bar_track, bl_track, bl_in])
|
||||||
|
|
||||||
|
self.add_layout_pin_rect_center(text="din",
|
||||||
|
layer="metal4",
|
||||||
|
offset=din_in)
|
||||||
|
|
||||||
|
|
||||||
|
def route_en_bar(self):
|
||||||
|
# Enable in track
|
||||||
|
track_xoff = self.get_m4_track(self.en_bar_track)
|
||||||
|
|
||||||
|
# This M2 pitch is a hack since the A and Z pins align horizontally
|
||||||
|
en_bar_loc = self.en_inst.get_pin("Z").uc()
|
||||||
|
en_bar_track = vector(track_xoff, en_bar_loc.y)
|
||||||
|
self.add_via_stack("metal1", "metal3", en_bar_loc)
|
||||||
|
|
||||||
|
# This is a U route to the right down then left
|
||||||
|
bl_en_loc = self.bl_inst.get_pin("en_bar").center()
|
||||||
|
bl_en_track = vector(track_xoff, bl_en_loc.y)
|
||||||
|
self.add_via_stack("metal1", "metal3", bl_en_loc)
|
||||||
|
br_en_loc = self.br_inst.get_pin("en_bar").center()
|
||||||
|
br_en_track = vector(track_xoff, bl_en_loc.y)
|
||||||
|
self.add_via_stack("metal1", "metal3", br_en_loc)
|
||||||
|
|
||||||
|
|
||||||
|
# L shape
|
||||||
|
self.add_wire(("metal3","via3","metal4"),
|
||||||
|
[en_bar_loc, en_bar_track, bl_en_track])
|
||||||
|
# U shape
|
||||||
|
self.add_wire(("metal3","via3","metal4"),
|
||||||
|
[bl_en_loc, bl_en_track, br_en_track, br_en_loc])
|
||||||
|
|
||||||
|
|
||||||
|
def route_en(self):
|
||||||
|
|
||||||
|
# Enable in track
|
||||||
|
track_xoff = self.get_m4_track(self.en_track)
|
||||||
|
|
||||||
|
# The en pin will be over the vdd rail
|
||||||
|
vdd_yloc = self.en_inst.get_pin("vdd").cy()
|
||||||
|
self.add_layout_pin_segment_center(text="en",
|
||||||
|
layer="metal3",
|
||||||
|
start=vector(0,vdd_yloc),
|
||||||
|
end=vector(self.width,vdd_yloc))
|
||||||
|
|
||||||
|
en_loc = self.en_inst.get_pin("A").center()
|
||||||
|
en_rail = vector(en_loc.x, vdd_yloc)
|
||||||
|
self.add_via_stack("metal1", "metal2", en_loc)
|
||||||
|
self.add_path("metal2", [en_loc, en_rail])
|
||||||
|
self.add_via_stack("metal2", "metal3", en_rail)
|
||||||
|
|
||||||
|
# Start point in the track on the pin rail
|
||||||
|
en_track = vector(track_xoff, vdd_yloc)
|
||||||
|
self.add_via_stack("metal3", "metal4", en_track)
|
||||||
|
|
||||||
|
# This is a U route to the right down then left
|
||||||
|
bl_en_loc = self.bl_inst.get_pin("en").center()
|
||||||
|
bl_en_track = vector(track_xoff, bl_en_loc.y)
|
||||||
|
self.add_via_stack("metal1", "metal3", bl_en_loc)
|
||||||
|
br_en_loc = self.br_inst.get_pin("en").center()
|
||||||
|
br_en_track = vector(track_xoff, bl_en_loc.y)
|
||||||
|
self.add_via_stack("metal1", "metal3", br_en_loc)
|
||||||
|
|
||||||
|
# U shape
|
||||||
|
self.add_wire(("metal3","via3","metal4"),
|
||||||
|
[en_track, bl_en_track, bl_en_loc, bl_en_track, br_en_track, br_en_loc])
|
||||||
|
|
||||||
|
|
||||||
|
def get_m4_track(self,i):
|
||||||
|
return 0.5*self.m4_space + i*(self.m4_width+self.m4_space)
|
||||||
|
def get_m3_track(self,i):
|
||||||
|
return 0.5*self.m3_space + i*(self.m3_width+self.m3_space)
|
||||||
|
def get_m2_track(self,i):
|
||||||
|
return 0.5*self.m2_space + i*(self.m2_width+self.m2_space)
|
||||||
|
|
||||||
|
def route_wires(self):
|
||||||
|
# M4 tracks
|
||||||
|
self.din_bar_track = 2
|
||||||
|
self.en_track = 0
|
||||||
|
self.en_bar_track = 1
|
||||||
|
|
||||||
|
self.route_bitlines()
|
||||||
|
self.route_din()
|
||||||
|
self.route_din_bar()
|
||||||
|
self.route_en()
|
||||||
|
self.route_en_bar()
|
||||||
|
|
||||||
|
def route_supplies(self):
|
||||||
|
for inst in [self.en_inst, self.din_inst, self.bl_inst, self.br_inst]:
|
||||||
|
# Continous vdd rail along with label.
|
||||||
|
vdd_pin=inst.get_pin("vdd")
|
||||||
|
self.add_layout_pin(text="vdd",
|
||||||
|
layer="metal1",
|
||||||
|
offset=vdd_pin.ll().scale(0,1),
|
||||||
|
width=self.width,
|
||||||
|
height=vdd_pin.height())
|
||||||
|
|
||||||
|
# Continous gnd rail along with label.
|
||||||
|
gnd_pin=inst.get_pin("gnd")
|
||||||
|
self.add_layout_pin(text="gnd",
|
||||||
|
layer="metal1",
|
||||||
|
offset=gnd_pin.ll().scale(0,1),
|
||||||
|
width=self.width,
|
||||||
|
height=vdd_pin.height())
|
||||||
|
|
||||||
|
|
||||||
|
def get_w_en_cin(self):
|
||||||
|
"""Get the relative capacitance of a single input"""
|
||||||
|
# This is approximated from SCMOS. It has roughly 5 3x transistor gates.
|
||||||
|
return 5*3
|
||||||
|
|
@ -7,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))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,6 @@ class supply_grid_router(router):
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
self.find_pins_and_blockages([self.vdd_name, self.gnd_name])
|
||||||
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
|
print_time("Finding pins and blockages",datetime.now(), start_time, 3)
|
||||||
|
|
||||||
# Add the supply rails in a mesh network and connect H/V with vias
|
# Add the supply rails in a mesh network and connect H/V with vias
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
# Block everything
|
# Block everything
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ class sram():
|
||||||
# Write the config file
|
# Write the config file
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
copyfile(OPTS.config_file + '.py', OPTS.output_path + OPTS.output_name + '.py')
|
copyfile(OPTS.config_file, OPTS.output_path + OPTS.output_name + '.py')
|
||||||
debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py'))
|
debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py'))
|
||||||
print_time("Config", datetime.datetime.now(), start_time)
|
print_time("Config", datetime.datetime.now(), start_time)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ import debug
|
||||||
class library_drc_test(openram_test):
|
class library_drc_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import verify
|
import verify
|
||||||
|
|
||||||
(gds_dir, gds_files) = setup_files()
|
(gds_dir, gds_files) = setup_files()
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ import debug
|
||||||
class library_lvs_test(openram_test):
|
class library_lvs_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import verify
|
import verify
|
||||||
|
|
||||||
(gds_dir, sp_dir, allnames) = setup_files()
|
(gds_dir, sp_dir, allnames) = setup_files()
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class contact_test(openram_test):
|
class contact_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
for layer_stack in [("metal1", "via1", "metal2"), ("poly", "contact", "metal1")]:
|
for layer_stack in [("metal1", "via1", "metal2"), ("poly", "contact", "metal1")]:
|
||||||
stack_name = ":".join(map(str, layer_stack))
|
stack_name = ":".join(map(str, layer_stack))
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ import debug
|
||||||
class path_test(openram_test):
|
class path_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import wire_path
|
import wire_path
|
||||||
import tech
|
import tech
|
||||||
import design
|
import design
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class ptx_1finger_nmos_test(openram_test):
|
class ptx_1finger_nmos_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import tech
|
import tech
|
||||||
|
|
||||||
debug.info(2, "Checking min size NMOS with 1 finger")
|
debug.info(2, "Checking min size NMOS with 1 finger")
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class ptx_1finger_pmos_test(openram_test):
|
class ptx_1finger_pmos_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import tech
|
import tech
|
||||||
|
|
||||||
debug.info(2, "Checking min size PMOS with 1 finger")
|
debug.info(2, "Checking min size PMOS with 1 finger")
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class ptx_3finger_nmos_test(openram_test):
|
class ptx_3finger_nmos_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import tech
|
import tech
|
||||||
|
|
||||||
debug.info(2, "Checking three fingers NMOS")
|
debug.info(2, "Checking three fingers NMOS")
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class ptx_3finger_pmos_test(openram_test):
|
class ptx_3finger_pmos_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import tech
|
import tech
|
||||||
|
|
||||||
debug.info(2, "Checking three fingers PMOS")
|
debug.info(2, "Checking three fingers PMOS")
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class ptx_4finger_nmos_test(openram_test):
|
class ptx_4finger_nmos_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import tech
|
import tech
|
||||||
|
|
||||||
debug.info(2, "Checking three fingers NMOS")
|
debug.info(2, "Checking three fingers NMOS")
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class ptx_test(openram_test):
|
class ptx_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import tech
|
import tech
|
||||||
|
|
||||||
debug.info(2, "Checking three fingers PMOS")
|
debug.info(2, "Checking three fingers PMOS")
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ import debug
|
||||||
class wire_test(openram_test):
|
class wire_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import wire
|
import wire
|
||||||
import tech
|
import tech
|
||||||
import design
|
import design
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class replica_pbitcell_test(openram_test):
|
class replica_pbitcell_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import dummy_pbitcell
|
import dummy_pbitcell
|
||||||
|
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pand2_test(openram_test):
|
class pand2_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
global verify
|
global verify
|
||||||
import verify
|
import verify
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pand3_test(openram_test):
|
class pand3_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
global verify
|
global verify
|
||||||
import verify
|
import verify
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ from sram_factory import factory
|
||||||
class pbitcell_test(openram_test):
|
class pbitcell_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
OPTS.num_rw_ports=1
|
OPTS.num_rw_ports=1
|
||||||
OPTS.num_w_ports=1
|
OPTS.num_w_ports=1
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pbuf_test(openram_test):
|
class pbuf_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing inverter/buffer 4x 8x")
|
debug.info(2, "Testing inverter/buffer 4x 8x")
|
||||||
a = factory.create(module_type="pbuf", size=8)
|
a = factory.create(module_type="pbuf", size=8)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pdriver_test(openram_test):
|
class pdriver_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing inverter/buffer 4x 8x")
|
debug.info(2, "Testing inverter/buffer 4x 8x")
|
||||||
# a tests the error message for specifying conflicting conditions
|
# a tests the error message for specifying conflicting conditions
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pinv_test(openram_test):
|
class pinv_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Checking 8x inverter")
|
debug.info(2, "Checking 8x inverter")
|
||||||
tx = factory.create(module_type="pinv", size=8)
|
tx = factory.create(module_type="pinv", size=8)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pinv_test(openram_test):
|
class pinv_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Checking 1x beta=3 size inverter")
|
debug.info(2, "Checking 1x beta=3 size inverter")
|
||||||
tx = factory.create(module_type="pinv", size=1, beta=3)
|
tx = factory.create(module_type="pinv", size=1, beta=3)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pinv_test(openram_test):
|
class pinv_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Checking 1x size inverter")
|
debug.info(2, "Checking 1x size inverter")
|
||||||
tx = factory.create(module_type="pinv", size=1)
|
tx = factory.create(module_type="pinv", size=1)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pinv_test(openram_test):
|
class pinv_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Checking 2x size inverter")
|
debug.info(2, "Checking 2x size inverter")
|
||||||
tx = factory.create(module_type="pinv", size=2)
|
tx = factory.create(module_type="pinv", size=2)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pinvbuf_test(openram_test):
|
class pinvbuf_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing inverter/buffer 4x 8x")
|
debug.info(2, "Testing inverter/buffer 4x 8x")
|
||||||
a = factory.create(module_type="pinvbuf", size=8)
|
a = factory.create(module_type="pinvbuf", size=8)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pnand2_test(openram_test):
|
class pnand2_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Checking 2-input nand gate")
|
debug.info(2, "Checking 2-input nand gate")
|
||||||
tx = factory.create(module_type="pnand2", size=1)
|
tx = factory.create(module_type="pnand2", size=1)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pnand3_test(openram_test):
|
class pnand3_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Checking 3-input nand gate")
|
debug.info(2, "Checking 3-input nand gate")
|
||||||
tx = factory.create(module_type="pnand3", size=1)
|
tx = factory.create(module_type="pnand3", size=1)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class pnor2_test(openram_test):
|
class pnor2_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Checking 2-input nor gate")
|
debug.info(2, "Checking 2-input nor gate")
|
||||||
tx = factory.create(module_type="pnor2", size=1)
|
tx = factory.create(module_type="pnor2", size=1)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class precharge_test(openram_test):
|
class precharge_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# check precharge in single port
|
# check precharge in single port
|
||||||
debug.info(2, "Checking precharge for handmade bitcell")
|
debug.info(2, "Checking precharge for handmade bitcell")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019 Regents of the University of California and The Board
|
||||||
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
||||||
|
# (acting for and on behalf of Oklahoma State University)
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
import unittest
|
||||||
|
from testutils import header, openram_test
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
@unittest.skip("SKIPPING 04_pwrite_driver_test")
|
||||||
|
class pwrite_driver_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||||
|
|
||||||
|
debug.info(2, "Checking 1x pwrite_driver")
|
||||||
|
tx = factory.create(module_type="pwrite_driver", size=1)
|
||||||
|
self.local_check(tx)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main()
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class replica_pbitcell_test(openram_test):
|
class replica_pbitcell_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import replica_pbitcell
|
import replica_pbitcell
|
||||||
|
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ import debug
|
||||||
class single_level_column_mux_test(openram_test):
|
class single_level_column_mux_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# check single level column mux in single port
|
# check single level column mux in single port
|
||||||
debug.info(2, "Checking column mux")
|
debug.info(2, "Checking column mux")
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ import debug
|
||||||
class bitcell_1rw_1r_array_test(openram_test):
|
class bitcell_1rw_1r_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
OPTS.bitcell = "bitcell_1rw_1r"
|
OPTS.bitcell = "bitcell_1rw_1r"
|
||||||
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
|
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ import debug
|
||||||
class array_test(openram_test):
|
class array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing 4x4 array for 6t_cell")
|
debug.info(2, "Testing 4x4 array for 6t_cell")
|
||||||
a = factory.create(module_type="bitcell_array", cols=4, rows=4)
|
a = factory.create(module_type="bitcell_array", cols=4, rows=4)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ import debug
|
||||||
class dummy_row_test(openram_test):
|
class dummy_row_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing dummy row for 6t_cell")
|
debug.info(2, "Testing dummy row for 6t_cell")
|
||||||
a = factory.create(module_type="dummy_array", rows=1, cols=4)
|
a = factory.create(module_type="dummy_array", rows=1, cols=4)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ import debug
|
||||||
class pbitcell_array_test(openram_test):
|
class pbitcell_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell")
|
debug.info(2, "Testing 4x4 array for multiport bitcell, with read ports at the edge of the bit cell")
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ import debug
|
||||||
class replica_bitcell_array_test(openram_test):
|
class replica_bitcell_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
OPTS.replica_bitcell = "replica_pbitcell"
|
OPTS.replica_bitcell = "replica_pbitcell"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class hierarchical_decoder_test(openram_test):
|
class hierarchical_decoder_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
# Doesn't require hierarchical decoder
|
# Doesn't require hierarchical decoder
|
||||||
# debug.info(1, "Testing 4 row sample for hierarchical_decoder")
|
# debug.info(1, "Testing 4 row sample for hierarchical_decoder")
|
||||||
# a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4)
|
# a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4)
|
||||||
|
|
@ -34,14 +35,30 @@ class hierarchical_decoder_test(openram_test):
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=16)
|
a = factory.create(module_type="hierarchical_decoder", rows=16)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing 17 row sample for hierarchical_decoder")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", rows=17)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing 23 row sample for hierarchical_decoder")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", rows=23)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 32 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=32)
|
a = factory.create(module_type="hierarchical_decoder", rows=32)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing 65 row sample for hierarchical_decoder")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", rows=65)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 128 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 128 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=128)
|
a = factory.create(module_type="hierarchical_decoder", rows=128)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
debug.info(1, "Testing 341 row sample for hierarchical_decoder")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", rows=341)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
|
debug.info(1, "Testing 512 row sample for hierarchical_decoder")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=512)
|
a = factory.create(module_type="hierarchical_decoder", rows=512)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
@ -57,14 +74,34 @@ class hierarchical_decoder_test(openram_test):
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=16)
|
a = factory.create(module_type="hierarchical_decoder", rows=16)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", rows=17)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", rows=23)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=32)
|
a = factory.create(module_type="hierarchical_decoder", rows=32)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", rows=65)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=128)
|
a = factory.create(module_type="hierarchical_decoder", rows=128)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
||||||
|
factory.reset()
|
||||||
|
debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)")
|
||||||
|
a = factory.create(module_type="hierarchical_decoder", rows=341)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
|
debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)")
|
||||||
a = factory.create(module_type="hierarchical_decoder", rows=512)
|
a = factory.create(module_type="hierarchical_decoder", rows=512)
|
||||||
self.local_check(a)
|
self.local_check(a)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class hierarchical_predecode2x4_test(openram_test):
|
class hierarchical_predecode2x4_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# checking hierarchical precode 2x4 for single port
|
# checking hierarchical precode 2x4 for single port
|
||||||
debug.info(1, "Testing sample for hierarchy_predecode2x4")
|
debug.info(1, "Testing sample for hierarchy_predecode2x4")
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class hierarchical_predecode3x8_test(openram_test):
|
class hierarchical_predecode3x8_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# checking hierarchical precode 3x8 for single port
|
# checking hierarchical precode 3x8 for single port
|
||||||
debug.info(1, "Testing sample for hierarchy_predecode3x8")
|
debug.info(1, "Testing sample for hierarchy_predecode3x8")
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ import debug
|
||||||
class single_level_column_mux_test(openram_test):
|
class single_level_column_mux_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import single_level_column_mux_array
|
import single_level_column_mux_array
|
||||||
|
|
||||||
# check single level column mux array in single port
|
# check single level column mux array in single port
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class precharge_test(openram_test):
|
class precharge_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# check precharge array in single port
|
# check precharge array in single port
|
||||||
debug.info(2, "Checking 3 column precharge")
|
debug.info(2, "Checking 3 column precharge")
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ import debug
|
||||||
class wordline_driver_test(openram_test):
|
class wordline_driver_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# check wordline driver for single port
|
# check wordline driver for single port
|
||||||
debug.info(2, "Checking driver")
|
debug.info(2, "Checking driver")
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class sense_amp_test(openram_test):
|
class sense_amp_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# check sense amp array for single port
|
# check sense amp array for single port
|
||||||
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
|
debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2")
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class write_driver_test(openram_test):
|
class write_driver_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# check write driver array for single port
|
# check write driver array for single port
|
||||||
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
|
debug.info(2, "Testing write_driver_array for columns=8, word_size=8")
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ import debug
|
||||||
class write_driver_test(openram_test):
|
class write_driver_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# check write driver array for single port
|
# check write driver array for single port
|
||||||
debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4")
|
debug.info(2, "Testing write_driver_array for columns=8, word_size=8, write_size=4")
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ import debug
|
||||||
class write_mask_and_array_test(openram_test):
|
class write_mask_and_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
# check write driver array for single port
|
# check write driver array for single port
|
||||||
debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4")
|
debug.info(2, "Testing write_mask_and_array for columns=8, word_size=8, write_size=4")
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class dff_array_test(openram_test):
|
class dff_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing dff_array for 3x3")
|
debug.info(2, "Testing dff_array for 3x3")
|
||||||
a = factory.create(module_type="dff_array", rows=3, columns=3)
|
a = factory.create(module_type="dff_array", rows=3, columns=3)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class dff_buf_array_test(openram_test):
|
class dff_buf_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing dff_buf_array for 3x3")
|
debug.info(2, "Testing dff_buf_array for 3x3")
|
||||||
a = factory.create(module_type="dff_buf_array", rows=3, columns=3)
|
a = factory.create(module_type="dff_buf_array", rows=3, columns=3)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class dff_buf_test(openram_test):
|
class dff_buf_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing dff_buf 4x 8x")
|
debug.info(2, "Testing dff_buf 4x 8x")
|
||||||
a = factory.create(module_type="dff_buf", inv1_size=4, inv2_size=8)
|
a = factory.create(module_type="dff_buf", inv1_size=4, inv2_size=8)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class tri_gate_array_test(openram_test):
|
class tri_gate_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(1, "Testing tri_gate_array for columns=8, word_size=8")
|
debug.info(1, "Testing tri_gate_array for columns=8, word_size=8")
|
||||||
a = factory.create(module_type="tri_gate_array", columns=8, word_size=8)
|
a = factory.create(module_type="tri_gate_array", columns=8, word_size=8)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class delay_chain_test(openram_test):
|
class delay_chain_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing delay_chain")
|
debug.info(2, "Testing delay_chain")
|
||||||
a = factory.create(module_type="delay_chain", fanout_list=[4, 4, 4, 4])
|
a = factory.create(module_type="delay_chain", fanout_list=[4, 4, 4, 4])
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ import debug
|
||||||
class replica_bitcell_array_test(openram_test):
|
class replica_bitcell_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
OPTS.bitcell = "bitcell_1rw_1r"
|
OPTS.bitcell = "bitcell_1rw_1r"
|
||||||
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
|
OPTS.replica_bitcell = "replica_bitcell_1rw_1r"
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ import debug
|
||||||
class replica_bitcell_array_test(openram_test):
|
class replica_bitcell_array_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing 4x4 array for 6t_cell")
|
debug.info(2, "Testing 4x4 array for 6t_cell")
|
||||||
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
|
a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0])
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ import debug
|
||||||
class replica_column_test(openram_test):
|
class replica_column_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(2, "Testing replica column for 6t_cell")
|
debug.info(2, "Testing replica column for 6t_cell")
|
||||||
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1)
|
a = factory.create(module_type="replica_column", rows=4, left_rbl=1, right_rbl=0, replica_bit=1)
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ import debug
|
||||||
class control_logic_test(openram_test):
|
class control_logic_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import control_logic
|
import control_logic
|
||||||
import tech
|
import tech
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class control_logic_test(openram_test):
|
class control_logic_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
import control_logic
|
import control_logic
|
||||||
import tech
|
import tech
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ import debug
|
||||||
class port_address_test(openram_test):
|
class port_address_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(1, "Port address 16 rows")
|
debug.info(1, "Port address 16 rows")
|
||||||
a = factory.create("port_address", cols=16, rows=16)
|
a = factory.create("port_address", cols=16, rows=16)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ import debug
|
||||||
class port_data_test(openram_test):
|
class port_data_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
c = sram_config(word_size=4,
|
c = sram_config(word_size=4,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class port_data_test(openram_test):
|
class port_data_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
c = sram_config(word_size=16,
|
c = sram_config(word_size=16,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class bank_select_test(openram_test):
|
class bank_select_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
|
|
||||||
debug.info(1, "No column mux, rw control logic")
|
debug.info(1, "No column mux, rw control logic")
|
||||||
a = factory.create(module_type="bank_select", port="rw")
|
a = factory.create(module_type="bank_select", port="rw")
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ import debug
|
||||||
class multi_bank_test(openram_test):
|
class multi_bank_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
c = sram_config(word_size=4,
|
c = sram_config(word_size=4,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ import debug
|
||||||
class multi_bank_test(openram_test):
|
class multi_bank_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ import debug
|
||||||
class psingle_bank_test(openram_test):
|
class psingle_bank_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
OPTS.bitcell = "pbitcell"
|
OPTS.bitcell = "pbitcell"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class single_bank_1rw_1r_test(openram_test):
|
class single_bank_1rw_1r_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
OPTS.bitcell = "bitcell_1rw_1r"
|
OPTS.bitcell = "bitcell_1rw_1r"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class single_bank_1w_1r_test(openram_test):
|
class single_bank_1w_1r_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
OPTS.bitcell = "bitcell_1w_1r"
|
OPTS.bitcell = "bitcell_1w_1r"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class single_bank_test(openram_test):
|
class single_bank_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
c = sram_config(word_size=4,
|
c = sram_config(word_size=4,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class single_bank_wmask_test(openram_test):
|
class single_bank_wmask_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ import debug
|
||||||
class sram_1bank_2mux_test(openram_test):
|
class sram_1bank_2mux_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=4,
|
c = sram_config(word_size=4,
|
||||||
num_words=32,
|
num_words=32,
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ import debug
|
||||||
class sram_1bank_2mux_wmask_test(openram_test):
|
class sram_1bank_2mux_wmask_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=8,
|
c = sram_config(word_size=8,
|
||||||
write_size=4,
|
write_size=4,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ import debug
|
||||||
class sram_1bank_4mux_test(openram_test):
|
class sram_1bank_4mux_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=4,
|
c = sram_config(word_size=4,
|
||||||
num_words=64,
|
num_words=64,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class sram_1bank_8mux_1rw_1r_test(openram_test):
|
class sram_1bank_8mux_1rw_1r_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
OPTS.bitcell = "bitcell_1rw_1r"
|
OPTS.bitcell = "bitcell_1rw_1r"
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ import debug
|
||||||
class sram_1bank_8mux_test(openram_test):
|
class sram_1bank_8mux_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=2,
|
c = sram_config(word_size=2,
|
||||||
num_words=128,
|
num_words=128,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class sram_1bank_nomux_1rw_1r_test(openram_test):
|
class sram_1bank_nomux_1rw_1r_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
|
|
||||||
OPTS.bitcell = "bitcell_1rw_1r"
|
OPTS.bitcell = "bitcell_1rw_1r"
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ import debug
|
||||||
class sram_1bank_nomux_test(openram_test):
|
class sram_1bank_nomux_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=4,
|
c = sram_config(word_size=4,
|
||||||
num_words=16,
|
num_words=16,
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ import debug
|
||||||
class sram_1bank_nomux_wmask_test(openram_test):
|
class sram_1bank_nomux_wmask_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=8,
|
c = sram_config(word_size=8,
|
||||||
write_size=4,
|
write_size=4,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ import debug
|
||||||
class sram_2bank_test(openram_test):
|
class sram_2bank_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
from sram_config import sram_config
|
from sram_config import sram_config
|
||||||
c = sram_config(word_size=16,
|
c = sram_config(word_size=16,
|
||||||
num_words=32,
|
num_words=32,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ import debug
|
||||||
class timing_sram_test(openram_test):
|
class timing_sram_test(openram_test):
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||||
|
globals.init_openram(config_file)
|
||||||
OPTS.spice_name="hspice"
|
OPTS.spice_name="hspice"
|
||||||
OPTS.analytical_delay = False
|
OPTS.analytical_delay = False
|
||||||
OPTS.netlist_only = True
|
OPTS.netlist_only = True
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue