Merge branch 'dev' into update_scmos_models

This commit is contained in:
Hunter Nichols 2019-10-03 13:16:32 -07:00
commit d722311822
10 changed files with 199 additions and 174 deletions

View File

@ -7,39 +7,44 @@
#
import hierarchy_design
import debug
import utils
from tech import drc,layer
from tech import drc, layer
from vector import vector
class contact(hierarchy_design.hierarchy_design):
"""
Object for a contact shape with its conductor enclosures.
Creates a contact array minimum active or poly enclosure and metal1 enclosure.
This class has enclosure on two or four sides of the contact.
The direction specifies whether the first and second layer have asymmetric extension in the H or V direction.
Object for a contact shape with its conductor enclosures. Creates
a contact array minimum active or poly enclosure and metal1
enclosure. This class has enclosure on two or four sides of the
contact. The direction specifies whether the first and second
layer have asymmetric extension in the H or V direction.
The well/implant_type is an option to add a select/implant layer
enclosing the contact. This is necessary to import layouts into
Magic which requires the select to be in the same GDS hierarchy as
the contact.
The well/implant_type is an option to add a select/implant layer enclosing the contact. This is
necessary to import layouts into Magic which requires the select to be in the same GDS
hierarchy as the contact.
"""
def __init__(self, layer_stack, dimensions=(1,1), directions=("V","V"), implant_type=None, well_type=None, name=""):
# This will ignore the name parameter since we can guarantee a unique name here
def __init__(self, layer_stack, dimensions=(1, 1), directions=("V", "V"),
implant_type=None, well_type=None, name=""):
# This will ignore the name parameter since
# we can guarantee a unique name here
hierarchy_design.hierarchy_design.__init__(self, name)
debug.info(4, "create contact object {0}".format(name))
self.add_comment("layers: {0}".format(layer_stack))
self.add_comment("dimensions: {0}".format(dimensions))
if implant_type or well_type:
self.add_comment("implant type: {0}\nwell_type: {1}".format(implant_type,well_type))
self.add_comment("implant type: {}\n".format(implant_type))
self.add_comment("well_type: {}\n".format(well_type))
self.layer_stack = layer_stack
self.dimensions = dimensions
self.directions = directions
self.offset = vector(0,0)
self.offset = vector(0, 0)
self.implant_type = implant_type
self.well_type = well_type
self.well_type = well_type
# Module does not have pins, but has empty pin list.
self.pins = []
self.create_layout()
@ -59,7 +64,7 @@ class contact(hierarchy_design.hierarchy_design):
if self.implant_type and self.well_type:
self.create_implant_well_enclosures()
elif self.implant_type or self.well_type:
debug.error(-1,"Must define both implant and well type or none at all.")
debug.error(-1, "Must define both implant and well type or none at all.")
def setup_layers(self):
""" Locally assign the layer names. """
@ -67,10 +72,11 @@ class contact(hierarchy_design.hierarchy_design):
(first_layer, via_layer, second_layer) = self.layer_stack
self.first_layer_name = first_layer
self.via_layer_name = via_layer
# Some technologies have a separate active contact from the poly contact
# Some technologies have a separate active
# contact from the poly contact
# We will use contact for DRC, but active_contact for output
if first_layer=="active" or second_layer=="active":
self.via_layer_name_expanded = "active_"+via_layer
if first_layer == "active" or second_layer == "active":
self.via_layer_name_expanded = "active_" + via_layer
else:
self.via_layer_name_expanded = via_layer
self.second_layer_name = second_layer
@ -97,19 +103,19 @@ class contact(hierarchy_design.hierarchy_design):
second_layer_enclosure = drc("{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name))
second_layer_extend = drc("{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name))
# In some technologies, the minimum width may be larger than the overlap requirement around the via, so
# In some technologies, the minimum width may be larger
# than the overlap requirement around the via, so
# check this for each dimension.
if self.directions[0] == "V":
self.first_layer_horizontal_enclosure = max(first_layer_enclosure,
(first_layer_minwidth - self.contact_array_width)/2)
(first_layer_minwidth - self.contact_array_width) / 2)
self.first_layer_vertical_enclosure = max(first_layer_extend,
(first_layer_minwidth - self.contact_array_height)/2)
(first_layer_minwidth - self.contact_array_height) / 2)
elif self.directions[0] == "H":
self.first_layer_horizontal_enclosure = max(first_layer_extend,
(first_layer_minwidth - self.contact_array_width)/2)
(first_layer_minwidth - self.contact_array_width) / 2)
self.first_layer_vertical_enclosure = max(first_layer_enclosure,
(first_layer_minwidth - self.contact_array_height)/2)
(first_layer_minwidth - self.contact_array_height) / 2)
else:
debug.error("Invalid first layer direction.", -1)
@ -117,23 +123,23 @@ class contact(hierarchy_design.hierarchy_design):
# check this for each dimension.
if self.directions[1] == "V":
self.second_layer_horizontal_enclosure = max(second_layer_enclosure,
(second_layer_minwidth - self.contact_array_width)/2)
(second_layer_minwidth - self.contact_array_width) / 2)
self.second_layer_vertical_enclosure = max(second_layer_extend,
(second_layer_minwidth - self.contact_array_height)/2)
(second_layer_minwidth - self.contact_array_height) / 2)
elif self.directions[1] == "H":
self.second_layer_horizontal_enclosure = max(second_layer_extend,
(second_layer_minwidth - self.contact_array_height)/2)
(second_layer_minwidth - self.contact_array_height) / 2)
self.second_layer_vertical_enclosure = max(second_layer_enclosure,
(second_layer_minwidth - self.contact_array_width)/2)
(second_layer_minwidth - self.contact_array_width) / 2)
else:
debug.error("Invalid second layer direction.", -1)
def create_contact_array(self):
""" Create the contact array at the origin"""
# offset for the via array
self.via_layer_position =vector(max(self.first_layer_horizontal_enclosure,self.second_layer_horizontal_enclosure),
max(self.first_layer_vertical_enclosure,self.second_layer_vertical_enclosure))
self.via_layer_position = vector(
max(self.first_layer_horizontal_enclosure, self.second_layer_horizontal_enclosure),
max(self.first_layer_vertical_enclosure, self.second_layer_vertical_enclosure))
for i in range(self.dimensions[1]):
offset = self.via_layer_position + vector(0, self.contact_pitch * i)
@ -142,15 +148,16 @@ class contact(hierarchy_design.hierarchy_design):
offset=offset,
width=self.contact_width,
height=self.contact_width)
offset = offset + vector(self.contact_pitch,0)
offset = offset + vector(self.contact_pitch, 0)
def create_first_layer_enclosure(self):
# this is if the first and second layers are different
self.first_layer_position = vector(max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure,0),
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure,0))
self.first_layer_position = vector(
max(self.second_layer_horizontal_enclosure - self.first_layer_horizontal_enclosure, 0),
max(self.second_layer_vertical_enclosure - self.first_layer_vertical_enclosure, 0))
self.first_layer_width = self.contact_array_width + 2*self.first_layer_horizontal_enclosure
self.first_layer_height = self.contact_array_height + 2*self.first_layer_vertical_enclosure
self.first_layer_width = self.contact_array_width + 2 * self.first_layer_horizontal_enclosure
self.first_layer_height = self.contact_array_height + 2 * self.first_layer_vertical_enclosure
self.add_rect(layer=self.first_layer_name,
offset=self.first_layer_position,
width=self.first_layer_width,
@ -158,27 +165,28 @@ class contact(hierarchy_design.hierarchy_design):
def create_second_layer_enclosure(self):
# this is if the first and second layers are different
self.second_layer_position = vector(max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure,0),
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure,0))
self.second_layer_position = vector(
max(self.first_layer_horizontal_enclosure - self.second_layer_horizontal_enclosure, 0),
max(self.first_layer_vertical_enclosure - self.second_layer_vertical_enclosure, 0))
self.second_layer_width = self.contact_array_width + 2*self.second_layer_horizontal_enclosure
self.second_layer_height = self.contact_array_height + 2*self.second_layer_vertical_enclosure
self.second_layer_width = self.contact_array_width + 2 * self.second_layer_horizontal_enclosure
self.second_layer_height = self.contact_array_height + 2 * self.second_layer_vertical_enclosure
self.add_rect(layer=self.second_layer_name,
offset=self.second_layer_position,
width=self.second_layer_width,
height=self.second_layer_height)
def create_implant_well_enclosures(self):
implant_position = self.first_layer_position - [drc("implant_enclosure_active")]*2
implant_width = self.first_layer_width + 2*drc("implant_enclosure_active")
implant_height = self.first_layer_height + 2*drc("implant_enclosure_active")
implant_position = self.first_layer_position - [drc("implant_enclosure_active")] * 2
implant_width = self.first_layer_width + 2 * drc("implant_enclosure_active")
implant_height = self.first_layer_height + 2 * drc("implant_enclosure_active")
self.add_rect(layer="{}implant".format(self.implant_type),
offset=implant_position,
width=implant_width,
height=implant_height)
well_position = self.first_layer_position - [drc("well_enclosure_active")]*2
well_width = self.first_layer_width + 2*drc("well_enclosure_active")
well_height = self.first_layer_height + 2*drc("well_enclosure_active")
well_position = self.first_layer_position - [drc("well_enclosure_active")] * 2
well_width = self.first_layer_width + 2 * drc("well_enclosure_active")
well_height = self.first_layer_height + 2 * drc("well_enclosure_active")
self.add_rect(layer="{}well".format(self.well_type),
offset=well_position,
width=well_width,
@ -188,16 +196,30 @@ class contact(hierarchy_design.hierarchy_design):
""" Get total power of a module """
return self.return_power()
from sram_factory import factory
# This is not instantiated and used for calculations only.
# These are static 1x1 contacts to reuse in all the design modules.
well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"), directions=("H","V"))
active = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1"), directions=("H","V"))
poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1"), directions=("V","H"))
m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2"), directions=("H","V"))
m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3"), directions=("V","H"))
well = factory.create(module_type="contact",
layer_stack=("active", "contact", "metal1"),
directions=("H", "V"))
active = factory.create(module_type="contact",
layer_stack=("active", "contact", "metal1"),
directions=("H", "V"))
poly = factory.create(module_type="contact",
layer_stack=("poly", "contact", "metal1"),
directions=("V", "H"))
m1m2 = factory.create(module_type="contact",
layer_stack=("metal1", "via1", "metal2"),
directions=("H", "V"))
m2m3 = factory.create(module_type="contact",
layer_stack=("metal2", "via2", "metal3"),
directions=("V", "H"))
if "metal4" in layer.keys():
m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4"), directions=("H","V"))
m3m4 = factory.create(module_type="contact",
layer_stack=("metal3", "via3", "metal4"),
directions=("H", "V"))
else:
m3m4 = None

View File

@ -6,6 +6,7 @@
# All rights reserved.
#
class delay_data():
"""
This is the delay class to represent the delay information
@ -20,13 +21,13 @@ class delay_data():
def __str__(self):
""" override print function output """
return "Delay Data: Delay "+str(self.delay)+", Slew "+str(self.slew)+""
return "Delta Data: Delay {} Slew {}".format(self.delay, self.slew)
def __add__(self, other):
"""
Override - function (left), for delay_data: a+b != b+a
"""
assert isinstance(other,delay_data)
assert isinstance(other, delay_data)
return delay_data(other.delay + self.delay,
other.slew)
@ -34,7 +35,7 @@ class delay_data():
"""
Override - function (right), for delay_data: a+b != b+a
"""
assert isinstance(other,delay_data)
assert isinstance(other, delay_data)
return delay_data(other.delay + self.delay,
self.slew)

View File

@ -7,12 +7,9 @@
#
from hierarchy_design import hierarchy_design
import contact
import globals
import verify
import debug
import os
from globals import OPTS
class design(hierarchy_design):
"""
This is the same as the hierarchy_design class except it contains
@ -21,29 +18,29 @@ class design(hierarchy_design):
"""
def __init__(self, name):
hierarchy_design.__init__(self,name)
hierarchy_design.__init__(self, name)
self.setup_drc_constants()
self.setup_multiport_constants()
from tech import layer
self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(self.m1_space, self.m2_space)
self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(self.m2_space, self.m3_space)
self.m1_pitch = max(contact.m1m2.width, contact.m1m2.height) + max(self.m1_space, self.m2_space)
self.m2_pitch = max(contact.m2m3.width, contact.m2m3.height) + max(self.m2_space, self.m3_space)
if "metal4" in layer:
self.m3_pitch = max(contact.m3m4.width,contact.m3m4.height) + max(self.m3_space, self.m4_space)
self.m3_pitch = max(contact.m3m4.width, contact.m3m4.height) + max(self.m3_space, self.m4_space)
else:
self.m3_pitch = self.m2_pitch
def setup_drc_constants(self):
""" These are some DRC constants used in many places in the compiler."""
from tech import drc,layer
from tech import drc, layer
self.well_width = drc("minwidth_well")
self.poly_width = drc("minwidth_poly")
self.poly_space = drc("poly_to_poly")
self.poly_space = drc("poly_to_poly")
self.m1_width = drc("minwidth_metal1")
self.m1_space = drc("metal1_to_metal1")
self.m2_width = drc("minwidth_metal2")
self.m2_space = drc("metal2_to_metal2")
self.m2_space = drc("metal2_to_metal2")
self.m3_width = drc("minwidth_metal3")
self.m3_space = drc("metal3_to_metal3")
if "metal4" in layer:
@ -93,12 +90,12 @@ class design(hierarchy_design):
port_number += 1
for port in range(OPTS.num_w_ports):
self.write_ports.append(port_number)
self.writeonly_ports.append(port_number)
self.writeonly_ports.append(port_number)
port_number += 1
for port in range(OPTS.num_r_ports):
self.read_ports.append(port_number)
self.readonly_ports.append(port_number)
port_number += 1
port_number += 1
def analytical_power(self, corner, load):
""" Get total power of a module """

View File

@ -6,7 +6,7 @@
# All rights reserved.
#
"""
This provides a set of useful generic types for the gdsMill interface.
This provides a set of useful generic types for the gdsMill interface.
"""
import debug
from vector import vector
@ -15,6 +15,7 @@ import math
from globals import OPTS
from utils import round_to_grid
class geometry:
"""
A specific path, shape, or text geometry. Base class for shared
@ -27,11 +28,11 @@ class geometry:
def __str__(self):
""" override print function output """
debug.error("__str__ must be overridden by all geometry types.",1)
debug.error("__str__ must be overridden by all geometry types.", 1)
def __repr__(self):
""" override print function output """
debug.error("__repr__ must be overridden by all geometry types.",1)
debug.error("__repr__ must be overridden by all geometry types.", 1)
# def translate_coords(self, coords, mirr, angle, xyShift):
# """Calculate coordinates after flip, rotate, and shift"""
@ -46,50 +47,52 @@ class geometry:
"""Calculate coordinates after flip, rotate, and shift"""
coordinate = []
for item in coords:
x = item[0]*math.cos(angle) - item[1]*mirr*math.sin(angle) + offset[0]
y = item[0]*math.sin(angle) + item[1]*mirr*math.cos(angle) + offset[1]
x = item[0] * math.cos(angle) - item[1] * mirr * math.sin(angle) + offset[0]
y = item[0] * math.sin(angle) + item[1] * mirr * math.cos(angle) + offset[1]
coordinate += [[x, y]]
return coordinate
def normalize(self):
""" Re-find the LL and UR points after a transform """
(first,second)=self.boundary
ll = vector(min(first[0],second[0]),min(first[1],second[1])).snap_to_grid()
ur = vector(max(first[0],second[0]),max(first[1],second[1])).snap_to_grid()
self.boundary=[ll,ur]
(first, second) = self.boundary
ll = vector(min(first[0], second[0]),
min(first[1], second[1])).snap_to_grid()
ur = vector(max(first[0], second[0]),
max(first[1], second[1])).snap_to_grid()
self.boundary = [ll, ur]
def update_boundary(self):
""" Update the boundary with a new placement. """
self.compute_boundary(self.offset,self.mirror,self.rotate)
self.compute_boundary(self.offset, self.mirror, self.rotate)
def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0):
""" Transform with offset, mirror and rotation to get the absolute pin location.
def compute_boundary(self, offset=vector(0, 0), mirror="", rotate=0):
""" 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. """
if OPTS.netlist_only:
return
(ll,ur) = [vector(0,0),vector(self.width,self.height)]
(ll, ur) = [vector(0, 0), vector(self.width, self.height)]
if mirror=="MX":
ll=ll.scale(1,-1)
ur=ur.scale(1,-1)
elif mirror=="MY":
ll=ll.scale(-1,1)
ur=ur.scale(-1,1)
elif mirror=="XY":
ll=ll.scale(-1,-1)
ur=ur.scale(-1,-1)
if mirror == "MX":
ll = ll.scale(1, -1)
ur = ur.scale(1, -1)
elif mirror == "MY":
ll = ll.scale(-1, 1)
ur = ur.scale(-1, 1)
elif mirror == "XY":
ll = ll.scale(-1, -1)
ur = ur.scale(-1, -1)
if rotate==90:
ll=ll.rotate_scale(-1,1)
ur=ur.rotate_scale(-1,1)
elif rotate==180:
ll=ll.scale(-1,-1)
ur=ur.scale(-1,-1)
elif rotate==270:
ll=ll.rotate_scale(1,-1)
ur=ur.rotate_scale(1,-1)
if rotate == 90:
ll = ll.rotate_scale(-1, 1)
ur = ur.rotate_scale(-1, 1)
elif rotate == 180:
ll = ll.scale(-1, -1)
ur = ur.scale(-1, -1)
elif rotate == 270:
ll = ll.rotate_scale(1, -1)
ur = ur.rotate_scale(1, -1)
self.boundary=[offset+ll,offset+ur]
self.boundary = [offset + ll, offset + ur]
self.normalize()
def ll(self):
@ -108,7 +111,6 @@ class geometry:
""" Return the upper left corner """
return vector(self.boundary[0].x, self.boundary[1].y)
def uy(self):
""" Return the upper edge """
return self.boundary[1].y
@ -127,11 +129,11 @@ class geometry:
def cx(self):
""" Return the center x """
return 0.5*(self.boundary[0].x + self.boundary[1].x)
return 0.5 * (self.boundary[0].x + self.boundary[1].x)
def cy(self):
""" Return the center y """
return 0.5*(self.boundary[0].y + self.boundary[1].y)
return 0.5 * (self.boundary[0].y + self.boundary[1].y)
class instance(geometry):
@ -139,10 +141,11 @@ class instance(geometry):
An instance of an instance/module with a specified location and
rotation
"""
def __init__(self, name, mod, offset=[0,0], mirror="R0", rotate=0):
def __init__(self, name, mod, offset=[0, 0], mirror="R0", rotate=0):
"""Initializes an instance to represent a module"""
geometry.__init__(self)
debug.check(mirror not in ["R90","R180","R270"], "Please use rotation and not mirroring during instantiation.")
debug.check(mirror not in ["R90", "R180", "R270"],
"Please use rotation and not mirroring during instantiation.")
self.name = name
self.mod = mod
@ -154,13 +157,13 @@ class instance(geometry):
self.width = 0
self.height = 0
else:
if mirror in ["R90","R270"] or rotate in [90,270]:
if mirror in ["R90", "R270"] or rotate in [90, 270]:
self.width = round_to_grid(mod.height)
self.height = round_to_grid(mod.width)
else:
self.width = round_to_grid(mod.width)
self.height = round_to_grid(mod.height)
self.compute_boundary(offset,mirror,rotate)
self.compute_boundary(offset, mirror, rotate)
debug.info(4, "creating instance: " + self.name)
@ -169,18 +172,18 @@ class instance(geometry):
Apply the transform of the instance placement to give absolute blockages."""
angle = math.radians(float(self.rotate))
mirr = 1
if self.mirror=="R90":
if self.mirror == "R90":
angle += math.radians(90.0)
elif self.mirror=="R180":
elif self.mirror == "R180":
angle += math.radians(180.0)
elif self.mirror=="R270":
elif self.mirror == "R270":
angle += math.radians(270.0)
elif self.mirror=="MX":
elif self.mirror == "MX":
mirr = -1
elif self.mirror=="MY":
elif self.mirror == "MY":
mirr = -1
angle += math.radians(180.0)
elif self.mirror=="XY":
elif self.mirror == "XY":
mirr = 1
angle += math.radians(180.0)
@ -226,7 +229,7 @@ class instance(geometry):
this instance location. Index will return one of several pins."""
import copy
if index==-1:
if index == -1:
pin = copy.deepcopy(self.mod.get_pin(name))
pin.transform(self.offset,self.mirror,self.rotate)
return pin
@ -339,6 +342,7 @@ class label(geometry):
""" override print function output """
return "( label: " + self.text + " @" + str(self.offset) + " layer=" + str(self.layerNumber) + " )"
class rectangle(geometry):
"""Represents a rectangular shape"""
@ -351,22 +355,23 @@ class rectangle(geometry):
self.size = vector(width, height).snap_to_grid()
self.width = round_to_grid(self.size.x)
self.height = round_to_grid(self.size.y)
self.compute_boundary(offset,"",0)
self.compute_boundary(offset, "", 0)
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
def get_blockages(self, layer):
""" Returns a list of one rectangle if it is on this layer"""
if self.layerNumber == layer:
return [[self.offset, vector(self.offset.x+self.width,self.offset.y+self.height)]]
return [[self.offset,
vector(self.offset.x + self.width,
self.offset.y + self.height)]]
else:
return []
def gds_write_file(self, new_layout):
"""Writes the rectangular shape to GDS"""
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))
new_layout.addBox(layerNumber=self.layerNumber,
purposeNumber=0,

View File

@ -94,7 +94,7 @@ def info(lev, str):
frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0])
# classname = frm.f_globals['__name__']
if mod.__name__ == None:
if mod.__name__ is None:
class_name = ""
else:
class_name = mod.__name__

View File

@ -13,10 +13,7 @@ created without re-running the entire process. Right now, it assumes the nominal
corner, but should probably be extended.
"""
import sys,os
import datetime
import re
import importlib
import sys
from globals import *
(OPTS, args) = parse_args()

View File

@ -16,34 +16,32 @@ a LEF (.lef) file for preliminary P&R (real one should be from layout)
a Liberty (.lib) file for timing analysis/optimization
"""
import sys,os
import sys
import datetime
import re
import importlib
from globals import *
import globals as g
(OPTS, args) = parse_args()
(OPTS, args) = g.parse_args()
# Check that we are left with a single configuration file as argument.
if len(args) != 1:
print(USAGE)
print(g.USAGE)
sys.exit(2)
# These depend on arguments, so don't load them until now.
import debug
init_openram(config_file=args[0], is_unit_test=False)
g.init_openram(config_file=args[0], is_unit_test=False)
# Only print banner here so it's not in unit tests
print_banner()
g.print_banner()
# Keep track of running stats
start_time = datetime.datetime.now()
print_time("Start",start_time)
g.print_time("Start", start_time)
# Output info about this run
report_status()
g.report_status()
from sram_config import sram_config
@ -54,15 +52,16 @@ c = sram_config(word_size=OPTS.word_size,
write_size=OPTS.write_size)
debug.print_raw("Words per row: {}".format(c.words_per_row))
#from parser import *
output_extensions = ["sp","v","lib","py","html","log"]
output_extensions = ["sp", "v", "lib", "py", "html", "log"]
# Only output lef/gds if back-end
if not OPTS.netlist_only:
output_extensions.extend(["lef","gds"])
output_extensions.extend(["lef", "gds"])
output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions]
output_files = ["{0}{1}.{2}".format(OPTS.output_path,
OPTS.output_name, x)
for x in output_extensions]
debug.print_raw("Output files are: ")
for path in output_files:
for path in output_files:
debug.print_raw(path)
@ -74,7 +73,7 @@ s = sram(sram_config=c,
s.save()
# Delete temp files etc.
end_openram()
print_time("End",datetime.datetime.now(), start_time)
g.end_openram()
g.print_time("End", datetime.datetime.now(), start_time)

View File

@ -6,13 +6,13 @@
# All rights reserved.
#
import optparse
import getpass
import getpass
import os
#import sram_config
class options(optparse.Values):
"""
Class for holding all of the OpenRAM options. All of these options can be over-riden in a configuration file
Class for holding all of the OpenRAM options. All
of these options can be over-riden in a configuration file
that is the sole required command-line positional argument for openram.py.
"""
@ -39,15 +39,16 @@ class options(optparse.Values):
process_corners = ""
# Size parameters must be specified by user in config file.
#num_words = 0
#word_size = 0
# num_words = 0
# word_size = 0
# You can manually specify banks, but it is better to auto-detect it.
num_banks = 1
###################
# Optimization options
###################
rbl_delay_percentage = 0.5 #Approximate percentage of delay compared to bitlines
# Approximate percentage of delay compared to bitlines
rbl_delay_percentage = 0.5
# Allow manual adjustment of the delay chain over automatic
use_tech_delay_chain_size = False
@ -65,7 +66,8 @@ class options(optparse.Values):
openram_temp = os.path.abspath(os.environ.get("OPENRAM_TMP"))
except:
# Else use a unique temporary directory
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid())
openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),
os.getpid())
# This is the verbosity level to control debug information. 0 is none, 1
# is minimal, etc.
debug_level = 0
@ -100,7 +102,8 @@ class options(optparse.Values):
drc_name = ""
lvs_name = ""
pex_name = ""
# The DRC/LVS/PEX executable being used which is derived from the user PATH.
# The DRC/LVS/PEX executable being used
# which is derived from the user PATH.
drc_exe = None
lvs_exe = None
pex_exe = None
@ -113,15 +116,14 @@ class options(optparse.Values):
output_path = "."
# Define the output file base name
output_name = ""
# Use analytical delay models by default rather than (slow) characterization
# Use analytical delay models by default
# rather than (slow) characterization
analytical_delay = True
# Purge the temp directory after a successful run (doesn't purge on errors, anyhow)
# Purge the temp directory after a successful
# run (doesn't purge on errors, anyhow)
purge_temp = True
###################
# These are the default modules that can be over-riden
###################
bank_select = "bank_select"
bitcell_array = "bitcell_array"
bitcell = "bitcell"

View File

@ -5,9 +5,9 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import debug
from globals import OPTS
class sram_factory:
"""
This is a factory pattern to create modules for usage in an SRAM.
@ -19,7 +19,7 @@ class sram_factory:
"""
def __init__(self):
# A dictionary of modules indexed by module type
# A dictionary of modules indexed by module type
self.modules = {}
# These are the indices to append to name to make unique object names
self.module_indices = {}
@ -34,8 +34,8 @@ class sram_factory:
def create(self, module_type, **kwargs):
"""
A generic function to create a module with a given module_type. The args
are passed directly to the module constructor.
A generic function to create a module with a given module_type.
The args are passed directly to the module constructor.
"""
# if name!="":
# # This is a special case where the name and type don't match
@ -58,28 +58,30 @@ class sram_factory:
self.objects[module_type] = []
# Either retreive a previous object or create a new one
#print("new",kwargs)
for obj in self.objects[module_type]:
(obj_kwargs, obj_item) = obj
# Must have the same dictionary exactly (conservative)
if obj_kwargs == kwargs:
#debug.info(0, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs)))
return obj_item
#else:
# print("obj",obj_kwargs)
# Use the default name if there are default arguments
# This is especially for library cells so that the spice and gds files can be found.
if len(kwargs)>0:
# This is especially for library cells so that the
# spice and gds files can be found.
if len(kwargs) > 0:
# Create a unique name and increment the index
module_name = "{0}_{1}".format(module_type, self.module_indices[module_type])
module_name = "{0}_{1}".format(module_type,
self.module_indices[module_type])
self.module_indices[module_type] += 1
else:
module_name = module_type
#debug.info(0, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs)))
obj = mod(name=module_name,**kwargs)
self.objects[module_type].append((kwargs,obj))
# type_str = "type={}".format(module_type)
# name_str = "name={}".format(module_name)
# kwargs_str = "kwargs={}".format(str(kwargs))
# import debug
# debug.info(0, "New module:" + type_str + name_str + kwargs_str)
obj = mod(name=module_name, **kwargs)
self.objects[module_type].append((kwargs, obj))
return obj
def get_mods(self, module_type):
@ -90,11 +92,11 @@ class sram_factory:
module_type = getattr(OPTS, module_type)
try:
mod_tuples = self.objects[module_type]
mods = [mod for kwargs,mod in mod_tuples]
mods = [mod for kwargs, mod in mod_tuples]
except KeyError:
mods = []
return mods
# Make a factory
factory = sram_factory()

View File

@ -9,8 +9,8 @@
import pstats
p = pstats.Stats("profile.dat")
p.strip_dirs()
#p.sort_stats("cumulative")
# p.sort_stats("cumulative")
p.sort_stats("tottime")
#p.print_stats(50)
# p.print_stats(50)
p.print_stats()