Commit e935c73e authored by Martin Jeřábek's avatar Martin Jeřábek

testfw: fix accumulating sim_options, extract common bits, cleanup

parent 27d09104
...@@ -27,7 +27,7 @@ setup_logging() ...@@ -27,7 +27,7 @@ setup_logging()
from . import vunit_ifc from . import vunit_ifc
from . import test_unit, test_sanity, test_feature, test_reference from . import test_unit, test_sanity, test_feature, test_reference
from vunit.ui import VUnit from vunit.ui import VUnit
from .test_common import add_common_sources, add_flags from .test_common import add_common_sources, get_compile_options
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
...@@ -150,7 +150,11 @@ def test(obj, *, config, strict, create_ghws, vunit_args): ...@@ -150,7 +150,11 @@ def test(obj, *, config, strict, create_ghws, vunit_args):
for t in tests: for t in tests:
t.add_sources() t.add_sources()
add_flags(ui, lib, build)
c = get_compile_options()
for k, v in c.items():
lib.set_compile_option(k, v)
conf_ok = [t.configure() for t in tests] conf_ok = [t.configure() for t in tests]
# check for unknown tests # check for unknown tests
...@@ -198,27 +202,3 @@ def vunit_run(ui, build, out_basename) -> int: ...@@ -198,27 +202,3 @@ def vunit_run(ui, build, out_basename) -> int:
f.write(c) f.write(c)
out.unlink() out.unlink()
return res return res
"""
+ vunit configurations
+ pass modelsim gui file via ui.set_sim_option("modelsim.init_file.gui", ...)
+ include the standard library files in ui.set_sim_option("modelsim.init_files.after_load", [...])
+ set TCOMP global variable
- allow preprocessed calls to log()
- use some log from vunit?
- use random from unit?
+ use per-test default configurations (with set tcl files etc.), different sanity configurations
x pass encoded composite generics (sanity test)
+ use watchdog - pass the time in config: test_runner_watchdog(runner, 10 ms);
- bash completion for files & tests:
- click._bashcompletion.get_choices -> extend the if to check if the given argument is an instance of XXX
and implement completion method for that instance. Complete test names.
- feature tests
- sanity - optimize bus delay shift registers
"""
...@@ -8,11 +8,13 @@ from jinja2 import Environment, PackageLoader ...@@ -8,11 +8,13 @@ from jinja2 import Environment, PackageLoader
from pprint import pprint from pprint import pprint
import random import random
from .gtkwave import tcl2gtkw from .gtkwave import tcl2gtkw
from typing import List from typing import List, Tuple
import copy
import re
__all__ = ['add_sources', 'add_common_sources', 'get_common_modelsim_init_files', __all__ = ['add_sources', 'add_common_sources',
'add_flags', 'dict_merge', 'vhdl_serialize', 'dump_sim_options', 'dict_merge', 'vhdl_serialize', 'dump_sim_options',
'TestsBase', 'get_seed'] 'TestsBase', 'get_seed', 'OptionsDict']
d = Path(abspath(__file__)).parent d = Path(abspath(__file__)).parent
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -20,6 +22,43 @@ log = logging.getLogger(__name__) ...@@ -20,6 +22,43 @@ log = logging.getLogger(__name__)
jinja_env = Environment(loader=PackageLoader(__package__, 'data'), autoescape=False) jinja_env = Environment(loader=PackageLoader(__package__, 'data'), autoescape=False)
class OptionsDict(dict):
# def __getattr__(self, key):
# return self[key]
def __iadd__(self, upper: dict):
self.__merge(self, upper)
return self
def __add__(self, upper: dict) -> 'OptionsDict':
res = copy.deepcopy(self)
res += upper
return res
def __radd__(self, lower: dict) -> 'OptionsDict':
res = copy.deepcopy(lower)
res += self
return res
@classmethod
def __merge(cls, lower, upper) -> None:
if isinstance(lower, OptionsDict):
if not isinstance(upper, OptionsDict):
raise TypeError('Cannot merge {} and {}'.format(type(lower), type('upper')))
for k, v in upper.items():
if k not in lower:
lower[k] = v
else:
cls.__merge(lower[k], v)
elif isinstance(lower, list):
if not isinstance(upper, list):
raise TypeError('Cannot merge {} and {}'.format(type(lower), type('upper')))
lower.extend(upper)
else:
raise TypeError('Cannot merge {} and {}'.format(type(lower), type('upper')))
class TestsBase: class TestsBase:
def __init__(self, ui, lib, config, build, base, create_ghws: bool): def __init__(self, ui, lib, config, build, base, create_ghws: bool):
self.ui = ui self.ui = ui
...@@ -43,9 +82,18 @@ class TestsBase: ...@@ -43,9 +82,18 @@ class TestsBase:
raise NotImplementedError() raise NotImplementedError()
def add_modelsim_gui_file(self, tb, cfg, name, tcl_init_files: List[str] = None) -> None: def generate_init_tcl(self, fname: str, tcomp: str) -> OptionsDict:
if tcl_init_files is None: tcl = self.build / fname
tcl_init_files = get_common_modelsim_init_files() with tcl.open('wt', encoding='utf-8') as f:
print(dedent('''\
global TCOMP
set TCOMP {}
'''.format(tcomp)), file=f)
return OptionsDict({"modelsim.init_files.after_load": [str(tcl)]})
def add_modelsim_gui_file(self, tb, cfg, name, tcl_init_files: List[str]) -> OptionsDict:
"""Return sim_options to add to the testcase."""
sim_options = OptionsDict({'ghdl.sim_flags': []})
if 'wave' in cfg: if 'wave' in cfg:
tcl = self.base / cfg['wave'] tcl = self.base / cfg['wave']
if not tcl.exists(): if not tcl.exists():
...@@ -65,7 +113,7 @@ class TestsBase: ...@@ -65,7 +113,7 @@ class TestsBase:
get_test_results get_test_results
'''.format(name)), file=f) '''.format(name)), file=f)
tb.set_sim_option("modelsim.init_file.gui", str(tcl)) sim_options["modelsim.init_file.gui"] = str(tcl)
if 'gtkw' in cfg: if 'gtkw' in cfg:
gtkw = self.base / cfg['gtkw'] gtkw = self.base / cfg['gtkw']
if not gtkw.exists(): if not gtkw.exists():
...@@ -79,9 +127,7 @@ class TestsBase: ...@@ -79,9 +127,7 @@ class TestsBase:
# the conversion now. # the conversion now.
if self.create_ghws: if self.create_ghws:
log.info('Will generate {}'.format(ghw_file)) log.info('Will generate {}'.format(ghw_file))
sim_flags = get_common_sim_flags() sim_options["ghdl.sim_flags"] += ['--wave=' + str(ghw_file)]
sim_flags += ['--wave=' + str(ghw_file)]
tb.set_sim_option("ghdl.sim_flags", sim_flags)
else: else:
if not ghw_file.exists(): if not ghw_file.exists():
log.warning("Cannot convert wave file {} to gtkw, because" log.warning("Cannot convert wave file {} to gtkw, because"
...@@ -94,12 +140,32 @@ class TestsBase: ...@@ -94,12 +140,32 @@ class TestsBase:
if gtkw: if gtkw:
try: try:
tb.set_sim_option("ghdl.gtkwave_flags", ['--save='+str(gtkw)]) tb.set_sim_option("ghdl.gtkwave_flags", [])
sim_options["ghdl.gtkwave_flags"] = ['--save='+str(gtkw)]
except ValueError: except ValueError:
try: try:
tb.set_sim_option("ghdl.gtkw_file", str(gtkw)) tb.set_sim_option("ghdl.gtkw_file", "")
sim_options["ghdl.gtkw_file"] = str(gtkw)
except ValueError: except ValueError:
log.warning('Setting GTKW file per test is not supported in this VUnit version.') log.warning('Setting GTKW file per test is not supported in this VUnit version.')
return OptionsDict(sim_options)
def get_default_sim_options(self) -> OptionsDict:
c, s = get_default_compile_and_sim_options()
return s
def add_psl_cov(self, name) -> OptionsDict:
name = re.sub(r'[^a-zA-Z0-9_-]', '_', name)
psl_path = self.build / "functional_coverage" / "coverage_data" \
/ "psl_cov_{}.json".format(name)
sim_flags = ["--psl-report={}".format(psl_path)]
return OptionsDict({"ghdl.sim_flags": sim_flags})
@staticmethod
def set_sim_options(tb, options: OptionsDict) -> None:
for k, v in options.items():
tb.set_sim_option(k, v)
def add_sources(lib, patterns) -> None: def add_sources(lib, patterns) -> None:
for pattern in patterns: for pattern in patterns:
...@@ -109,6 +175,7 @@ def add_sources(lib, patterns) -> None: ...@@ -109,6 +175,7 @@ def add_sources(lib, patterns) -> None:
if f != "tb_wrappers.vhd": if f != "tb_wrappers.vhd":
lib.add_source_file(str(f)) lib.add_source_file(str(f))
def add_common_sources(lib, ui) -> None: def add_common_sources(lib, ui) -> None:
add_sources(lib, ['../src/**/*.vhd']) add_sources(lib, ['../src/**/*.vhd'])
ui.enable_check_preprocessing() ui.enable_check_preprocessing()
...@@ -116,38 +183,41 @@ def add_common_sources(lib, ui) -> None: ...@@ -116,38 +183,41 @@ def add_common_sources(lib, ui) -> None:
add_sources(lib, ['*.vhd', 'lib/*.vhd', 'models/*.vhd']) add_sources(lib, ['*.vhd', 'lib/*.vhd', 'models/*.vhd'])
def get_common_modelsim_init_files() -> List[str]: def get_default_compile_and_sim_options() -> Tuple[OptionsDict, OptionsDict]:
modelsim_init_files = ['../lib/test_lib.tcl', 'modelsim_init.tcl'] # TODO: move to config
modelsim_init_files = [str(d/x) for x in modelsim_init_files] debug = True
return modelsim_init_files coverage = True
psl = True
def get_common_sim_flags() -> List[str]:
return ["--ieee-asserts=disable-at-0"] compile_flags = [] # type: List[str]
elab_flags = ["-Wl,-no-pie"]
def add_flags(ui, lib, build) -> None:
unit_tests = lib.get_test_benches('*_unit_test', allow_empty=True) if debug:
for ut in unit_tests: compile_flags += ['-g']
ut.scan_tests_from_file(str(build / "../unit/vunittb_wrapper.vhd")) elab_flags += ['-g']
if coverage:
reference_tests = lib.get_test_benches('*reference*', allow_empty=True) compile_flags += ["-fprofile-arcs", "-ftest-coverage"]
for rt in reference_tests: elab_flags += ["-Wl,-lgcov", "-Wl,--coverage"]
rt.scan_tests_from_file(str(build / "../reference/vunit_reference_wrapper.vhd")) if psl:
compile_flags += ['-fpsl']
#lib.add_compile_option("ghdl.flags", ["-Wc,-g"]) elab_flags += ['-fpsl']
lib.add_compile_option("ghdl.flags", ["-fprofile-arcs", "-ftest-coverage", "-fpsl", "-g"])
compile_options = OptionsDict()
elab_flags = ["-Wl,-lgcov", "-g"] compile_options["ghdl.flags"] = compile_flags
elab_flags.append("-Wl,--coverage")
elab_flags.append("-Wl,-no-pie") cmif = ['../lib/test_lib.tcl', 'modelsim_init.tcl']
elab_flags.append("-fpsl") common_modelsim_init_files = [str(d/x) for x in cmif]
ui.set_sim_option("ghdl.elab_flags", elab_flags) sim_options = OptionsDict({
"ghdl.elab_flags": elab_flags,
# Global simulation flags "modelsim.init_files.after_load": common_modelsim_init_files,
sim_flags = get_common_sim_flags() "ghdl.sim_flags": ["--ieee-asserts=disable-at-0"],
ui.set_sim_option("ghdl.sim_flags", sim_flags) })
return compile_options, sim_options
modelsim_init_files = get_common_modelsim_init_files()
ui.set_sim_option("modelsim.init_files.after_load", modelsim_init_files)
def get_compile_options() -> OptionsDict:
c, s = get_default_compile_and_sim_options()
return c
def get_seed(cfg) -> int: def get_seed(cfg) -> int:
......
import logging import logging
from pathlib import Path from pathlib import Path
from .test_common import add_sources, TestsBase, dict_merge, \ from .test_common import add_sources, TestsBase, dict_merge, \
get_common_modelsim_init_files, get_seed get_seed, OptionsDict
from textwrap import dedent from textwrap import dedent
import re import re
...@@ -26,25 +26,14 @@ class FeatureTests(TestsBase): ...@@ -26,25 +26,14 @@ class FeatureTests(TestsBase):
tb = self.lib.get_test_benches('*tb_feature')[0] tb = self.lib.get_test_benches('*tb_feature')[0]
tb.scan_tests_from_file(str(wrname)) tb.scan_tests_from_file(str(wrname))
def create_psl_cov_file_opt(self, name):
psl_path = "functional_coverage/coverage_data/psl_cov_feature_{}.json".format(name)
psl_flag = "--psl-report={}".format(psl_path)
return {"ghdl.sim_flags" : [psl_flag]}
def configure(self) -> bool: def configure(self) -> bool:
tb = self.lib.get_test_benches('*tb_feature')[0] tb = self.lib.get_test_benches('*tb_feature')[0]
default = self.config['default'] default = self.config['default']
sim_options = self.get_default_sim_options()
# generate & set per-test modelsim tcl file # generate & set per-test modelsim tcl file
tcl = self.build / 'modelsim_init_feature.tcl' sim_options += self.generate_init_tcl('modelsim_init_feature.tcl', 'tb_feature/test_comp')
with tcl.open('wt', encoding='utf-8') as f: sim_options += self.add_modelsim_gui_file(tb, default, 'feature', sim_options['modelsim.init_files.after_load'])
print(dedent('''\
global TCOMP
set TCOMP tb_feature/test_comp
'''), file=f)
init_files = get_common_modelsim_init_files()
init_files += [str(tcl)]
tb.set_sim_option("modelsim.init_files.after_load", init_files)
for name, cfg in self.config['tests'].items(): for name, cfg in self.config['tests'].items():
if cfg is None: if cfg is None:
...@@ -64,12 +53,13 @@ class FeatureTests(TestsBase): ...@@ -64,12 +53,13 @@ class FeatureTests(TestsBase):
'seed' : get_seed(cfg) 'seed' : get_seed(cfg)
} }
if (cfg['psl_coverage']): local_sim_options = OptionsDict()
psl_opts = self.create_psl_cov_file_opt(name) if cfg['psl_coverage']:
tb.add_config(name, generics=generics, sim_options=psl_opts) local_sim_options += self.add_psl_cov('{}.{}'.format(tb.name, name))
else:
tb.add_config(name, generics=generics) local_sim_options = sim_options + local_sim_options
self.add_modelsim_gui_file(tb, default, 'feature', init_files) tb.add_config(name, generics=generics, sim_options=local_sim_options)
return self._check_for_unconfigured() return self._check_for_unconfigured()
def _check_for_unconfigured(self) -> bool: def _check_for_unconfigured(self) -> bool:
......
import logging import logging
from pathlib import Path from pathlib import Path
from .test_common import add_sources, TestsBase, dict_merge, \ from .test_common import add_sources, TestsBase, dict_merge, \
get_common_modelsim_init_files, get_seed get_seed, OptionsDict
from textwrap import dedent
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -18,28 +17,20 @@ class ReferenceTests(TestsBase): ...@@ -18,28 +17,20 @@ class ReferenceTests(TestsBase):
sources.append('reference/vunit_reference_wrapper.vhd') sources.append('reference/vunit_reference_wrapper.vhd')
add_sources(self.lib, sources) add_sources(self.lib, sources)
def create_psl_cov_file_opt(self, name):
psl_path = "functional_coverage/coverage_data/psl_cov_reference_{}.json".format(name)
psl_flag = "--psl-report={}".format(psl_path)
return {"ghdl.sim_flags" : [psl_flag]}
def configure(self) -> bool: def configure(self) -> bool:
tb = self.lib.get_test_benches('*reference*')[0] tb = self.lib.get_test_benches('*reference*')[0]
default = self.config['default'] default = self.config['default']
tcl = self.build / 'modelsim_init_reference.tcl' # TODO: is this necessary?
with tcl.open('wt', encoding='utf-8') as f: tb.scan_tests_from_file(str(self.base / "reference/vunit_reference_wrapper.vhd"))
print(dedent('''\
global TCOMP
set TCOMP tb_reference_wrapper/i_test
'''), file=f)
init_files = get_common_modelsim_init_files() sim_options = self.get_default_sim_options()
init_files += [str(tcl)] # generate & set per-test modelsim tcl file
sim_options += self.generate_init_tcl('modelsim_init_reference.tcl', 'tb_reference_wrapper/i_test')
sim_options += self.add_modelsim_gui_file(tb, default, 'reference', sim_options['modelsim.init_files.after_load'])
for data_set, cfg in self.config['tests'].items(): for data_set, cfg in self.config['tests'].items():
dict_merge(cfg, default) dict_merge(cfg, default)
# bm = len_to_matrix(cfg['topology'], cfg['bus_len_v'])
generics = { generics = {
'timeout' : cfg['timeout'], 'timeout' : cfg['timeout'],
'iterations' : cfg['iterations'], 'iterations' : cfg['iterations'],
...@@ -48,13 +39,10 @@ class ReferenceTests(TestsBase): ...@@ -48,13 +39,10 @@ class ReferenceTests(TestsBase):
'seed' : get_seed(cfg), 'seed' : get_seed(cfg),
'data_path' : str(self.build) + '/../' + cfg['data_path'], 'data_path' : str(self.build) + '/../' + cfg['data_path'],
} }
local_sim_options = OptionsDict()
if cfg['psl_coverage']:
local_sim_options += self.add_psl_cov('{}.{}'.format(tb.name, data_set))
local_sim_options = sim_options + local_sim_options
tb.add_config(data_set, generics=generics, sim_options=local_sim_options)
if (cfg['psl_coverage']):
psl_opts = self.create_psl_cov_file_opt(data_set)
tb.add_config(data_set, generics=generics, sim_options=psl_opts)
else:
tb.add_config(data_set, generics=generics)
tb.set_sim_option("modelsim.init_files.after_load", init_files)
self.add_modelsim_gui_file(tb, default, 'reference', init_files)
return True return True
import logging import logging
from textwrap import dedent from textwrap import dedent
from .test_common import TestsBase, add_sources, dict_merge, vhdl_serialize, \ from .test_common import TestsBase, add_sources, dict_merge, vhdl_serialize, \
get_seed, get_common_modelsim_init_files get_seed, OptionsDict
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def len_to_matrix(topology, bus_len):
l = bus_len
if topology == 'bus':
bm = [[0.0, l[1], l[1]+l[2], l[1]+l[2]+l[3]],
[l[1], 0.0, l[2], l[2]+l[3]],
[l[1]+l[2], l[2], 0.0, l[3]],
[l[1]+l[2]+l[3], l[2]+l[3], l[3], 0.0]]
elif topology == 'star':
bm = [[0.0, l[1]+l[2], l[1]+l[3], l[1]+l[4]],
[l[1]+l[2], 0.0, l[2]+l[3], l[2]+l[4]],
[l[1]+l[3], l[2]+l[3], 0.0, l[3]+l[4]],
[l[1]+l[4], l[2]+l[4], l[3]+l[4], 0.0]]
elif topology == 'tree':
bm = [[0.0, l[1]+l[2], l[1]+l[3]+l[5], l[1]+l[4]+l[5]],
[l[1]+l[2], 0.0, l[2]+l[3]+l[5], l[2]+l[4]+l[5]],
[l[1]+l[3]+l[5], l[2]+l[3]+l[5], 0.0, l[3]+l[4]],
[l[1]+l[4]+l[5], l[2]+l[4]+l[5], l[3]+l[4], 0.0]]
elif topology == 'ring':
bm = [[0.0, min(l[1], l[2]+l[3]+l[4]), min(l[1]+l[2],l[3]+l[4]), min(l[4],l[1]+l[2]+l[3])],
[min(l[1], l[2]+l[3]+l[4]), 0.0, min(l[2], l[1]+l[3]+l[4]), min(l[2]+l[3],l[1]+l[4])],
[min(l[1]+l[2],l[3]+l[4]), min(l[2], l[1]+l[3]+l[4]), 0.0, min(l[3],l[1]+l[2]+l[4])],
[min(l[4],l[1]+l[2]+l[3]), min(l[2]+l[3],l[1]+l[4]), min(l[3],l[1]+l[2]+l[4]), 0.0]]
elif topology == 'custom':
bm = [[0.0, l[1], l[2], l[3]],
[l[1], 0.0, l[4], l[5]],
[l[2], l[4], 0.0, l[6]],
[l[3], l[6], l[6], 0.0]]
else:
raise ValueError("Invalid bus topology.")
return bm
class SanityTests(TestsBase): class SanityTests(TestsBase):
def add_sources(self): def add_sources(self):
add_sources(self.lib, ['sanity/**/*.vhd']) add_sources(self.lib, ['sanity/**/*.vhd'])
...@@ -48,25 +15,14 @@ class SanityTests(TestsBase): ...@@ -48,25 +15,14 @@ class SanityTests(TestsBase):
valid_name = valid_name.replace("/", "_") valid_name = valid_name.replace("/", "_")
return valid_name return valid_name
def create_psl_cov_file_opt(self, name):
test_name = "psl_cov_sanity_{}.json".format(self.format_valid_test_name(name))
psl_path = "functional_coverage/coverage_data/{}".format(test_name)
psl_flag = "--psl-report={}".format(psl_path)
return {"ghdl.sim_flags" : [psl_flag]}
def configure(self): def configure(self):
tb = self.lib.get_test_benches('*tb_sanity')[0] tb = self.lib.get_test_benches('*tb_sanity')[0]
default = self.config['default'] default = self.config['default']
tcl = self.build / 'modelsim_init_sanity.tcl' sim_options = self.get_default_sim_options()
with tcl.open('wt', encoding='utf-8') as f: # generate & set per-test modelsim tcl file
print(dedent('''\ sim_options += self.generate_init_tcl('modelsim_init_sanity.tcl', 'tb_sanity')
global TCOMP sim_options += self.add_modelsim_gui_file(tb, default, 'sanity', sim_options['modelsim.init_files.after_load'])
set TCOMP tb_sanity
'''), file=f)
init_files = get_common_modelsim_init_files()
init_files += [str(tcl)]
for name, cfg in self.config['tests'].items(): for name, cfg in self.config['tests'].items():
if 'wave' in cfg: if 'wave' in cfg:
...@@ -74,7 +30,6 @@ class SanityTests(TestsBase): ...@@ -74,7 +30,6 @@ class SanityTests(TestsBase):
' (set it in default instead)'.format(name)) ' (set it in default instead)'.format(name))
dict_merge(cfg, default) dict_merge(cfg, default)
# bm = len_to_matrix(cfg['topology'], cfg['bus_len_v'])
generics = { generics = {
'timeout' : cfg['timeout'], 'timeout' : cfg['timeout'],
'iterations' : cfg['iterations'], 'iterations' : cfg['iterations'],
...@@ -94,13 +49,9 @@ class SanityTests(TestsBase): ...@@ -94,13 +49,9 @@ class SanityTests(TestsBase):
'gauss_iter' : vhdl_serialize(cfg['gauss_iter']), 'gauss_iter' : vhdl_serialize(cfg['gauss_iter']),
} }
sanity_cfg_name = name.replace(" ", "_").replace("/", "_").strip('"') local_sim_options = OptionsDict()
if cfg['psl_coverage']: if cfg['psl_coverage']:
psl_opts = self.create_psl_cov_file_opt(name) local_sim_options += self.add_psl_cov('{}.{}'.format(tb.name, name))
tb.add_config(name, generics=generics, sim_options=psl_opts) local_sim_options = sim_options + local_sim_options
else: tb.add_config(name, generics=generics, sim_options=local_sim_options)
tb.add_config(name, generics=generics)
self.add_modelsim_gui_file(tb, default, 'sanity', init_files)
return True return True
...@@ -2,7 +2,7 @@ import re ...@@ -2,7 +2,7 @@ import re
import logging import logging
from textwrap import dedent from textwrap import dedent
from .test_common import add_sources, dict_merge, TestsBase, \ from .test_common import add_sources, dict_merge, TestsBase, \
get_common_modelsim_init_files, get_seed get_seed, OptionsDict
from pprint import pprint from pprint import pprint
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -13,15 +13,14 @@ class UnitTests(TestsBase): ...@@ -13,15 +13,14 @@ class UnitTests(TestsBase):
add_sources(self.lib, ['unit/**/*.vhd']) add_sources(self.lib, ['unit/**/*.vhd'])
self._create_wrapper(self.build / "tb_wrappers.vhd") self._create_wrapper(self.build / "tb_wrappers.vhd")
def add_psl_cov_file(self, tb, name):
psl_path = "functional_coverage/coverage_data/psl_cov_unit_{}.json".format(name)
psl_flag = "--psl-report={}".format(psl_path)
tb.set_sim_option("ghdl.sim_flags", [psl_flag])
def configure(self) -> bool: def configure(self) -> bool:
lib, config, build = self.lib, self.config, self.build lib, config, build = self.lib, self.config, self.build
default = config['default'] default = config['default']
unit_tests = lib.get_test_benches('*_unit_test') unit_tests = lib.get_test_benches('*_unit_test')
for ut in unit_tests:
ut.scan_tests_from_file(str(build / "../unit/vunittb_wrapper.vhd"))
for name, cfg in config['tests'].items(): for name, cfg in config['tests'].items():
dict_merge(cfg, default) dict_merge(cfg, default)
tb = lib.get_test_benches('*tb_{}_unit_test'.format(name), tb = lib.get_test_benches('*tb_{}_unit_test'.format(name),
...@@ -39,19 +38,15 @@ class UnitTests(TestsBase): ...@@ -39,19 +38,15 @@ class UnitTests(TestsBase):
tb.set_generic('error_tol', cfg['error_tolerance']) tb.set_generic('error_tol', cfg['error_tolerance'])
tb.set_generic('seed', get_seed(cfg)) tb.set_generic('seed', get_seed(cfg))
sim_options = self.get_default_sim_options()
# generate & set per-test modelsim tcl file # generate & set per-test modelsim tcl file
tcl = build / 'modelsim_init_{}.tcl'.format(name) sim_options += self.generate_init_tcl('modelsim_init_{}.tcl'.format(name), 'tb_{}_unit_test/tb/i_test'.format(name))
with tcl.open('wt', encoding='utf-8') as f: sim_options += self.add_modelsim_gui_file(tb, cfg, name, sim_options['modelsim.init_files.after_load'])
print(dedent('''\
global TCOMP if cfg['psl_coverage']:
set TCOMP tb_{}_unit_test/tb/i_test sim_options += self.add_psl_cov(tb.name)
'''.format(name)), file=f) self.set_sim_options(tb, sim_options)
init_files = get_common_modelsim_init_files()
init_files += [str(tcl)]
tb.set_sim_option("modelsim.init_files.after_load", init_files)
if (cfg['psl_coverage']):
self.add_psl_cov_file(tb, name)
self.add_modelsim_gui_file(tb, cfg, name, tcl_init_files=init_files)
return self._check_for_unconfigured() return self._check_for_unconfigured()
def _check_for_unconfigured(self) -> bool: def _check_for_unconfigured(self) -> bool:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment