mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into update_scmos_models
This commit is contained in:
commit
d722311822
|
|
@ -7,32 +7,37 @@
|
|||
#
|
||||
import hierarchy_design
|
||||
import debug
|
||||
import utils
|
||||
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
|
||||
|
|
@ -67,7 +72,8 @@ 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
|
||||
|
|
@ -97,8 +103,8 @@ 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,
|
||||
|
|
@ -128,11 +134,11 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
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),
|
||||
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]):
|
||||
|
|
@ -146,7 +152,8 @@ class contact(hierarchy_design.hierarchy_design):
|
|||
|
||||
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),
|
||||
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
|
||||
|
|
@ -158,7 +165,8 @@ 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),
|
||||
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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
|
||||
|
||||
class delay_data():
|
||||
"""
|
||||
This is the delay class to represent the delay information
|
||||
|
|
@ -20,7 +21,7 @@ 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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -54,8 +55,10 @@ class geometry:
|
|||
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()
|
||||
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):
|
||||
|
|
@ -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
|
||||
|
|
@ -142,7 +144,8 @@ class instance(geometry):
|
|||
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
|
||||
|
|
@ -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"""
|
||||
|
||||
|
|
@ -356,11 +360,12 @@ class rectangle(geometry):
|
|||
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 []
|
||||
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,13 +52,14 @@ 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"]
|
||||
# Only output lef/gds if back-end
|
||||
if not OPTS.netlist_only:
|
||||
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:
|
||||
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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
import optparse
|
||||
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.
|
||||
"""
|
||||
|
||||
|
|
@ -47,7 +47,8 @@ class options(optparse.Values):
|
|||
###################
|
||||
# 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"
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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,26 +58,28 @@ 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.
|
||||
# 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)))
|
||||
# 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
|
||||
|
|
@ -95,6 +97,6 @@ class sram_factory:
|
|||
mods = []
|
||||
return mods
|
||||
|
||||
|
||||
# Make a factory
|
||||
factory = sram_factory()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue