Skip to content

Commit 87e6bcc

Browse files
committed
Adds SimulatorFactory class
1 parent 82c3f1c commit 87e6bcc

7 files changed

Lines changed: 157 additions & 94 deletions

File tree

user_guide.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ cases.
3535
usage: run.py [-h] [-l] [--compile] [--elaborate] [--clean] [-o OUTPUT_PATH]
3636
[-x XUNIT_XML] [-v] [--no-color] [--gui {load,run}]
3737
[--log-level {info,error,warning,debug}]
38+
[--gui {load,run}] [--new-vsim]
3839
[tests [tests ...]]
3940
4041
VUnit command line tool.
@@ -60,6 +61,16 @@ optional arguments:
6061
and runs the test case while recursively logging all
6162
variables and signals
6263
--log-level {info,error,warning,debug}
64+
65+
modelsim:
66+
ModelSim specific flags
67+
68+
--gui {load,run} Open test case(s) in simulator gui. 'load' only loads
69+
the test case and gives the user control. 'run' loads
70+
and runs the test case while recursively logging all
71+
variables and signals
72+
--new-vsim Do not re-use the same vsim process for running
73+
different test cases (slower)
6374
```
6475

6576
## VHDL Test Benches

vunit/modelsim_interface.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,34 @@ class ModelSimInterface(object):
3434
"""
3535
name = "modelsim"
3636

37+
@staticmethod
38+
def add_arguments(parser):
39+
"""
40+
Add command line arguments
41+
"""
42+
group = parser.add_argument_group("modelsim",
43+
description="ModelSim specific flags")
44+
group.add_argument('--gui', choices=["load", "run"],
45+
default=None,
46+
help=("Open test case(s) in simulator gui. "
47+
"'load' only loads the test case and gives the user control. "
48+
"'run' loads and runs the test case while recursively "
49+
"logging all variables and signals"))
50+
group.add_argument("--new-vsim",
51+
action="store_true",
52+
default=False,
53+
help="Do not re-use the same vsim process for running different test cases (slower)")
54+
55+
@classmethod
56+
def from_args(cls, output_path, args):
57+
"""
58+
Create new instance from command line arguments object
59+
"""
60+
persistent = (not args.new_vsim) and args.gui is None
61+
return cls(join(output_path, "modelsim.ini"),
62+
persistent=persistent,
63+
gui_mode=args.gui)
64+
3765
@staticmethod
3866
def is_available():
3967
"""

vunit/simulator_factory.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
3+
# You can obtain one at http://mozilla.org/MPL/2.0/.
4+
#
5+
# Copyright (c) 2015, Lars Asplund lars.anders.asplund@gmail.com
6+
7+
"""
8+
Create simulator instances
9+
"""
10+
11+
from vunit.modelsim_interface import ModelSimInterface
12+
from os.path import join, exists
13+
import os
14+
15+
16+
class SimulatorFactory(object):
17+
"""
18+
Create simulator instances
19+
"""
20+
21+
@staticmethod
22+
def supported_simulators():
23+
"""
24+
Return a list of supported simulator classes
25+
"""
26+
return [ModelSimInterface]
27+
28+
@classmethod
29+
def available_simulators(cls):
30+
"""
31+
Return a list of available simulators
32+
"""
33+
return [simulator_class
34+
for simulator_class in cls.supported_simulators()
35+
if simulator_class.is_available()]
36+
37+
@classmethod
38+
def select_simulator(cls):
39+
"""
40+
Select simulator class, either from VUNIT_SIMULATOR environment variable
41+
or the first available
42+
"""
43+
environ_name = "VUNIT_SIMULATOR"
44+
45+
available_simulators = cls.available_simulators()
46+
name_mapping = {simulator_class.name: simulator_class for simulator_class in cls.supported_simulators()}
47+
if len(available_simulators) == 0:
48+
raise RuntimeError("No available simulator detected. "
49+
"Simulator executables must be available in PATH environment variable.")
50+
51+
if environ_name in os.environ:
52+
simulator_name = os.environ[environ_name]
53+
if simulator_name not in name_mapping:
54+
raise RuntimeError(
55+
("Simulator from " + environ_name + " environment variable %r is not supported. "
56+
"Supported simulators are %r")
57+
% (simulator_name, name_mapping.keys()))
58+
simulator_class = name_mapping[simulator_name]
59+
else:
60+
simulator_class = available_simulators[0]
61+
62+
return simulator_class
63+
64+
@classmethod
65+
def add_arguments(cls, parser):
66+
"""
67+
Add command line arguments to parser
68+
"""
69+
cls.select_simulator().add_arguments(parser)
70+
71+
def __init__(self, args):
72+
self._args = args
73+
self._output_path = args.output_path
74+
self._simulator_class = self.select_simulator()
75+
76+
@property
77+
def simulator_name(self):
78+
return self._simulator_class.name
79+
80+
@property
81+
def simulator_output_path(self):
82+
return join(self._output_path, self.simulator_name)
83+
84+
def create(self):
85+
"""
86+
Create new simulator instance
87+
"""
88+
if not exists(self.simulator_output_path):
89+
os.makedirs(self.simulator_output_path)
90+
91+
return self._simulator_class.from_args(self.simulator_output_path,
92+
self._args)

vunit/test/acceptance/test_artificial.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import unittest
1313
from os.path import join, dirname
14-
from vunit.test.common import has_simulator, check_report
14+
from vunit.test.common import has_simulator, check_report, simulator_is
1515
from os import environ
1616
from vunit import VUnit
1717
from subprocess import call
@@ -30,11 +30,12 @@ def setUp(self):
3030
self.report_file = join(self.output_path, "xunit.xml")
3131
self.artificial_run = join(dirname(__file__), "artificial", "run.py")
3232

33-
def test_artificial_with_persistent(self):
34-
self._test_artificial(persistent_sim=True)
33+
@unittest.skipUnless(simulator_is("modelsim"), "Only modelsim has --new-vsim flag")
34+
def test_artificial_modelsim_new_vsim(self):
35+
self._test_artificial(args=["--new-vsim"])
3536

3637
def test_artificial(self):
37-
self._test_artificial(persistent_sim=False)
38+
self._test_artificial()
3839

3940
def test_artificial_elaborate_only(self):
4041
self.check(self.artificial_run,
@@ -82,14 +83,14 @@ def test_artificial_elaborate_only(self):
8283
check_report(self.report_file, [
8384
("failed", "lib.tb_elab_fail")])
8485

85-
def _test_artificial(self, persistent_sim):
86+
def _test_artificial(self, args=None):
8687
"""
8788
Utility function to run and check the result of all test benches
8889
using either persistent or non-persistent simulator interface mode
8990
"""
9091
self.check(self.artificial_run,
9192
exit_code=1,
92-
persistent_sim=persistent_sim)
93+
args=args)
9394
check_report(self.report_file, [
9495
("passed", "lib.tb_pass"),
9596
("failed", "lib.tb_fail"),
@@ -171,7 +172,8 @@ def check(self, run_file, args=None, persistent_sim=True, clean=True, exit_code=
171172
args = args if args is not None else []
172173
new_env = environ.copy()
173174
new_env["VUNIT_VHDL_STANDARD"] = '2008'
174-
new_env["VUNIT_PERSISTENT_SIM"] = str(persistent_sim)
175+
if not persistent_sim:
176+
args += ["--new-vsim"]
175177
if clean:
176178
args += ["--clean"]
177179
retcode = call([sys.executable, run_file,

vunit/test/acceptance/test_ui.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ def tearDown(self):
8181

8282
def _create_ui(self):
8383
""" Create an instance of the VUnit public interface class """
84-
ui = VUnit(output_path=self._output_path, clean=True)
84+
ui = VUnit.from_argv(argv=["--output-path=%s" % self._output_path,
85+
"--clean"])
8586
ui.add_library('lib')
8687
return ui
8788

@@ -204,7 +205,8 @@ def setUp(self):
204205
self._output_path = join(dirname(__file__), 'ui_out')
205206

206207
def test_can_add_non_ascii_encoded_files(self):
207-
ui = VUnit(output_path=self._output_path, clean=True)
208+
ui = VUnit.from_argv(argv=["--output-path=%s" % self._output_path,
209+
"--clean"])
208210
lib = ui.add_library('lib')
209211
lib.add_source_files(join(dirname(__file__), 'encoding', 'encoding.vhd'))
210212
lib.entity("encoding") # Fill raise exception of not found

vunit/test/common.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,21 @@
1010

1111

1212
from xml.etree import ElementTree
13-
from vunit import VUnit
13+
from vunit.simulator_factory import SimulatorFactory
1414

1515

1616
def has_simulator():
17-
return VUnit.select_simulator().is_available()
17+
return SimulatorFactory.select_simulator().is_available()
1818

1919

2020
def simulator_is(*names):
2121
"""
2222
Check that current simulator is any of names
2323
"""
24-
supported_names = [sim.name for sim in VUnit.supported_simulators()]
24+
supported_names = [sim.name for sim in SimulatorFactory.supported_simulators()]
2525
for name in names:
2626
assert name in supported_names
27-
return VUnit.select_simulator().name in names
27+
return SimulatorFactory.select_simulator().name in names
2828

2929

3030
def check_report(report_file, tests):

0 commit comments

Comments
 (0)