Skip to content

Commit

Permalink
Refactor to better support extensions of VHDL configurations.
Browse files Browse the repository at this point in the history
  • Loading branch information
LarsAsplund committed Feb 5, 2022
1 parent 322424c commit 5e6ade4
Show file tree
Hide file tree
Showing 18 changed files with 170 additions and 67 deletions.
8 changes: 8 additions & 0 deletions docs/py/vunit.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ Test

.. autoclass:: vunit.ui.test.Test()

ConfigurationList
-----------------

.. autoclass:: vunit.ui.configuration.ConfigurationList()
:special-members: __iter__
:inherited-members:


Configuration
-------------

Expand Down
23 changes: 15 additions & 8 deletions examples/vhdl/vhdl_configuration/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,30 @@
# VHDL configurations are detected automatically and are treated as a special
# case of the broader VUnit configuration concept. As such the configuration
# can be extended beyond the capabilities of a pure VHDL configuration. For example,
# by adding a post_check function. The exception is generics since VHDL doesn't allow
# generics to be combined with configurations. Workarounds for this limitation can be
# found in the handling_generics_limitation directory
# by adding a pre_config or post_check function hooks. The exception is generics since VHDL
# doesn't allow generics to be combined with configurations.
# Workarounds for this limitation can be found in the handling_generics_limitation directory

# Get the VHDL-defined configurations from test or testbench objects using a pattern matching
# configurations of interest.
tb = lib.test_bench("tb_selecting_dut_with_vhdl_configuration")
configurations = tb.get_configs("dff_*")
configs = tb.get_configs("dff_*")

# Remember to run the run script with the -v flag to see the message from the dummy post_check
def post_check(output_path):
print("Running post-check")
def make_hook(msg):
def hook(output_path):
print(msg)

return True
return True

return hook

configurations.set_post_check(post_check)

configs.set_post_check(make_hook("Common post_check"))

# You can also loop over the matching configurations
for config in configs:
config.set_pre_config(make_hook(f"pre_config for {config.name}"))

# The testbenches in the handling_generics_limitation directory are examples of how the generics
# limitation of VHDL configurations can be worked around. This allow us to create configurations
Expand Down
7 changes: 6 additions & 1 deletion tests/acceptance/artificial/vhdl/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ def post_check(output_path):
tb = ui.library("lib").test_bench("tb_with_vhdl_configuration")
tb.get_configs("cfg*").set_post_check(make_post_check("arch1"))
tb.test("test1").get_configs("cfg2").set_post_check(make_post_check("arch2"))
tb.test("test2").get_configs("cfg2").set_post_check(make_post_check("arch2"))
for config in tb.test("test2").get_configs():
if config.name == "cfg2":
config.set_post_check(make_post_check("arch2"))
tb.test("test1").delete_config("cfg1")
tb.add_config("foo")
tb.delete_config("foo")


configure_tb_with_generic_config()
Expand Down
4 changes: 0 additions & 4 deletions tests/acceptance/test_artificial.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,6 @@ def test_exit_0_flag(self):
"failed",
"lib.tb_assert_stop_level.Report failure when VHDL assert stop level = failure",
),
(
"passed",
"lib.tb_with_vhdl_configuration.cfg1.test1",
),
(
"passed",
"lib.tb_with_vhdl_configuration.cfg1.test2",
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ def test_error_on_setting_illegal_value_sim_option(self):
self.assertRaises(ValueError, config.set_sim_option, "vhdl_assert_stop_level", "illegal")

def test_error_on_both_generics_and_vhdl_configuration(self):
with _create_config(vhdl_configuration_name="cfg") as config:
with _create_config(vhdl_config_name="cfg") as config:
self.assertRaises(GenericAndVHDLConfigurationException, config.set_generic, "foo", "bar")

with _create_config(generics=dict(foo=17)) as config:
self.assertRaises(GenericAndVHDLConfigurationException, config.set_vhdl_configuration_name, "bar")
self.assertRaises(GenericAndVHDLConfigurationException, config.set_vhdl_config_name, "bar")

def test_sim_option_is_not_mutated(self):
with _create_config() as config:
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_incisive_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ def test_configuration_and_entity_selection(self, find_cds_root_irun, find_cds_r
with create_tempdir() as tempdir:
design_unit = Entity("tb_entity", file_name=str(Path(tempdir) / "file.vhd"))
design_unit.generic_names = ["runner_cfg"]
config = Configuration("name", design_unit, vhdl_configuration_name="cfg")
config = Configuration("name", design_unit, vhdl_config_name="cfg")
simif = IncisiveInterface(prefix="prefix", output_path=self.output_path)
self.assertEqual(simif._select_vhdl_top(config), "cfg") # pylint: disable=protected-access
config = Configuration("name", design_unit)
Expand Down Expand Up @@ -1002,5 +1002,5 @@ def make_config(sim_options=None, generics=None, verilog=False):

cfg.sim_options = {} if sim_options is None else sim_options
cfg.generics = {} if generics is None else generics
cfg.vhdl_configuration_name = None
cfg.vhdl_config_name = None
return cfg
2 changes: 1 addition & 1 deletion tests/unit/test_test_suites.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def get_simulator_output_path(self, output_path):

for expect_runner_cfg_generic in [False, True]:
config = Configuration(
"name", design_unit, vhdl_configuration_name=None if expect_runner_cfg_generic else "cfg"
"name", design_unit, vhdl_config_name=None if expect_runner_cfg_generic else "cfg"
)
sim_if = TestSimIf(output_path, gui=False, expect_runner_cfg_generic=expect_runner_cfg_generic)

Expand Down
53 changes: 39 additions & 14 deletions vunit/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ def __init__( # pylint: disable=too-many-arguments
pre_config=None,
post_check=None,
attributes=None,
vhdl_configuration_name=None,
vhdl_config_name=None,
):
self.name = name
self._design_unit = design_unit
self.generics = {} if generics is None else generics
self.sim_options = {} if sim_options is None else sim_options
self.attributes = {} if attributes is None else attributes
self.vhdl_configuration_name = vhdl_configuration_name
self.vhdl_config_name = vhdl_config_name

self.tb_path = str(Path(design_unit.original_file_name).parent)

Expand All @@ -70,7 +70,7 @@ def copy(self):
pre_config=self.pre_config,
post_check=self.post_check,
attributes=self.attributes.copy(),
vhdl_configuration_name=self.vhdl_configuration_name,
vhdl_config_name=self.vhdl_config_name,
)

@property
Expand Down Expand Up @@ -109,20 +109,20 @@ def set_attribute(self, name, value):
else:
raise AttributeException

def set_vhdl_configuration_name(self, name):
def set_vhdl_config_name(self, name):
"""
Set VHDL configuration name
"""
if self.generics:
raise GenericAndVHDLConfigurationException("Generics can't be used with VHDL configurations.")

self.vhdl_configuration_name = name
self.vhdl_config_name = name

def set_generic(self, name, value):
"""
Set generic
"""
if self.vhdl_configuration_name:
if self.vhdl_config_name:
raise GenericAndVHDLConfigurationException("Generics can't be used with VHDL configurations.")
if name not in self._design_unit.generic_names:
LOGGER.warning(
Expand Down Expand Up @@ -210,7 +210,10 @@ def get_configuration_dicts():

def set_attribute(self, name, value):
"""
Set attribute
Set attribute.
:param name: Attribute name.
:param value: Attribute value.
"""
self._check_enabled()
for configs in self.get_configuration_dicts():
Expand All @@ -219,7 +222,10 @@ def set_attribute(self, name, value):

def set_generic(self, name, value):
"""
Set generic
Set generic.
:param name: Generic name.
:param value: Generic value.
"""
self._check_enabled()
for configs in self.get_configuration_dicts():
Expand All @@ -228,8 +234,10 @@ def set_generic(self, name, value):

def set_sim_option(self, name, value, overwrite=True):
"""
Set sim option
Set simulation option
:param name: Simulation option name.
:param value: Simulation option value.
:param overwrite: To overwrite the option or append to the existing value
"""
self._check_enabled()
Expand All @@ -243,6 +251,8 @@ def set_sim_option(self, name, value, overwrite=True):
def set_pre_config(self, value):
"""
Set pre_config function
:param value: pre_config function.
"""
self._check_enabled()
for configs in self.get_configuration_dicts():
Expand All @@ -252,6 +262,8 @@ def set_pre_config(self, value):
def set_post_check(self, value):
"""
Set post_check function
:param value: post_check function.
"""
self._check_enabled()
for configs in self.get_configuration_dicts():
Expand All @@ -266,10 +278,10 @@ def add_config( # pylint: disable=too-many-arguments, too-many-branches
post_check=None,
sim_options=None,
attributes=None,
vhdl_configuration_name=None,
vhdl_config_name=None,
):
"""
Add a configuration copying unset fields from the default configuration:
Add a configuration copying unset fields from the default configuration.
"""
self._check_enabled()

Expand All @@ -291,7 +303,7 @@ def add_config( # pylint: disable=too-many-arguments, too-many-branches
config.post_check = post_check

if generics is not None:
if config.vhdl_configuration_name:
if config.vhdl_config_name:
raise GenericAndVHDLConfigurationException
config.generics.update(generics)

Expand All @@ -304,9 +316,22 @@ def add_config( # pylint: disable=too-many-arguments, too-many-branches
raise AttributeException
config.attributes.update(attributes)

if vhdl_configuration_name is not None:
if vhdl_config_name is not None:
if config.generics:
raise GenericAndVHDLConfigurationException
config.vhdl_configuration_name = vhdl_configuration_name
config.vhdl_config_name = vhdl_config_name

configs[config.name] = config

def delete_config(self, name):
"""
Delete a configuration.
"""
found_config = False
for configs in self.get_configuration_dicts():
if name in configs:
found_config = True
del configs[name]

if not found_config:
raise RuntimeError(f"Configuration name {name!s} not defined")
4 changes: 2 additions & 2 deletions vunit/sim_if/activehdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,12 +238,12 @@ def _create_load_function(self, config, output_path):
config.library_name,
]

if config.vhdl_configuration_name is None:
if config.vhdl_config_name is None:
vsim_flags.append(config.entity_name)
if config.architecture_name is not None:
vsim_flags.append(config.architecture_name)
else:
vsim_flags.append(config.vhdl_configuration_name)
vsim_flags.append(config.vhdl_config_name)

if config.sim_options.get("enable_coverage", False):
coverage_file_path = str(Path(output_path) / "coverage.acdb")
Expand Down
4 changes: 2 additions & 2 deletions vunit/sim_if/ghdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ def _get_command(self, config, output_path, elaborate_only, ghdl_e, wave_file):
# Enable coverage in linker
cmd += ["-Wl,-lgcov"]

if config.vhdl_configuration_name is not None:
cmd += [config.vhdl_configuration_name]
if config.vhdl_config_name is not None:
cmd += [config.vhdl_config_name]
else:
cmd += [config.entity_name, config.architecture_name]

Expand Down
4 changes: 2 additions & 2 deletions vunit/sim_if/incisive.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,10 @@ def _get_mapped_libraries(self):
@staticmethod
def _select_vhdl_top(config):
"Select VHDL configuration or entity as top."
if config.vhdl_configuration_name is None:
if config.vhdl_config_name is None:
return f"{config.library_name!s}.{config.entity_name!s}:{config.architecture_name!s}"

return f"{config.vhdl_configuration_name!s}"
return f"{config.vhdl_config_name!s}"

def simulate(
self, output_path, test_suite_name, config, elaborate_only=False
Expand Down
4 changes: 2 additions & 2 deletions vunit/sim_if/modelsim.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ def _create_load_function(self, test_suite_name, config, output_path):

simulation_target = (
config.library_name + "." + config.entity_name + architecture_suffix
if config.vhdl_configuration_name is None
else config.library_name + "." + config.vhdl_configuration_name
if config.vhdl_config_name is None
else config.library_name + "." + config.vhdl_config_name
)

vsim_flags = [
Expand Down
4 changes: 2 additions & 2 deletions vunit/sim_if/rivierapro.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,15 +301,15 @@ def _create_load_function(self, test_suite_name, config, output_path): # pylint

vsim_flags += ["-lib", config.library_name]

if config.vhdl_configuration_name is None:
if config.vhdl_config_name is None:
# Add the the testbench top-level unit last as coverage is
# only collected for the top-level unit specified last
vsim_flags += [config.entity_name]

if config.architecture_name is not None:
vsim_flags.append(config.architecture_name)
else:
vsim_flags += [config.vhdl_configuration_name]
vsim_flags += [config.vhdl_config_name]

tcl = """
proc vunit_load {{}} {{
Expand Down
4 changes: 2 additions & 2 deletions vunit/test/bench_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def add_from_source_file(self, source_file):

self._vhdl_configurations[design_unit.name]["test_bench"] = test_bench
for configuration in self._vhdl_configurations[design_unit.name]["configurations"]:
test_bench.add_config(name=configuration, vhdl_configuration_name=configuration)
test_bench.add_config(name=configuration, vhdl_config_name=configuration)

if design_unit.is_vhdl_configuration:
if design_unit.entity_name not in self._vhdl_configurations:
Expand All @@ -51,7 +51,7 @@ def add_from_source_file(self, source_file):
self._vhdl_configurations[design_unit.entity_name]["configurations"].append(design_unit.name)
if self._vhdl_configurations[design_unit.entity_name]["test_bench"]:
self._vhdl_configurations[design_unit.entity_name]["test_bench"].add_config(
name=design_unit.name, vhdl_configuration_name=design_unit.name
name=design_unit.name, vhdl_config_name=design_unit.name
)

def _add_test_bench(self, test_bench):
Expand Down
2 changes: 1 addition & 1 deletion vunit/test/suites.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def _simulate(self, output_path):
}

simulator_output_path = self._simulator_if.get_simulator_output_path(output_path) / "runner.cfg"
if config.vhdl_configuration_name is not None:
if config.vhdl_config_name is not None:
simulator_output_path.parent.mkdir(parents=True, exist_ok=True)
simulator_output_path.write_text(encode_dict(runner_cfg))
else:
Expand Down
Loading

0 comments on commit 5e6ade4

Please sign in to comment.