Merge remote-tracking branch 'origin/master' into router

This commit is contained in:
Matt Guthaus 2016-11-15 10:21:02 -08:00
commit 836c7ece73
67 changed files with 440 additions and 184 deletions

Binary file not shown.

2
README
View File

@ -3,7 +3,7 @@ BASIC SETUP
-The OpenRAM compiler has very few dependencies:
1) ngspice v20 or later or HSpice I-2013.12-1 or later
1) ngspice-25 or later or HSpice I-2013.12-1 or later
2) Python 2.7 and higher (currently excludes Python 3 and up)
3) a setup script for each technology
4) a technology directory for each technology with the base cells

View File

@ -29,4 +29,12 @@ hierarchical_predecode3x8 to hierarchical_predecode class
Fix stimuli.py to be more readable.
Change the delay measurement to be from the negative clock edge to
remove the dependency on the clock period.
remove the dependency on the clock period.
Remove duplicate clock inverter in MS flop.
Make lib file have delay relative to negedge for DATA. Must update
timing code too.
Convert characterizer into a Python package

View File

@ -90,6 +90,7 @@ def run_drc(name, gds_name):
f.close()
# run drc
cwd = os.getcwd()
os.chdir(OPTS.openram_temp)
errfile = "%s%s.drc.err" % (OPTS.openram_temp, name)
outfile = "%s%s.drc.out" % (OPTS.openram_temp, name)
@ -98,6 +99,7 @@ def run_drc(name, gds_name):
OPTS.calibre_exe, OPTS.openram_temp, errfile, outfile)
debug.info(1, cmd)
os.system(cmd)
os.chdir(cwd)
# check the result for these lines in the summary:
# TOTAL Original Layer Geometries: 106 (157)
@ -163,6 +165,7 @@ def run_lvs(name, gds_name, sp_name):
f.close()
# run LVS
cwd = os.getcwd()
os.chdir(OPTS.openram_temp)
errfile = "%s%s.lvs.err" % (OPTS.openram_temp, name)
outfile = "%s%s.lvs.out" % (OPTS.openram_temp, name)
@ -171,6 +174,7 @@ def run_lvs(name, gds_name, sp_name):
OPTS.openram_temp, errfile, outfile)
debug.info(2, cmd)
os.system(cmd)
os.chdir(cwd)
# check the result for these lines in the summary:
f = open(lvs_runset['lvsReportFile'], "r")
@ -265,6 +269,7 @@ def run_pex(name, gds_name, sp_name, output=None):
f.close()
# run pex
cwd = os.getcwd()
os.chdir(OPTS.openram_temp)
errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name)
outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name)
@ -275,6 +280,7 @@ def run_pex(name, gds_name, sp_name, output=None):
outfile)
debug.info(2, cmd)
os.system(cmd)
os.chdir(cwd)
# also check the output file
f = open(outfile, "r")

View File

@ -27,7 +27,11 @@ def relative_compare(value1,value2):
def parse_output(filename, key):
"""Parses a hspice output.lis file for a key value"""
f = open("{0}/{1}.lis".format(OPTS.openram_temp, filename), "r")
full_filename="{0}{1}.lis".format(OPTS.openram_temp, filename)
try:
f = open(full_filename, "r")
except IOError:
debug.error("Unable to open spice output file: {0}".format(full_filename),1)
contents = f.read()
val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents)
if val != None:

View File

@ -6,6 +6,7 @@ import tech
import math
import stimuli
import charutils as ch
import utils
OPTS = globals.get_opts()
@ -262,20 +263,11 @@ class delay():
# run until the last cycle time
end_time = self.cycle_times[-1]
self.sf.write(".TRAN 5p {0}n\n".format(end_time))
if OPTS.spice_version == "hspice":
# create plots for all signals
self.sf.write(".OPTIONS POST=1 PROBE\n")
self.sf.write(".probe V(*)\n")
# end the stimulus file
self.sf.write(".end\n")
self.sf.close()
else:
self.sf.write(".control\n")
self.sf.write("run\n")
self.sf.write("quit\n")
self.sf.write(".endc\n")
self.sf.write(".end\n")
self.sf.write(".OPTIONS POST=1 PROBE\n")
# create plots for all signals
self.sf.write(".probe V(*)\n")
# end the stimulus file
self.sf.write(".end\n")
@ -353,20 +345,19 @@ class delay():
target_period = 0.5 * (ub_period + lb_period)
debug.info(1, "MinPeriod Search: {0}ns (ub: {1} lb: {2})".format(target_period,
ub_period,
lb_period))
ub_period,
lb_period))
(success, delay_out) = self.try_period(feasible_period, target_period, data_value)
if success:
if ch.relative_compare(ub_period, target_period):
# use the two values to compare, but only return the ub since it is guaranteed feasible
(success, delay_out) = self.try_period(feasible_period, ub_period, data_value)
return (ub_period, delay_out)
fail_flag = False
ub_period = target_period
else:
lb_period = target_period
if ch.relative_compare(ub_period, lb_period):
# use the two values to compare, but only return the ub since it is guaranteed feasible
(success, delay_out) = self.try_period(feasible_period, ub_period, data_value)
return (ub_period, delay_out)
self.error("Should not reach here.",-1)
return (target_period, delay_out)

View File

@ -165,20 +165,12 @@ class setup_hold():
def write_control(self, period):
# transient window
end_time = 2 * period
self.sf.write(".TRAN 1n {0}n\n".format(end_time))
self.sf.write(".TRAN 5p {0}n\n".format(end_time))
self.sf.write(".OPTIONS POST=1 PROBE\n")
if OPTS.spice_version == "hspice":
self.sf.write(".probe V(*)\n")
# end the stimulus file
self.sf.write(".end\n")
else:
self.sf.write(".control\n")
self.sf.write("run\n")
self.sf.write("quit\n")
self.sf.write(".endc\n")
self.sf.write(".end\n")
# create plots for all signals
self.sf.write(".probe V(*)\n")
# end the stimulus file
self.sf.write(".end\n")
def bidir_search(self, correct_value, noise_margin, measure_name, mode):
""" This will perform a bidirectional search for either setup or hold times.
@ -186,9 +178,11 @@ class setup_hold():
depending on whether we are doing setup or hold.
"""
period = tech.spice["feasible_period"]
debug.info(2,"Feasible period from technology file: {0} ".format(period))
# The clock will start being offset by a period, so we want to look before and after
# theis time.
# this time by half a period.
if mode == "HOLD":
target_time = 1.5 * period
lower_bound = 0.5*period
@ -212,6 +206,8 @@ class setup_hold():
setuphold_time = target_time - period
else:
setuphold_time = period - target_time
debug.info(2,"Checked initial {0} time {1}, data at {2}, clock at {3} ".format(mode,setuphold_time,
target_time,period))
debug.info(3,"Target time: {0} Low: {1} Up: {2} Measured: {3}".format(target_time,
lower_bound,
upper_bound,
@ -220,6 +216,10 @@ class setup_hold():
debug.error("Initial period/target hold time fails for data value",2)
# We already found it feasible, so advance one step first thing.
debug.info(2,"Performing bidir search on {3} time: {2} LB: {0} UB: {1} ".format(lower_bound,
upper_bound,
setuphold_time,
mode))
if mode == "HOLD":
target_time -= 0.5 * (upper_bound - lower_bound)
else:
@ -269,6 +269,8 @@ class setup_hold():
setuphold_time = target_time - period
else:
setuphold_time = period - target_time
debug.info(2,"Converged on {0} time {1}, data at {2}, clock at {3}.".format(mode,setuphold_time,target_time,period))
return setuphold_time

View File

@ -445,23 +445,31 @@ def write_supply(stim_file, vdd_name, gnd_name, vdd_voltage, gnd_voltage):
def run_sim():
"""Run hspice in batch mode and output rawfile to parse."""
temp_stim = "{0}stim.sp".format(OPTS.openram_temp)
if OPTS.spice_version == "hspice":
# TODO: Should make multithreading parameter a configuration option
cmd_args = "-mt 8 -i {1} -o {2}timing 2>&1 /dev/null".format(OPTS.spice_exe,
cmd = "{0} -mt 8 -i {1} -o {2}timing".format(OPTS.spice_exe,
temp_stim,
OPTS.openram_temp)
valid_retcode=0
else:
cmd_args = "-b -i {1} -o {2}timing.lis 2>&1 /dev/null".format(OPTS.spice_exe,
temp_stim,
OPTS.openram_temp)
cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe,
temp_stim,
OPTS.openram_temp)
# for some reason, ngspice-25 returns 1 when it only has acceptable warnings
valid_retcode=1
FNULL = open(os.devnull, 'w')
debug.info(2, OPTS.spice_exe + " " + cmd_args)
retcode = subprocess.call([OPTS.spice_exe, cmd_args], stdout=FNULL, stderr=FNULL)
FNULL.close()
spice_stdout = open("{0}spice_stdout.log".format(OPTS.openram_temp), 'w')
spice_stderr = open("{0}spice_stderr.log".format(OPTS.openram_temp), 'w')
if (retcode > 0):
debug.error("Spice simulation error: " + OPTS.spice_exe + " " + cmd_args)
sys.exit(-1)
debug.info(3, cmd)
retcode = subprocess.call(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True)
spice_stdout.close()
spice_stderr.close()
if (retcode > valid_retcode):
debug.error("Spice simulation error: " + cmd, -1)

View File

@ -18,7 +18,7 @@ class contact(design.design):
dimensions[1],
contact.unique_contact_id)
design.design.__init__(self, name)
debug.info(2, "create contact object {0}".format(name))
debug.info(3, "create contact object {0}".format(name))
contact.unique_contact_id += 1
self.layer_stack = layer_stack

View File

@ -14,19 +14,6 @@ import importlib
# Current version of OpenRAM.
VERSION = "1.0"
# Output banner for file output and program execution.
BANNER = """\
##############################################################
# #
# OpenRAM Compiler v""" + VERSION + """ #
# #
# VLSI Design Automation Lab #
# UCSC CE Department #
# #
# VLSI Computer Architecture Research Group #
# Oklahoma State University ECE Department #
# #
##############################################################\n"""
USAGE = "usage: openram.py [options] <config file>\n"
@ -81,6 +68,25 @@ def parse_args():
def get_opts():
return(OPTS)
def print_banner():
""" Conditionally print the banner to stdout """
global OPTS
if not OPTS.print_banner:
return
print "|==============================================================================|"
name = "OpenRAM Compiler v"+VERSION
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 "|==============================================================================|"
def init_openram(config_file):
"""Initialize the technology, paths, simulators, etc."""
@ -140,7 +146,6 @@ def end_openram():
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)
@ -191,23 +196,48 @@ def set_spice():
debug.info(2,"Finding spice...")
global OPTS
# set the input dir for spice files if using ngspice (not needed for
# hspice)
OPTS.spice_exe = ""
# Check if the preferred spice option exists in the path
for path in os.environ["PATH"].split(os.pathsep):
spice_exe = os.path.join(path, OPTS.spice_version)
# if it is found, then break and use first version
if is_exe(spice_exe):
debug.info(1, "Using spice: " + spice_exe)
OPTS.spice_exe = spice_exe
break
if not OPTS.force_spice and OPTS.spice_exe == "":
# if we didn't find the preferred version, try the other version and warn
prev_version=OPTS.spice_version
if OPTS.spice_version == "hspice":
OPTS.spice_version = "ngspice"
else:
OPTS.spice_version = "hspice"
debug.warning("Unable to find {0} so trying {1}".format(prev_version,OPTS.spice_version))
for path in os.environ["PATH"].split(os.pathsep):
spice_exe = os.path.join(path, OPTS.spice_version)
# if it is found, then break and use first version
if is_exe(spice_exe):
found_spice = True
debug.info(1, "Using spice: " + spice_exe)
OPTS.spice_exe = spice_exe
break
# 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)
# search for calibre in the path
for path in os.environ["PATH"].split(os.pathsep):
OPTS.spice_exe = os.path.join(path, OPTS.spice_version)
# if it is found, then break and use first version
if is_exe(OPTS.spice_exe):
debug.info(1, "Using spice: " + OPTS.spice_exe)
break
else:
if OPTS.spice_exe == "":
# otherwise, give warning and procede
debug.warning("Spice not found. Unable to perform characterization.")
if OPTS.force_spice:
debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_version),1)
else:
debug.error("Neither hspice/ngspice not found. Unable to perform characterization.",1)
# imports correct technology directories for testing
def import_tech():
global OPTS

View File

@ -245,14 +245,14 @@ class layout:
Otherwise, start a new layout for dynamic generation."""
# open the gds file if it exists or else create a blank layout
if os.path.isfile(self.gds_file):
debug.info(2, "opening %s" % self.gds_file)
debug.info(3, "opening %s" % self.gds_file)
self.gds = gdsMill.VlsiLayout(units=GDS["unit"])
reader = gdsMill.Gds2reader(self.gds)
reader.loadFromFile(self.gds_file)
# TODO: parse the width/height
# TODO: parse the pin locations
else:
debug.info(2, "creating structure %s" % self.name)
debug.info(3, "creating structure %s" % self.name)
self.gds = gdsMill.VlsiLayout(
name=self.name, units=GDS["unit"])

View File

@ -68,7 +68,7 @@ class spice:
"""Reads the sp file (and parse the pins) from the library
Otherwise, initialize it to null for dynamic generation"""
if os.path.isfile(self.sp_file):
debug.info(2, "opening {0}".format(self.sp_file))
debug.info(3, "opening {0}".format(self.sp_file))
f = open(self.sp_file)
self.spice = f.readlines()
for i in range(len(self.spice)):

View File

@ -33,9 +33,8 @@ import debug
if len(args) < 1:
print globals.USAGE
sys.exit(2)
if OPTS.print_banner:
print globals.BANNER
globals.print_banner()
globals.init_openram(args[0])
@ -94,7 +93,7 @@ s.gds_write(gdsname)
# Run Characterizer on the design
sram_file = spname
if OPTS.run_pex:
if OPTS.use_pex:
sram_file = OPTS.out_path + "temp_pex.sp"
calibre.run_pex(s.name, gdsname, spname, output=sram_file)

View File

@ -6,6 +6,7 @@ class options(optparse.Values):
"""
Class for holding all of the OpenRAM options.
"""
# This is the technology directory.
openram_tech = ""
# This is the name of the technology.
@ -19,6 +20,8 @@ class options(optparse.Values):
check_lvsdrc = True
# Variable to select the variant of spice (hspice or ngspice right now)
spice_version = "hspice"
# Should we fall back if we can't find our preferred spice?
force_spice = False
# Should we print out the banner at startup
print_banner = True
# The Calibre executable being used which is derived from the user PATH.
@ -26,7 +29,7 @@ class options(optparse.Values):
# The spice executable being used which is derived from the user PATH.
spice_exe = ""
# Run with extracted parasitics
run_pex = False
use_pex = False
# Trim noncritical memory cells for simulation speed-up
trim_noncritical = False
# Define the output file paths

View File

@ -20,7 +20,7 @@ class path(design.design):
name = "path_{0}".format(path.unique_path_id)
path.unique_path_id += 1
design.design.__init__(self, name)
debug.info(2, "create path obj {0}".format(name))
debug.info(3, "create path obj {0}".format(name))
self.name = name
self.layer_name = layer

View File

@ -16,7 +16,7 @@ class ptx(design.design):
name = "{0}{1}".format(name, ptx.unique_mos_id)
ptx.unique_mos_id += 1
design.design.__init__(self, name)
debug.info(2, "create ptx structure {0}".format(name))
debug.info(3, "create ptx structure {0}".format(name))
self.tx_type = tx_type
self.mults = mults

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python2.7
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test the library cells for DRC"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test the library cells for LVS"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test for DRC on basic contacts of different array sizes"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic path"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic parameterized transistors"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -2,7 +2,7 @@
"Run a regresion test on a basic wire"
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -6,7 +6,7 @@ size 2_input nand gate that is nmos_width=2*tech.drc[minwidth_tx].
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -6,7 +6,7 @@ It generate only the minimum size 3_input nand gate that is nmos_width=3*tech.dr
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -5,7 +5,7 @@ This module doesn't generate multi_finger 2_input nor gate
It generate only the minimum size 2_input nor gate that is nmos_width=2*tech.drc[minwidth_tx]
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run regresion tests on a parameterized inverter
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a wordline_driver array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a basic array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a thierarchy_decoder.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a hierarchical_predecode2x4.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a hierarchical_predecode3x8.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a single transistor column_mux.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a precharge array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a sense amp array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a write driver array
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a dff_array.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a control_logic
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a test on a delay chain
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a tri_gate_array.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a test on a delay chain
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a 1 bank SRAM
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a 2 bank SRAM
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on a 4 bank SRAM
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -22,8 +22,10 @@ class timing_sram_test(unittest.TestCase):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.use_pex = False
OPTS.spice_version="hspice"
OPTS.force_spice = True
globals.set_spice()
import sram
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
@ -60,15 +62,9 @@ class timing_sram_test(unittest.TestCase):
self.assertTrue(False) # other techs fail
os.remove(tempspice)
globals.end_openram()
def isclose(value1,value2):
""" This is used to compare relative values for convergence. """
return (abs(value1 - value2) / max(value1,value2) <= 1e-2)
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -22,7 +22,9 @@ class timing_setup_test(unittest.TestCase):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.use_pex = False
OPTS.spice_version="hspice"
OPTS.force_spice = True
globals.set_spice()
import sram
import setup_hold
@ -42,11 +44,6 @@ class timing_setup_test(unittest.TestCase):
self.assertTrue(False) # other techs fail
globals.end_openram()
def isclose(value1,value2):
""" This is used to compare relative values for convergence. """
return (abs(value1 - value2) / max(value1,value2) <= 1e-2)
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -20,9 +20,12 @@ class timing_setup_test(unittest.TestCase):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.use_pex = False
OPTS.spice_version="hspice"
OPTS.force_spice = True
globals.set_spice()
import sram
import setup_hold
@ -42,11 +45,6 @@ class timing_setup_test(unittest.TestCase):
globals.end_openram()
def isclose(value1,value2):
""" This is used to compare relative values for convergence. """
return (abs(value1 - value2) / max(value1,value2) <= 1e-2)
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()

View File

@ -0,0 +1,73 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on various srams
"""
import unittest
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.get_opts()
#@unittest.skip("SKIPPING 21_ngspice_delay_test")
class timing_sram_test(unittest.TestCase):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_version="ngspice"
OPTS.force_spice = True
globals.set_spice()
import sram
debug.info(1, "Testing timing for sample 1bit, 16words SRAM with 1 bank")
s = sram.sram(word_size=OPTS.config.word_size,
num_words=OPTS.config.num_words,
num_banks=OPTS.config.num_banks,
name="test_sram1")
# reset these options
OPTS.check_lvsdrc = True
OPTS.spice_version="hspice"
OPTS.force_spice = False
globals.set_spice()
import delay
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
probe_address = "1" * s.addr_size
probe_data = s.word_size - 1
debug.info(1, "Probe address {0} probe data {1}".format(probe_address, probe_data))
d = delay.delay(s,tempspice)
data = d.analyze(probe_address, probe_data)
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(data['delay1'],0.013649)) # diff than hspice
self.assertTrue(isclose(data['delay0'],0.22893)) # diff than hspice
self.assertTrue(isclose(data['min_period1'],0.078582763671875)) # diff than hspice
self.assertTrue(isclose(data['min_period0'],0.25543212890625)) # diff than hspice
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(data['delay1'],1.5342000000000002)) # diff than hspice
self.assertTrue(isclose(data['delay0'],2.2698)) # diff than hspice
self.assertTrue(isclose(data['min_period1'],1.534423828125)) # diff than hspice
self.assertTrue(isclose(data['min_period0'],2.99560546875)) # diff than hspice
else:
self.assertTrue(False) # other techs fail
os.remove(tempspice)
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,55 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on various srams
"""
import unittest
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.get_opts()
#@unittest.skip("SKIPPING 21_timing_sram_test")
class timing_setup_test(unittest.TestCase):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_version="ngspice"
OPTS.force_spice = True
globals.set_spice()
import sram
import setup_hold
sh = setup_hold.setup_hold()
[one_setup_time, zero_setup_time] = sh.hold_time()
# reset these options
OPTS.check_lvsdrc = True
OPTS.spice_version="hspice"
OPTS.force_spice = False
globals.set_spice()
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(one_setup_time,-0.0048828125))
self.assertTrue(isclose(zero_setup_time,-0.010986328125))
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(one_setup_time,0.45654296875)) # diff than hspice
self.assertTrue(isclose(zero_setup_time,-0.0830078125))
else:
self.assertTrue(False) # other techs fail
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -0,0 +1,55 @@
#!/usr/bin/env python2.7
"""
Run a regresion test on various srams
"""
import unittest
from testutils import header,isclose
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
import debug
import calibre
OPTS = globals.get_opts()
#@unittest.skip("SKIPPING 21_timing_sram_test")
class timing_setup_test(unittest.TestCase):
def runTest(self):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.spice_version="ngspice"
OPTS.force_spice = True
globals.set_spice()
import sram
import setup_hold
sh = setup_hold.setup_hold()
[one_setup_time, zero_setup_time] = sh.setup_time()
# reset these options
OPTS.check_lvsdrc = True
OPTS.spice_version="hspice"
OPTS.force_spice = False
globals.set_spice()
if OPTS.tech_name == "freepdk45":
self.assertTrue(isclose(one_setup_time,0.0146484375))
self.assertTrue(isclose(zero_setup_time,0.008544921875))
elif OPTS.tech_name == "scn3me_subm":
self.assertTrue(isclose(one_setup_time,0.09521484375)) #diff than hspice
self.assertTrue(isclose(zero_setup_time,-0.0244140625))
else:
self.assertTrue(False) # other techs fail
# instantiate a copdsay of the class to actually run the test
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main()

View File

@ -4,7 +4,7 @@ Run a regression test on an extracted SRAM to ensure functionality.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals

View File

@ -4,7 +4,7 @@ Run a regresion test on various srams
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -22,7 +22,6 @@ class sram_func_test(unittest.TestCase):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.use_pex = False
import sram

View File

@ -4,7 +4,7 @@ Check the .lib file for an SRAM
"""
import unittest
from header import header
from testutils import header,isdiff
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -20,11 +20,9 @@ class lib_test(unittest.TestCase):
globals.init_openram("config_20_{0}".format(OPTS.tech_name))
# we will manually run lvs/drc
OPTS.check_lvsdrc = False
OPTS.use_pex = False
import sram
import lib
import filecmp
debug.info(1, "Testing timing for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
@ -33,18 +31,16 @@ class lib_test(unittest.TestCase):
name="sram_2_16_1_{0}".format(OPTS.tech_name))
OPTS.check_lvsdrc = True
tempspice = OPTS.openram_temp + "temp.sp"
s.sp_write(tempspice)
curpath=os.path.dirname(os.path.realpath(__file__)) + "/"
filename = s.name + ".lib"
libname = curpath + filename
libname = OPTS.openram_temp + filename
lib.lib(libname,s,tempspice)
# let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),filename)
self.assertEqual(filecmp.cmp(libname,golden),True)
self.assertEqual(isdiff(libname,golden),True)
os.system("rm {0}".format(libname))

View File

@ -4,7 +4,7 @@ Check the LEF file for an SRMA
"""
import unittest
from header import header
from testutils import header,isdiff
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -23,7 +23,6 @@ class lef_test(unittest.TestCase):
import sram
import lef
import filecmp
debug.info(1, "Testing LEF for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
@ -33,17 +32,16 @@ class lef_test(unittest.TestCase):
OPTS.check_lvsdrc = True
curpath=os.path.dirname(os.path.realpath(__file__)) + "/"
gdsfile = s.name + ".gds"
leffile = s.name + ".lef"
gdsname = curpath + gdsfile
lefname = curpath + leffile
gdsname = OPTS.openram_temp + gdsfile
lefname = OPTS.openram_temp + leffile
s.gds_write(gdsname)
lef.lef(gdsname,lefname,s)
# let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),leffile)
self.assertEqual(filecmp.cmp(lefname,golden),True)
self.assertEqual(isdiff(lefname,golden),True)
os.system("rm {0}".format(gdsname))
os.system("rm {0}".format(lefname))

View File

@ -4,7 +4,7 @@ Check the .v file for an SRAM
"""
import unittest
from header import header
from testutils import header,isdiff
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -23,7 +23,6 @@ class verilog_test(unittest.TestCase):
import sram
import verilog
import filecmp
debug.info(1, "Testing Verilog for sample 2 bit, 16 words SRAM with 1 bank")
s = sram.sram(word_size=2,
@ -33,15 +32,14 @@ class verilog_test(unittest.TestCase):
OPTS.check_lvsdrc = True
curpath=os.path.dirname(os.path.realpath(__file__)) + "/"
vfile = s.name + ".v"
vname = curpath + vfile
vname = OPTS.openram_temp + vfile
verilog.verilog(vname,s)
# let's diff the result with a golden model
golden = "{0}/golden/{1}".format(os.path.dirname(os.path.realpath(__file__)),vfile)
self.assertEqual(filecmp.cmp(vname,golden),True)
self.assertEqual(isdiff(vname,golden),True)
os.system("rm {0}".format(vname))

View File

@ -6,7 +6,7 @@ check that these files are right.
"""
import unittest
from header import header
from testutils import header
import sys,os
sys.path.append(os.path.join(sys.path[0],".."))
import globals
@ -24,10 +24,8 @@ class openram_test(unittest.TestCase):
debug.info(1, "Testing top-level openram.py with 2-bit, 16 word SRAM.")
out_file = "testsram"
# get the directory under the test modules
out_path=os.path.dirname(os.path.realpath(__file__))
# make a temp directory for output
out_path += "/testsram"
out_path = OPTS.openram_temp + out_file
# make sure we start without the files existing
if os.path.exists(out_path):

View File

@ -1,10 +0,0 @@
def header(str, tec):
tst = "Running Test for:"
print "\n"
print " ______________________________________________________________________________ "
print "|==============================================================================|"
print "|=========" + tst.center(60) + "=========|"
print "|=========" + tec.center(60) + "=========|"
print "|=========" + str.center(60) + "=========|"
print "|==============================================================================|"

View File

@ -9,8 +9,8 @@ import globals
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
import header
header.header(__file__, OPTS.tech_name)
from testutils import header
header(__file__, OPTS.tech_name)
# get a list of all files in the tests directory
files = os.listdir(sys.path[0])

View File

@ -0,0 +1,43 @@
def isclose(value1,value2,error_tolerance=1e-2):
""" This is used to compare relative values. """
import debug
relative_diff = abs(value1 - value2) / max(value1,value2)
check = relative_diff <= error_tolerance
if not check:
debug.info(1,"NOT CLOSE {0} {1} relative diff={2}".format(value1,value2,relative_diff))
else:
debug.info(2,"CLOSE {0} {1} relative diff={2}".format(value1,value2,relative_diff))
return (check)
def isdiff(file1,file2):
""" This is used to compare two files and display the diff if they are different.. """
import debug
import filecmp
import difflib
check = filecmp.cmp(file1,file2)
if not check:
debug.info(2,"MISMATCH {0} {1}".format(file1,file2))
f1 = open(file1,"r")
s1 = f1.readlines()
f2 = open(file2,"r")
s2 = f2.readlines()
for line in difflib.unified_diff(s1, s2):
debug.error(line)
else:
debug.info(2,"MATCH {0} {1}".format(file1,file2))
return (check)
def header(filename, technology):
tst = "Running Test for:"
print "\n"
print " ______________________________________________________________________________ "
print "|==============================================================================|"
print "|=========" + tst.center(60) + "=========|"
print "|=========" + technology.center(60) + "=========|"
print "|=========" + filename.center(60) + "=========|"
import globals
OPTS = globals.get_opts()
print "|=========" + OPTS.openram_temp.center(60) + "=========|"
print "|==============================================================================|"

View File

@ -41,3 +41,7 @@ def auto_measure_libcell(pin_list, name, units, layer):
for pin in pin_list:
cell[str(pin)] = gdsPinToOffset(cell_vlsi.readPin(str(pin)))
return cell

View File

@ -20,7 +20,7 @@ class wire(path):
name = "wire_{0}".format(wire.unique_wire_id)
wire.unique_wire_id += 1
design.design.__init__(self, name)
debug.info(2, "create wire obj {0}".format(name))
debug.info(3, "create wire obj {0}".format(name))
self.layer_stack = layer_stack
self.position_list = position_list

View File

@ -23,7 +23,8 @@ os.environ["MGC_TMPDIR"] = "/tmp"
#OpenRAM Paths
DRCLVS_HOME= PDK_DIR+"/ncsu_basekit/techfile/calibre"
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
os.environ["SPICE_MODEL_DIR"] = PDK_DIR+"/ncsu_basekit/models/hspice/tran_models/models_nom"
##########################

View File

@ -21,8 +21,12 @@ os.environ["MGC_TMPDIR"] = "/tmp"
# OpenRAM Paths
OPENRAM_TECH=os.path.abspath(os.environ.get("OPENRAM_TECH"))
DRCLVS_HOME=OPENRAM_TECH+"/scn3me_subm/tech"
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
os.environ["SPICE_MODEL_DIR"] = "/mada/software/techfiles/scn3me_subm"
os.environ["DRCLVS_HOME"] = DRCLVS_HOME
# You can override the spice model diretory in the environment
try:
SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR"))
except:
os.environ["SPICE_MODEL_DIR"] = "/mada/software/techfiles/scn3me_subm"
##########################
# Paths required for OPENRAM to function