Skip to content

Commit bc01d74

Browse files
committed
Added support for Questa 3-step flow. Related to #899.
1 parent 51365a5 commit bc01d74

File tree

7 files changed

+423
-29
lines changed

7 files changed

+423
-29
lines changed

docs/news.d/899.feature.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[Questa/Modelsim] Added support for 3-step flow which is enabled by setting the
2+
simulation option ``modelsim.three_step_flow`` to ``True``. Extra flags to the ``vopt``
3+
step can be provided with the simulation flags ``modelsim.vopt_flags`` and
4+
``modelsim.vopt_flags.gui`` in normal and GUI mode, respectively.

docs/py/opts.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,19 @@ The following simulation options are known.
140140
Additionally, the ``vunit_tb_name`` variable is defined as the name of the test bench.
141141
Must be a string.
142142

143+
``modelsim.three_step_flow``
144+
Enable 3-step flow where a separate ``vopt`` step is executed before ``vsim`` is called.
145+
Must be a boolean value. Default is False.
146+
147+
``modelsim.vopt_flags``
148+
Extra arguments passed to ``vopt`` when ``modelsim.three_step_flow`` is ``True``.
149+
Must be a list of strings.
150+
151+
``modelsim.vsim_flags.gui``
152+
Extra arguments passed to ``vopt`` when ``modelsim.three_step_flow`` is ``True`` and
153+
GUI mode is enabled. Takes precedence over ``modelsim.vopt_flags``. Must be a list of
154+
strings.
155+
143156
``rivierapro.vsim_flags``
144157
Extra arguments passed to ``vsim`` when loading the design.
145158
Must be a list of strings.

tests/unit/test_modelsim_interface.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from vunit.sim_if.modelsim import ModelSimInterface
1919
from vunit.project import Project
2020
from vunit.ostools import renew_path, write_file
21+
from vunit.test.bench import Configuration
2122
from vunit.vhdl_standard import VHDL
2223

2324

@@ -316,14 +317,60 @@ def test_overwrites_modelsim_ini_file_from_user(self):
316317
with open(modelsim_ini, "r") as fptr:
317318
self.assertEqual(fptr.read(), "user")
318319

320+
@mock.patch("vunit.sim_if.modelsim.LOGGER", autospec=True)
321+
@mock.patch("vunit.sim_if.check_output", autospec=True, return_value="")
322+
@mock.patch("vunit.sim_if.modelsim.Process", autospec=True)
323+
@mock.patch("vunit.sim_if.vsim_simulator_mixin.Process", autospec=True)
324+
def test_optimize(self, vsim_simulator_mixin_process, modelsim_process, check_output, LOGGER):
325+
simif = ModelSimInterface(prefix=self.prefix_path, output_path=self.output_path, persistent=False)
326+
project = Project()
327+
project.add_library("lib", str(Path(self.libraries_path) / "lib"))
328+
write_file("file.vhd", "")
329+
project.add_source_file("file.vhd", "lib", file_type="vhdl", vhdl_standard=VHDL.standard("2008"))
330+
simif.compile_project(project)
331+
config = make_config(sim_options={"modelsim.three_step_flow":True})
332+
333+
# First call should optimize design
334+
simif.simulate(self.simulation_output_path, "test_suite_name", config, False)
335+
design_to_optimize = "lib.tb(test)"
336+
expected_calls = [
337+
mock.call("%s scheduled for optimization.", design_to_optimize),
338+
mock.call("Acquired library lock for %s to optimize %s.", "lib", design_to_optimize),
339+
mock.call("Optimizing %s.", design_to_optimize),
340+
mock.call("%s optimization completed.", design_to_optimize),
341+
]
342+
self.assertEqual(LOGGER.debug.call_count, len(expected_calls))
343+
LOGGER.debug.assert_has_calls(expected_calls)
344+
345+
# Second call should reuse the already optimized design
346+
LOGGER.reset_mock()
347+
simif.simulate(self.simulation_output_path, "test_suite_name", config, False)
348+
LOGGER.debug.assert_called_once_with("Reusing optimized %s.", "lib.tb(test)")
349+
350+
# Fake that design is being optimized and that it is being waited for
351+
LOGGER.reset_mock()
352+
simif._optimized_designs[design_to_optimize]["optimized_design"] = None
353+
simif.simulate(self.simulation_output_path, "test_suite_name", config, False)
354+
expected_calls = [
355+
mock.call("Waiting for %s to be optimized.", design_to_optimize),
356+
mock.call("Done waiting for %s to be optimized.", design_to_optimize),
357+
]
358+
self.assertEqual(LOGGER.debug.call_count, len(expected_calls))
359+
LOGGER.debug.assert_has_calls(expected_calls)
360+
361+
319362
def setUp(self):
320363
self.test_path = str(Path(__file__).parent / "test_modelsim_out")
321364

322365
self.output_path = str(Path(self.test_path) / "modelsim")
323366
self.prefix_path = str(Path(self.test_path) / "prefix" / "bin")
367+
self.libraries_path = str(Path(self.output_path) / "libraries")
368+
self.simulation_output_path = str(Path(self.test_path) / "test_output" / "lib.tb")
324369
renew_path(self.test_path)
325370
renew_path(self.output_path)
326371
renew_path(self.prefix_path)
372+
renew_path(self.libraries_path)
373+
renew_path(self.simulation_output_path)
327374
installed_modelsim_ini = str(Path(self.prefix_path) / ".." / "modelsim.ini")
328375
write_file(installed_modelsim_ini, "[Library]")
329376
self.project = Project()
@@ -334,3 +381,23 @@ def tearDown(self):
334381
os.chdir(self.cwd)
335382
if Path(self.test_path).exists():
336383
rmtree(self.test_path)
384+
385+
def make_config(sim_options=None, generics=None, verilog=False):
386+
"""
387+
Utility to reduce boiler plate in tests
388+
"""
389+
cfg = mock.Mock(spec=Configuration)
390+
cfg.library_name = "lib"
391+
392+
if verilog:
393+
cfg.entity_name = "tb"
394+
cfg.architecture_name = None
395+
else:
396+
cfg.entity_name = "tb"
397+
cfg.architecture_name = "test"
398+
399+
cfg.sim_options = {} if sim_options is None else sim_options
400+
cfg.generics = {} if generics is None else generics
401+
cfg.vhdl_configuration_name = None
402+
cfg.vhdl_assert_stop_level = "error"
403+
return cfg

vunit/persistent_tcl_shell.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def read_var(self, varname):
7373
return consumer.var
7474

7575
def read_bool(self, varname):
76-
result = self.read_var(varname)
76+
result = self.read_var(varname).lower()
7777
assert result in ("true", "false")
7878
return result == "true"
7979

0 commit comments

Comments
 (0)