2016-11-08 18:57:35 +01:00
|
|
|
"""
|
|
|
|
|
This is called globals.py, but it actually parses all the arguments and performs
|
|
|
|
|
the global OpenRAM setup as well.
|
|
|
|
|
"""
|
|
|
|
|
import os
|
|
|
|
|
import debug
|
|
|
|
|
import shutil
|
|
|
|
|
import optparse
|
|
|
|
|
import options
|
|
|
|
|
import sys
|
|
|
|
|
import re
|
|
|
|
|
import importlib
|
|
|
|
|
|
|
|
|
|
# Current version of OpenRAM.
|
2017-10-05 05:18:30 +02:00
|
|
|
VERSION = "1.01"
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-06-12 23:37:15 +02:00
|
|
|
USAGE = "Usage: openram.py [options] <config file>\nUse -h for help.\n"
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
# Anonymous object that will be the options
|
|
|
|
|
OPTS = options.options()
|
|
|
|
|
|
2017-06-12 23:37:15 +02:00
|
|
|
# check that we are not using version 3 and at least 2.7
|
|
|
|
|
major_python_version = sys.version_info.major
|
|
|
|
|
minor_python_version = sys.version_info.minor
|
|
|
|
|
if not (major_python_version == 2 and minor_python_version >= 7):
|
|
|
|
|
debug.error("Python 2.7 is required.",-1)
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
def is_exe(fpath):
|
|
|
|
|
return os.path.exists(fpath) and os.access(fpath, os.X_OK)
|
|
|
|
|
|
|
|
|
|
# parse the optional arguments
|
|
|
|
|
# this only does the optional arguments
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_args():
|
|
|
|
|
"""Parse the arguments and initialize openram"""
|
|
|
|
|
|
|
|
|
|
global OPTS
|
|
|
|
|
|
|
|
|
|
option_list = {
|
2017-05-31 17:12:17 +02:00
|
|
|
optparse.make_option("-b", "--backannotated", action="store_true", dest="run_pex",
|
2017-06-12 23:37:15 +02:00
|
|
|
help="Back annotate simulation"),
|
|
|
|
|
optparse.make_option("-o", "--output", 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"),
|
2016-11-08 18:57:35 +01:00
|
|
|
optparse.make_option("-n", "--nocheck", action="store_false",
|
|
|
|
|
help="Disable inline LVS/DRC checks", dest="check_lvsdrc"),
|
|
|
|
|
optparse.make_option("-q", "--quiet", action="store_false", dest="print_banner",
|
|
|
|
|
help="Don\'t display banner"),
|
|
|
|
|
optparse.make_option("-v", "--verbose", action="count", dest="debug_level",
|
|
|
|
|
help="Increase the verbosity level"),
|
|
|
|
|
optparse.make_option("-t", "--tech", dest="tech_name",
|
|
|
|
|
help="Technology name"),
|
|
|
|
|
optparse.make_option("-s", "--spiceversion", dest="spice_version",
|
|
|
|
|
help="Spice simulator name"),
|
2017-11-14 22:24:14 +01:00
|
|
|
optparse.make_option("-r", "--remove_netlist_trimming", action="store_false", dest="trim_netlist",
|
|
|
|
|
help="Disable removal of noncritical memory cells during characterization"),
|
2017-05-31 17:12:17 +02:00
|
|
|
optparse.make_option("-a", "--analytical", action="store_true", dest="analytical_delay",
|
2017-11-09 20:13:44 +01:00
|
|
|
help="Use analytical models to calculate delays (default)"),
|
|
|
|
|
optparse.make_option("-c", "--characterize", action="store_false", dest="analytical_delay",
|
|
|
|
|
help="Perform characterization to calculate delays (default is analytical models)")
|
2016-11-08 18:57:35 +01:00
|
|
|
}
|
|
|
|
|
# -h --help is implicit.
|
|
|
|
|
|
|
|
|
|
parser = optparse.OptionParser(option_list=option_list,
|
|
|
|
|
description="Compile and/or characterize an SRAM.",
|
|
|
|
|
usage=USAGE,
|
|
|
|
|
version="sramc v" + VERSION)
|
|
|
|
|
|
|
|
|
|
(options, args) = parser.parse_args(values=OPTS)
|
|
|
|
|
|
2017-01-11 20:47:58 +01:00
|
|
|
# If we don't specify a tech, assume freepdk45.
|
|
|
|
|
# This may be overridden when we read a config file though...
|
|
|
|
|
if OPTS.tech_name == "":
|
|
|
|
|
OPTS.tech_name = "freepdk45"
|
|
|
|
|
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
return (options, args)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_opts():
|
|
|
|
|
return(OPTS)
|
|
|
|
|
|
2016-11-15 19:13:57 +01:00
|
|
|
def print_banner():
|
|
|
|
|
""" Conditionally print the banner to stdout """
|
|
|
|
|
global OPTS
|
|
|
|
|
if not OPTS.print_banner:
|
|
|
|
|
return
|
|
|
|
|
|
2017-06-13 00:02:48 +02:00
|
|
|
print("|==============================================================================|")
|
2016-11-15 19:13:57 +01:00
|
|
|
name = "OpenRAM Compiler v"+VERSION
|
2017-06-13 00:02:48 +02:00
|
|
|
print("|=========" + name.center(60) + "=========|")
|
|
|
|
|
print("|=========" + " ".center(60) + "=========|")
|
|
|
|
|
print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|")
|
|
|
|
|
print("|=========" + "University of California Santa Cruz CE Department".center(60) + "=========|")
|
|
|
|
|
print("|=========" + " ".center(60) + "=========|")
|
|
|
|
|
print("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|")
|
|
|
|
|
print("|=========" + "Oklahoma State University ECE Department".center(60) + "=========|")
|
|
|
|
|
print("|=========" + " ".center(60) + "=========|")
|
|
|
|
|
print("|=========" + OPTS.openram_temp.center(60) + "=========|")
|
|
|
|
|
print("|==============================================================================|")
|
2016-11-15 19:13:57 +01:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
def init_openram(config_file):
|
|
|
|
|
"""Initialize the technology, paths, simulators, etc."""
|
|
|
|
|
|
|
|
|
|
debug.info(1,"Initializing OpenRAM...")
|
|
|
|
|
|
|
|
|
|
setup_paths()
|
|
|
|
|
|
2017-06-12 23:37:15 +02:00
|
|
|
read_config(config_file)
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
import_tech()
|
|
|
|
|
|
|
|
|
|
set_spice()
|
|
|
|
|
|
2017-11-15 00:27:03 +01:00
|
|
|
global OPTS
|
|
|
|
|
OPTS.drc_exe = get_tool("DRC",["calibre","magic"])
|
|
|
|
|
OPTS.lvs_exe = get_tool("LVS",["calibre","netgen"])
|
|
|
|
|
OPTS.pex_exe = get_tool("PEX",["calibre","magic"])
|
|
|
|
|
#set_drc()
|
|
|
|
|
#set_lvs()
|
|
|
|
|
#set_pex()
|
2017-11-14 23:59:14 +01:00
|
|
|
|
2017-06-02 20:11:57 +02:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
def read_config(config_file):
|
|
|
|
|
global OPTS
|
|
|
|
|
|
|
|
|
|
OPTS.config_file = config_file
|
|
|
|
|
OPTS.config_file = re.sub(r'\.py$', "", OPTS.config_file)
|
|
|
|
|
|
|
|
|
|
# dynamically import the configuration file of which modules to use
|
|
|
|
|
debug.info(1, "Configuration file is " + OPTS.config_file + ".py")
|
|
|
|
|
try:
|
|
|
|
|
OPTS.config = importlib.import_module(OPTS.config_file)
|
|
|
|
|
except:
|
|
|
|
|
debug.error("Unable to read configuration file: {0}".format(OPTS.config_file+".py. Did you specify the technology?"),2)
|
|
|
|
|
|
2017-06-12 23:37:15 +02:00
|
|
|
# This path must be setup after the config file.
|
|
|
|
|
try:
|
|
|
|
|
# If path not set on command line, try config file.
|
|
|
|
|
if OPTS.output_path=="":
|
|
|
|
|
OPTS.output_path=OPTS.config.output_path
|
|
|
|
|
except:
|
|
|
|
|
# Default to current directory.
|
|
|
|
|
OPTS.output_path="."
|
|
|
|
|
if not OPTS.output_path.endswith('/'):
|
|
|
|
|
OPTS.output_path += "/"
|
|
|
|
|
debug.info(1, "Output saved in " + OPTS.output_path)
|
2017-07-06 17:42:25 +02:00
|
|
|
|
|
|
|
|
# Don't delete the output dir, it may have other files!
|
|
|
|
|
# make the directory if it doesn't exist
|
|
|
|
|
try:
|
|
|
|
|
os.makedirs(OPTS.output_path, 0o750)
|
|
|
|
|
except OSError as e:
|
|
|
|
|
if e.errno == 17: # errno.EEXIST
|
|
|
|
|
os.chmod(OPTS.output_path, 0o750)
|
|
|
|
|
except:
|
|
|
|
|
debug.error("Unable to make output directory.",-1)
|
|
|
|
|
|
2017-06-12 23:37:15 +02:00
|
|
|
|
2017-11-14 23:59:14 +01:00
|
|
|
def find_exe(check_exe):
|
|
|
|
|
""" Check if the binary exists in the path and return the full path. """
|
|
|
|
|
# Check if the preferred spice option exists in the path
|
|
|
|
|
for path in os.environ["PATH"].split(os.pathsep):
|
|
|
|
|
exe = os.path.join(path, check_exe)
|
|
|
|
|
# if it is found, then break and use first version
|
|
|
|
|
if is_exe(exe):
|
|
|
|
|
return exe
|
2017-11-15 00:31:58 +01:00
|
|
|
return ""
|
2017-11-14 23:59:14 +01:00
|
|
|
|
2017-11-15 00:27:03 +01:00
|
|
|
def get_tool(tool_type, preferences):
|
|
|
|
|
"""
|
|
|
|
|
Find which tool we have from a list of preferences and return the full path.
|
|
|
|
|
"""
|
|
|
|
|
debug.info(2,"Finding {} tool...".format(tool_type))
|
2017-11-14 23:59:14 +01:00
|
|
|
global OPTS
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-11-14 23:59:14 +01:00
|
|
|
if not OPTS.check_lvsdrc:
|
|
|
|
|
debug.info(1,"LVS/DRC/PEX disabled.")
|
2017-11-15 00:31:58 +01:00
|
|
|
return None
|
2017-11-14 23:59:14 +01:00
|
|
|
else:
|
2017-11-15 00:27:03 +01:00
|
|
|
for name in preferences:
|
|
|
|
|
exe_name = find_exe(name)
|
2017-11-15 00:31:58 +01:00
|
|
|
if exe_name!="":
|
2017-11-15 00:27:03 +01:00
|
|
|
debug.info(1, "Using {0}: {1}".format(tool_type,exe_name))
|
|
|
|
|
return(exe_name)
|
2017-11-14 23:59:14 +01:00
|
|
|
else:
|
2017-11-15 00:27:03 +01:00
|
|
|
debug.info(1, "Could not find {0}, trying next {1} tool.".format(name,tool_type))
|
2017-11-15 00:49:47 +01:00
|
|
|
else:
|
|
|
|
|
return("")
|
2017-11-15 00:27:03 +01:00
|
|
|
|
2016-11-11 23:05:14 +01:00
|
|
|
def end_openram():
|
|
|
|
|
""" Clean up openram for a proper exit """
|
|
|
|
|
cleanup_paths()
|
2017-06-02 20:11:57 +02:00
|
|
|
|
|
|
|
|
# Reset the static duplicate name checker for unit tests.
|
|
|
|
|
# This is needed for running unit tests.
|
|
|
|
|
import design
|
|
|
|
|
design.design.name_map=[]
|
|
|
|
|
|
2016-11-11 23:05:14 +01:00
|
|
|
|
|
|
|
|
def cleanup_paths():
|
|
|
|
|
# we should clean up this temp directory after execution...
|
|
|
|
|
if os.path.exists(OPTS.openram_temp):
|
|
|
|
|
shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
def setup_paths():
|
|
|
|
|
""" Set up the non-tech related paths. """
|
|
|
|
|
debug.info(2,"Setting up paths...")
|
|
|
|
|
|
|
|
|
|
global OPTS
|
|
|
|
|
|
2016-11-09 21:00:16 +01:00
|
|
|
try:
|
|
|
|
|
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
|
|
|
|
|
except:
|
2017-05-12 23:56:31 +02:00
|
|
|
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+"/gdsMill"),
|
|
|
|
|
"$OPENRAM_HOME/gdsMill does not exist: {0}".format(OPENRAM_HOME+"/gdsMill"))
|
2016-11-08 18:57:35 +01:00
|
|
|
sys.path.append("{0}/gdsMill".format(OPENRAM_HOME))
|
2017-05-12 23:56:31 +02:00
|
|
|
debug.check(os.path.isdir(OPENRAM_HOME+"/tests"),
|
|
|
|
|
"$OPENRAM_HOME/tests does not exist: {0}".format(OPENRAM_HOME+"/tests"))
|
2016-11-08 18:57:35 +01:00
|
|
|
sys.path.append("{0}/tests".format(OPENRAM_HOME))
|
2017-05-12 23:56:31 +02:00
|
|
|
debug.check(os.path.isdir(OPENRAM_HOME+"/characterizer"),
|
|
|
|
|
"$OPENRAM_HOME/characterizer does not exist: {0}".format(OPENRAM_HOME+"/characterizer"))
|
2016-11-08 18:57:35 +01:00
|
|
|
sys.path.append("{0}/characterizer".format(OPENRAM_HOME))
|
2017-05-23 17:31:23 +02:00
|
|
|
debug.check(os.path.isdir(OPENRAM_HOME+"/router"),
|
|
|
|
|
"$OPENRAM_HOME/router does not exist: {0}".format(OPENRAM_HOME+"/router"))
|
|
|
|
|
sys.path.append("{0}/router".format(OPENRAM_HOME))
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
if not OPTS.openram_temp.endswith('/'):
|
|
|
|
|
OPTS.openram_temp += "/"
|
2016-11-15 18:04:32 +01:00
|
|
|
debug.info(1, "Temporary files saved in " + OPTS.openram_temp)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2016-11-11 23:05:14 +01:00
|
|
|
cleanup_paths()
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
# make the directory if it doesn't exist
|
|
|
|
|
try:
|
2017-06-13 00:02:48 +02:00
|
|
|
os.makedirs(OPTS.openram_temp, 0o750)
|
2016-11-08 18:57:35 +01:00
|
|
|
except OSError as e:
|
|
|
|
|
if e.errno == 17: # errno.EEXIST
|
2017-06-13 00:02:48 +02:00
|
|
|
os.chmod(OPTS.openram_temp, 0o750)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-07-06 17:42:25 +02:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_spice():
|
|
|
|
|
debug.info(2,"Finding spice...")
|
|
|
|
|
global OPTS
|
|
|
|
|
|
2017-11-09 20:13:44 +01:00
|
|
|
if OPTS.analytical_delay:
|
|
|
|
|
debug.info(1,"Using analytical delay models (no characterization)")
|
|
|
|
|
return
|
|
|
|
|
else:
|
2017-11-14 22:24:14 +01:00
|
|
|
if OPTS.spice_version != "":
|
2017-11-14 23:59:14 +01:00
|
|
|
OPTS.spice_exe=find_exe(OPTS.spice_version)
|
2017-11-15 00:31:58 +01:00
|
|
|
if OPTS.spice_exe=="":
|
2017-11-14 22:24:14 +01:00
|
|
|
debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_version),1)
|
|
|
|
|
else:
|
2017-11-15 00:31:58 +01:00
|
|
|
OPTS.spice_exe = get_tool("spice",["xa", "hspice", "ngspice", "ngspice.exe"])
|
2016-11-10 17:18:52 +01:00
|
|
|
|
2016-11-10 20:33:10 +01:00
|
|
|
# set the input dir for spice files if using ngspice
|
|
|
|
|
if OPTS.spice_version == "ngspice":
|
|
|
|
|
os.environ["NGSPICE_INPUT_DIR"] = "{0}".format(OPTS.openram_temp)
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2016-11-10 20:33:10 +01:00
|
|
|
if OPTS.spice_exe == "":
|
2017-11-12 19:42:41 +01:00
|
|
|
debug.error("No recognizable spice version found. Unable to perform characterization.",1)
|
2017-06-02 20:11:57 +02:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2016-11-10 20:33:10 +01:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
# imports correct technology directories for testing
|
|
|
|
|
def import_tech():
|
|
|
|
|
global OPTS
|
|
|
|
|
|
|
|
|
|
debug.info(2,"Importing technology: " + OPTS.tech_name)
|
|
|
|
|
|
2017-01-11 20:47:58 +01:00
|
|
|
# Set the tech to the config file we read in instead of the command line value.
|
|
|
|
|
OPTS.tech_name = OPTS.config.tech_name
|
|
|
|
|
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
# environment variable should point to the technology dir
|
2016-11-09 21:00:16 +01:00
|
|
|
try:
|
|
|
|
|
OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH"))
|
|
|
|
|
except:
|
2017-05-12 23:56:31 +02:00
|
|
|
debug.error("$OPENRAM_TECH is not properly defined.",1)
|
|
|
|
|
debug.check(os.path.isdir(OPENRAM_TECH),"$OPENRAM_TECH does not exist: {0}".format(OPENRAM_TECH))
|
|
|
|
|
|
2016-11-09 21:00:16 +01:00
|
|
|
OPTS.openram_tech = OPENRAM_TECH + "/" + OPTS.tech_name
|
2016-11-08 18:57:35 +01:00
|
|
|
if not OPTS.openram_tech.endswith('/'):
|
|
|
|
|
OPTS.openram_tech += "/"
|
|
|
|
|
debug.info(1, "Technology path is " + OPTS.openram_tech)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
filename = "setup_openram_{0}".format(OPTS.tech_name)
|
|
|
|
|
# we assume that the setup scripts (and tech dirs) are located at the
|
|
|
|
|
# same level as the compielr itself, probably not a good idea though.
|
|
|
|
|
path = "{0}/setup_scripts".format(os.environ.get("OPENRAM_TECH"))
|
2017-05-12 23:56:31 +02:00
|
|
|
debug.check(os.path.isdir(path),"OPENRAM_TECH does not exist: {0}".format(path))
|
2016-11-08 18:57:35 +01:00
|
|
|
sys.path.append(os.path.abspath(path))
|
|
|
|
|
__import__(filename)
|
|
|
|
|
except ImportError:
|
|
|
|
|
debug.error("Nonexistent technology_setup_file: {0}.py".format(filename))
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|