mirror of https://github.com/VLSIDA/OpenRAM.git
Skywater changes.
Default 1 thread and no temp subdirectory. Add skywater setup/hold golden data Add CLI option for simulation threads (-m) Add compatibility mode option and nomodcheck for ngspice to speed up sky130 model loading. Make subdir when using default /tmp dir. Pass num_threads so temp subdirs are created.
This commit is contained in:
parent
b6f3fbdd1f
commit
671470f5f2
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: scn4me_subm Archives
|
||||
path: ${{ github.workspace }}/scn4me_subm_temp/*/*
|
||||
path: $OPENRAM_HOME/*.zip
|
||||
freepdk45:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
|
|
@ -38,7 +38,7 @@ jobs:
|
|||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: FreePDK45 Archives
|
||||
path: ${{ github.workspace }}/freepdk45_temp/*/*
|
||||
path: $OPENRAM_HOME/*.zip
|
||||
# coverage_stats:
|
||||
# if: ${{ always() }}
|
||||
# needs: [scn4me_subm, freepdk45]
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ def parse_spice_list(filename, key):
|
|||
f = open(full_filename, "r")
|
||||
except IOError:
|
||||
debug.error("Unable to open spice output file: {0}".format(full_filename),1)
|
||||
debug.archive()
|
||||
|
||||
contents = f.read()
|
||||
f.close()
|
||||
# val = re.search(r"{0}\s*=\s*(-?\d+.?\d*\S*)\s+.*".format(key), contents)
|
||||
|
|
|
|||
|
|
@ -360,6 +360,8 @@ class stimuli():
|
|||
# -r {2}timing.raw
|
||||
ng_cfg = open("{}.spiceinit".format(OPTS.openram_temp), "w")
|
||||
ng_cfg.write("set num_threads={}\n".format(OPTS.num_sim_threads))
|
||||
ng_cfg.write("set ngbehavior=hsa\n")
|
||||
ng_cfg.write("set ng_nomodcheck\n")
|
||||
ng_cfg.close()
|
||||
|
||||
cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe,
|
||||
|
|
|
|||
|
|
@ -109,6 +109,19 @@ def info(lev, str):
|
|||
frm[0].f_code.co_name, str))
|
||||
|
||||
|
||||
def archive():
|
||||
from globals import OPTS
|
||||
try:
|
||||
OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME"))
|
||||
except:
|
||||
error("$OPENRAM_HOME is not properly defined.", 1)
|
||||
|
||||
import shutil
|
||||
zip_file = "{0}/{1}_{2}".format(OPENRAM_HOME, "fail_", os.getpid())
|
||||
info(0, "Archiving failed files to {}.zip".format(zip_file))
|
||||
shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
|
||||
|
||||
|
||||
def bp():
|
||||
"""
|
||||
An empty function so you can set soft breakpoints in pdb.
|
||||
|
|
|
|||
|
|
@ -61,8 +61,13 @@ def parse_args():
|
|||
optparse.make_option("-j", "--threads",
|
||||
action="store",
|
||||
type="int",
|
||||
help="Specify the number of threads (default: 2)",
|
||||
help="Specify the number of threads (default: 1)",
|
||||
dest="num_threads"),
|
||||
optparse.make_option("-m", "--sim_threads",
|
||||
action="store",
|
||||
type="int",
|
||||
help="Specify the number of spice simulation threads (default: 2)",
|
||||
dest="num_sim_threads"),
|
||||
optparse.make_option("-v",
|
||||
"--verbose",
|
||||
action="count",
|
||||
|
|
@ -381,6 +386,10 @@ def purge_temp():
|
|||
""" Remove the temp directory. """
|
||||
debug.info(1,
|
||||
"Purging temp directory: {}".format(OPTS.openram_temp))
|
||||
#import inspect
|
||||
#s = inspect.stack()
|
||||
#print("Purge {0} in dir {1}".format(s[3].filename, OPTS.openram_temp))
|
||||
|
||||
# This annoyingly means you have to re-cd into
|
||||
# the directory each debug iteration
|
||||
# shutil.rmtree(OPTS.openram_temp, ignore_errors=True)
|
||||
|
|
@ -429,9 +438,15 @@ def setup_paths():
|
|||
if "__pycache__" not in full_path:
|
||||
sys.path.append("{0}".format(full_path))
|
||||
|
||||
# Use a unique temp subdirectory
|
||||
OPTS.openram_temp += "/openram_{0}_{1}_temp/".format(getpass.getuser(),
|
||||
os.getpid())
|
||||
# Use a unique temp subdirectory if multithreaded
|
||||
if OPTS.num_threads > 1 or OPTS.openram_temp == "/tmp":
|
||||
|
||||
# Make a unique subdir
|
||||
tempdir = "/openram_{0}_{1}_temp".format(getpass.getuser(),
|
||||
os.getpid())
|
||||
# Only add the unique subdir one time
|
||||
if tempdir not in OPTS.openram_temp:
|
||||
OPTS.openram_temp += tempdir
|
||||
|
||||
if not OPTS.openram_temp.endswith('/'):
|
||||
OPTS.openram_temp += "/"
|
||||
|
|
@ -470,6 +485,12 @@ def init_paths():
|
|||
except OSError as e:
|
||||
if e.errno == 17: # errno.EEXIST
|
||||
os.chmod(OPTS.openram_temp, 0o750)
|
||||
#import inspect
|
||||
#s = inspect.stack()
|
||||
#from pprint import pprint
|
||||
#pprint(s)
|
||||
#print("Test {0} in dir {1}".format(s[2].filename, OPTS.openram_temp))
|
||||
|
||||
|
||||
# Don't delete the output dir, it may have other files!
|
||||
# make the directory if it doesn't exist
|
||||
|
|
|
|||
|
|
@ -526,13 +526,16 @@ class bank(design.design):
|
|||
height=self.dff.height)
|
||||
elif self.col_addr_size == 2:
|
||||
self.column_decoder = factory.create(module_type="hierarchical_predecode2x4",
|
||||
column_decoder=True,
|
||||
height=self.dff.height)
|
||||
|
||||
elif self.col_addr_size == 3:
|
||||
self.column_decoder = factory.create(module_type="hierarchical_predecode3x8",
|
||||
column_decoder=True,
|
||||
height=self.dff.height)
|
||||
elif self.col_addr_size == 4:
|
||||
self.column_decoder = factory.create(module_type="hierarchical_predecode4x16",
|
||||
column_decoder=True,
|
||||
height=self.dff.height)
|
||||
else:
|
||||
# No error checking before?
|
||||
|
|
|
|||
|
|
@ -18,19 +18,17 @@ class hierarchical_predecode(design.design):
|
|||
"""
|
||||
Pre 2x4 and 3x8 and TBD 4x16 decoder shared code.
|
||||
"""
|
||||
def __init__(self, name, input_number, height=None):
|
||||
def __init__(self, name, input_number, column_decoder=False, height=None):
|
||||
self.number_of_inputs = input_number
|
||||
|
||||
b = factory.create(module_type=OPTS.bitcell)
|
||||
|
||||
if not height:
|
||||
self.cell_height = b.height
|
||||
self.column_decoder = False
|
||||
else:
|
||||
self.cell_height = height
|
||||
# If we are pitch matched to the bitcell, it's a predecoder
|
||||
# otherwise it's a column decoder (out of pgates)
|
||||
self.column_decoder = (height != b.height)
|
||||
|
||||
self.column_decoder = column_decoder
|
||||
|
||||
self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
|
||||
super().__init__(name)
|
||||
|
|
@ -87,8 +85,15 @@ class hierarchical_predecode(design.design):
|
|||
|
||||
self.bus_layer = layer_props.hierarchical_predecode.bus_layer
|
||||
self.bus_directions = layer_props.hierarchical_predecode.bus_directions
|
||||
self.bus_pitch = getattr(self, self.bus_layer + "_pitch")
|
||||
self.bus_space = layer_props.hierarchical_predecode.bus_space_factor * getattr(self, self.bus_layer + "_space")
|
||||
|
||||
if self.column_decoder:
|
||||
# Column decoders may be routed on M2/M3 if there's a write mask
|
||||
self.bus_pitch = self.m3_pitch
|
||||
self.bus_space = self.m3_space
|
||||
else:
|
||||
self.bus_pitch = getattr(self, self.bus_layer + "_pitch")
|
||||
self.bus_space = getattr(self, self.bus_layer + "_space")
|
||||
self.bus_space = layer_props.hierarchical_predecode.bus_space_factor * self.bus_space
|
||||
self.input_layer = layer_props.hierarchical_predecode.input_layer
|
||||
self.output_layer = layer_props.hierarchical_predecode.output_layer
|
||||
self.output_layer_pitch = getattr(self, self.output_layer + "_pitch")
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ class hierarchical_predecode2x4(hierarchical_predecode):
|
|||
"""
|
||||
Pre 2x4 decoder used in hierarchical_decoder.
|
||||
"""
|
||||
def __init__(self, name, height=None):
|
||||
super().__init__( name, 2, height)
|
||||
def __init__(self, name, column_decoder=False, height=None):
|
||||
super().__init__(name, 2, column_decoder, height)
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
|||
"""
|
||||
Pre 3x8 decoder used in hierarchical_decoder.
|
||||
"""
|
||||
def __init__(self, name, height=None):
|
||||
super().__init__(name, 3, height)
|
||||
def __init__(self, name, column_decoder=False, height=None):
|
||||
super().__init__(name, 3, column_decoder, height)
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ class hierarchical_predecode4x16(hierarchical_predecode):
|
|||
"""
|
||||
Pre 4x16 decoder used in hierarchical_decoder.
|
||||
"""
|
||||
def __init__(self, name, height=None):
|
||||
super().__init__(name, 4, height)
|
||||
def __init__(self, name, column_decoder=False, height=None):
|
||||
super().__init__(name, 4, column_decoder, height)
|
||||
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ class options(optparse.Values):
|
|||
magic_exe = None
|
||||
|
||||
# Number of threads to use
|
||||
num_threads = 2
|
||||
num_threads = 1
|
||||
# Number of threads to use in ngspice/hspice
|
||||
num_sim_threads = 2
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import sys, os
|
|||
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
|
||||
class timing_setup_test(openram_test):
|
||||
|
||||
|
|
@ -29,14 +28,12 @@ class timing_setup_test(openram_test):
|
|||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import setup_hold
|
||||
import sram
|
||||
import tech
|
||||
slews = [tech.spice["rise_time"]*2]
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
sh = setup_hold(corner)
|
||||
data = sh.analyze(slews,slews)
|
||||
#print data
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'hold_times_HL': [-0.0158691],
|
||||
'hold_times_LH': [-0.0158691],
|
||||
|
|
@ -47,6 +44,11 @@ class timing_setup_test(openram_test):
|
|||
'hold_times_LH': [-0.11718749999999999],
|
||||
'setup_times_HL': [0.16357419999999998],
|
||||
'setup_times_LH': [0.1757812]}
|
||||
elif OPTS.tech_name == "sky130":
|
||||
golden_data = {'hold_times_HL': [-0.05615234],
|
||||
'hold_times_LH': [-0.03173828],
|
||||
'setup_times_HL': [0.078125],
|
||||
'setup_times_LH': [0.1025391]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import sys, os
|
|||
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||
import globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
|
||||
class timing_setup_test(openram_test):
|
||||
|
||||
|
|
@ -29,14 +28,12 @@ class timing_setup_test(openram_test):
|
|||
import characterizer
|
||||
reload(characterizer)
|
||||
from characterizer import setup_hold
|
||||
import sram
|
||||
import tech
|
||||
slews = [tech.spice["rise_time"]*2]
|
||||
|
||||
corner = (OPTS.process_corners[0], OPTS.supply_voltages[0], OPTS.temperatures[0])
|
||||
sh = setup_hold(corner)
|
||||
data = sh.analyze(slews,slews)
|
||||
#print data
|
||||
if OPTS.tech_name == "freepdk45":
|
||||
golden_data = {'hold_times_HL': [-0.01586914],
|
||||
'hold_times_LH': [-0.01586914],
|
||||
|
|
@ -47,6 +44,11 @@ class timing_setup_test(openram_test):
|
|||
'hold_times_LH': [-0.1293945],
|
||||
'setup_times_HL': [0.1757812],
|
||||
'setup_times_LH': [0.1879883]}
|
||||
elif OPTS.tech_name == "sky130":
|
||||
golden_data = {'hold_times_HL': [-0.05615234],
|
||||
'hold_times_LH': [-0.03173828],
|
||||
'setup_times_HL': [0.078125],
|
||||
'setup_times_LH': [0.1025391]}
|
||||
else:
|
||||
self.assertTrue(False) # other techs fail
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ class openram_back_end_test(openram_test):
|
|||
if OPTS.tech_name:
|
||||
options += " -t {}".format(OPTS.tech_name)
|
||||
|
||||
if OPTS.num_threads:
|
||||
options += " -j {}".format(OPTS.num_threads)
|
||||
|
||||
# Always perform code coverage
|
||||
if OPTS.coverage == 0:
|
||||
debug.warning("Failed to find coverage installation. This can be installed with pip3 install coverage")
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ class openram_front_end_test(openram_test):
|
|||
if OPTS.tech_name:
|
||||
options += " -t {}".format(OPTS.tech_name)
|
||||
|
||||
if OPTS.num_threads:
|
||||
options += " -j {}".format(OPTS.num_threads)
|
||||
|
||||
# Always perform code coverage
|
||||
if OPTS.coverage == 0:
|
||||
debug.warning("Failed to find coverage installation. This can be installed with pip3 install coverage")
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import sys, os
|
|||
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||
import globals
|
||||
from subunit import ProtocolTestCase, TestProtocolClient
|
||||
from subunit.test_results import AutoTimingTestResultDecorator
|
||||
from testtools import ConcurrentTestSuite
|
||||
|
||||
(OPTS, args) = globals.parse_args()
|
||||
|
|
@ -71,7 +70,7 @@ def fork_tests(num_threads):
|
|||
stream = os.fdopen(c2pwrite, 'wb', 0)
|
||||
os.close(c2pread)
|
||||
sys.stdin.close()
|
||||
test_suite_result = AutoTimingTestResultDecorator(TestProtocolClient(stream))
|
||||
test_suite_result = TestProtocolClient(stream)
|
||||
test_suite.run(test_suite_result)
|
||||
except EBADF:
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ class openram_test(unittest.TestCase):
|
|||
result=verify.run_drc(w.name, tempgds, None)
|
||||
if result != 0:
|
||||
self.fail("DRC failed: {}".format(w.name))
|
||||
|
||||
if not OPTS.keep_temp:
|
||||
elif not OPTS.keep_temp:
|
||||
self.cleanup()
|
||||
|
||||
def local_check(self, a, final_verification=False):
|
||||
|
|
@ -74,10 +73,10 @@ class openram_test(unittest.TestCase):
|
|||
# shutil.make_archive(zip_file, 'zip', OPTS.openram_temp)
|
||||
self.fail("LVS mismatch: {}".format(a.name))
|
||||
|
||||
if lvs_result == 0 and drc_result == 0 and not OPTS.keep_temp:
|
||||
self.cleanup()
|
||||
# For debug...
|
||||
# import pdb; pdb.set_trace()
|
||||
if not OPTS.keep_temp:
|
||||
self.cleanup()
|
||||
|
||||
def run_pex(self, a, output=None):
|
||||
tempspice = "{}.sp".format(a.name)
|
||||
|
|
@ -104,6 +103,7 @@ class openram_test(unittest.TestCase):
|
|||
|
||||
def cleanup(self):
|
||||
""" Reset the duplicate checker and cleanup files. """
|
||||
|
||||
files = glob.glob(OPTS.openram_temp + '*')
|
||||
for f in files:
|
||||
# Only remove the files
|
||||
|
|
|
|||
Loading…
Reference in New Issue