Skip to content

Commit

Permalink
Adds SimulatorFactory class
Browse files Browse the repository at this point in the history
  • Loading branch information
kraigher committed May 22, 2015
1 parent 82c3f1c commit 87e6bcc
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 94 deletions.
11 changes: 11 additions & 0 deletions user_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ cases.
usage: run.py [-h] [-l] [--compile] [--elaborate] [--clean] [-o OUTPUT_PATH]
[-x XUNIT_XML] [-v] [--no-color] [--gui {load,run}]
[--log-level {info,error,warning,debug}]
[--gui {load,run}] [--new-vsim]
[tests [tests ...]]
VUnit command line tool.
Expand All @@ -60,6 +61,16 @@ optional arguments:
and runs the test case while recursively logging all
variables and signals
--log-level {info,error,warning,debug}
modelsim:
ModelSim specific flags
--gui {load,run} Open test case(s) in simulator gui. 'load' only loads
the test case and gives the user control. 'run' loads
and runs the test case while recursively logging all
variables and signals
--new-vsim Do not re-use the same vsim process for running
different test cases (slower)
```

## VHDL Test Benches
Expand Down
28 changes: 28 additions & 0 deletions vunit/modelsim_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,34 @@ class ModelSimInterface(object):
"""
name = "modelsim"

@staticmethod
def add_arguments(parser):
"""
Add command line arguments
"""
group = parser.add_argument_group("modelsim",
description="ModelSim specific flags")
group.add_argument('--gui', choices=["load", "run"],
default=None,
help=("Open test case(s) in simulator gui. "
"'load' only loads the test case and gives the user control. "
"'run' loads and runs the test case while recursively "
"logging all variables and signals"))
group.add_argument("--new-vsim",
action="store_true",
default=False,
help="Do not re-use the same vsim process for running different test cases (slower)")

@classmethod
def from_args(cls, output_path, args):
"""
Create new instance from command line arguments object
"""
persistent = (not args.new_vsim) and args.gui is None
return cls(join(output_path, "modelsim.ini"),
persistent=persistent,
gui_mode=args.gui)

@staticmethod
def is_available():
"""
Expand Down
92 changes: 92 additions & 0 deletions vunit/simulator_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Copyright (c) 2015, Lars Asplund [email protected]

"""
Create simulator instances
"""

from vunit.modelsim_interface import ModelSimInterface
from os.path import join, exists
import os


class SimulatorFactory(object):
"""
Create simulator instances
"""

@staticmethod
def supported_simulators():
"""
Return a list of supported simulator classes
"""
return [ModelSimInterface]

@classmethod
def available_simulators(cls):
"""
Return a list of available simulators
"""
return [simulator_class
for simulator_class in cls.supported_simulators()
if simulator_class.is_available()]

@classmethod
def select_simulator(cls):
"""
Select simulator class, either from VUNIT_SIMULATOR environment variable
or the first available
"""
environ_name = "VUNIT_SIMULATOR"

available_simulators = cls.available_simulators()
name_mapping = {simulator_class.name: simulator_class for simulator_class in cls.supported_simulators()}
if len(available_simulators) == 0:
raise RuntimeError("No available simulator detected. "
"Simulator executables must be available in PATH environment variable.")

if environ_name in os.environ:
simulator_name = os.environ[environ_name]
if simulator_name not in name_mapping:
raise RuntimeError(
("Simulator from " + environ_name + " environment variable %r is not supported. "
"Supported simulators are %r")
% (simulator_name, name_mapping.keys()))
simulator_class = name_mapping[simulator_name]
else:
simulator_class = available_simulators[0]

return simulator_class

@classmethod
def add_arguments(cls, parser):
"""
Add command line arguments to parser
"""
cls.select_simulator().add_arguments(parser)

def __init__(self, args):
self._args = args
self._output_path = args.output_path
self._simulator_class = self.select_simulator()

@property
def simulator_name(self):
return self._simulator_class.name

@property
def simulator_output_path(self):
return join(self._output_path, self.simulator_name)

def create(self):
"""
Create new simulator instance
"""
if not exists(self.simulator_output_path):
os.makedirs(self.simulator_output_path)

return self._simulator_class.from_args(self.simulator_output_path,
self._args)
16 changes: 9 additions & 7 deletions vunit/test/acceptance/test_artificial.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import unittest
from os.path import join, dirname
from vunit.test.common import has_simulator, check_report
from vunit.test.common import has_simulator, check_report, simulator_is
from os import environ
from vunit import VUnit
from subprocess import call
Expand All @@ -30,11 +30,12 @@ def setUp(self):
self.report_file = join(self.output_path, "xunit.xml")
self.artificial_run = join(dirname(__file__), "artificial", "run.py")

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

def test_artificial(self):
self._test_artificial(persistent_sim=False)
self._test_artificial()

def test_artificial_elaborate_only(self):
self.check(self.artificial_run,
Expand Down Expand Up @@ -82,14 +83,14 @@ def test_artificial_elaborate_only(self):
check_report(self.report_file, [
("failed", "lib.tb_elab_fail")])

def _test_artificial(self, persistent_sim):
def _test_artificial(self, args=None):
"""
Utility function to run and check the result of all test benches
using either persistent or non-persistent simulator interface mode
"""
self.check(self.artificial_run,
exit_code=1,
persistent_sim=persistent_sim)
args=args)
check_report(self.report_file, [
("passed", "lib.tb_pass"),
("failed", "lib.tb_fail"),
Expand Down Expand Up @@ -171,7 +172,8 @@ def check(self, run_file, args=None, persistent_sim=True, clean=True, exit_code=
args = args if args is not None else []
new_env = environ.copy()
new_env["VUNIT_VHDL_STANDARD"] = '2008'
new_env["VUNIT_PERSISTENT_SIM"] = str(persistent_sim)
if not persistent_sim:
args += ["--new-vsim"]
if clean:
args += ["--clean"]
retcode = call([sys.executable, run_file,
Expand Down
6 changes: 4 additions & 2 deletions vunit/test/acceptance/test_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ def tearDown(self):

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

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

def test_can_add_non_ascii_encoded_files(self):
ui = VUnit(output_path=self._output_path, clean=True)
ui = VUnit.from_argv(argv=["--output-path=%s" % self._output_path,
"--clean"])
lib = ui.add_library('lib')
lib.add_source_files(join(dirname(__file__), 'encoding', 'encoding.vhd'))
lib.entity("encoding") # Fill raise exception of not found
8 changes: 4 additions & 4 deletions vunit/test/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@


from xml.etree import ElementTree
from vunit import VUnit
from vunit.simulator_factory import SimulatorFactory


def has_simulator():
return VUnit.select_simulator().is_available()
return SimulatorFactory.select_simulator().is_available()


def simulator_is(*names):
"""
Check that current simulator is any of names
"""
supported_names = [sim.name for sim in VUnit.supported_simulators()]
supported_names = [sim.name for sim in SimulatorFactory.supported_simulators()]
for name in names:
assert name in supported_names
return VUnit.select_simulator().name in names
return SimulatorFactory.select_simulator().name in names


def check_report(report_file, tests):
Expand Down
Loading

0 comments on commit 87e6bcc

Please sign in to comment.