diff --git a/tests/acceptance/test_artificial.py b/tests/acceptance/test_artificial.py index 3c8facfc2..4071342fa 100644 --- a/tests/acceptance/test_artificial.py +++ b/tests/acceptance/test_artificial.py @@ -27,7 +27,7 @@ class TestVunitArtificial(unittest.TestCase): """ def setUp(self): - if simulator_is("activehdl"): + if simulator_is("activehdl", "incisive", "xcelium"): self.output_path = str(ROOT / "artificial_out") else: # Spaces in path intentional to verify that it is supported diff --git a/tests/unit/test_xcelium_interface.py b/tests/unit/test_xcelium_interface.py new file mode 100644 index 000000000..ed68e421f --- /dev/null +++ b/tests/unit/test_xcelium_interface.py @@ -0,0 +1,1150 @@ +# 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) 2014-2021, Lars Asplund lars.anders.asplund@gmail.com + +# pylint: disable=too-many-public-methods, too-many-lines + +""" +Test the Xcelium interface +""" + + +import unittest +from pathlib import Path +import os +from shutil import rmtree +from unittest import mock +from vunit.sim_if.xcelium import XceliumInterface +from vunit.project import Project +from vunit.ostools import renew_path, write_file, read_file +from vunit.test.bench import Configuration +from vunit.vhdl_standard import VHDL + + +class TestXceliumInterface(unittest.TestCase): + """ + Test the Xcelium interface + """ + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_vhdl_2008( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.vhd", "") + project.add_source_file( + "file.vhd", "lib", file_type="vhdl", vhdl_standard=VHDL.standard("2008") + ) + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-v200x -extv200x -inc_v200x_pkg", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.log"), + "-quiet", + '-xmlibdirname "."', + "-makelib lib_path", + '"file.vhd"', + "-endlib", + ], + ) + + self.assertEqual( + read_file(str(Path(self.output_path) / "cds.lib")), + """\ +## cds.lib: Defines the locations of compiled libraries. +softinclude cds_root_xrun/tools/inca/files/cds.lib +# needed for referencing the library 'basic' for cells 'cds_alias', 'cds_thru' etc. in analog models: +# NOTE: 'virtuoso' executable not found! +# define basic ".../tools/dfII/etc/cdslib/basic" +define lib "lib_path" +define work "%s/libraries/work" +""" + % self.output_path, + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_vhdl_2002( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.vhd", "") + project.add_source_file( + "file.vhd", "lib", file_type="vhdl", vhdl_standard=VHDL.standard("2002") + ) + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-v200x -extv200x", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.log"), + "-quiet", + '-xmlibdirname "."', + "-makelib lib_path", + '"file.vhd"', + "-endlib", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_vhdl_93( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.vhd", "") + project.add_source_file( + "file.vhd", "lib", file_type="vhdl", vhdl_standard=VHDL.standard("93") + ) + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-v93", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.log"), + "-quiet", + '-xmlibdirname "."', + "-makelib lib_path", + '"file.vhd"', + "-endlib", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_vhdl_extra_flags( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.vhd", "") + source_file = project.add_source_file("file.vhd", "lib", file_type="vhdl") + source_file.set_compile_option("xcelium.xrun_vhdl_flags", ["custom", "flags"]) + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-v200x -extv200x -inc_v200x_pkg", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.log"), + "-quiet", + "custom", + "flags", + '-xmlibdirname "."', + "-makelib lib_path", + '"file.vhd"', + "-endlib", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_vhdl_hdlvar( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface( + prefix="prefix", output_path=self.output_path, hdlvar="custom_hdlvar" + ) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.vhd", "") + project.add_source_file("file.vhd", "lib", file_type="vhdl") + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-v200x -extv200x -inc_v200x_pkg", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-hdlvar "custom_hdlvar"', + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_vhdl_file_lib.log"), + "-quiet", + '-xmlibdirname "."', + "-makelib lib_path", + '"file.vhd"', + "-endlib", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_verilog( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.v", "") + project.add_source_file("file.v", "lib", file_type="verilog") + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_verilog_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn UEXPSC", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_verilog_file_lib.log"), + "-quiet", + '-incdir "cds_root_xrun/tools/spectre/etc/ahdl/"', + '-xmlibdirname "."', + "-makelib lib", + '"file.v"', + "-endlib", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_system_verilog( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.sv", "") + project.add_source_file("file.sv", "lib", file_type="systemverilog") + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_verilog_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn UEXPSC", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_verilog_file_lib.log"), + "-quiet", + '-incdir "cds_root_xrun/tools/spectre/etc/ahdl/"', + '-xmlibdirname "."', + "-makelib lib", + '"file.sv"', + "-endlib", + ], + ) + + self.assertEqual( + read_file(str(Path(self.output_path) / "cds.lib")), + """\ +## cds.lib: Defines the locations of compiled libraries. +softinclude cds_root_xrun/tools/inca/files/cds.lib +# needed for referencing the library 'basic' for cells 'cds_alias', 'cds_thru' etc. in analog models: +# NOTE: 'virtuoso' executable not found! +# define basic ".../tools/dfII/etc/cdslib/basic" +define lib "lib_path" +define work "%s/libraries/work" +""" + % self.output_path, + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_verilog_extra_flags( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.v", "") + source_file = project.add_source_file("file.v", "lib", file_type="verilog") + source_file.set_compile_option( + "xcelium.xrun_verilog_flags", ["custom", "flags"] + ) + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_verilog_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn UEXPSC", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-work work", + "custom", + "flags", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_verilog_file_lib.log"), + "-quiet", + '-incdir "cds_root_xrun/tools/spectre/etc/ahdl/"', + '-xmlibdirname "."', + "-makelib lib", + '"file.v"', + "-endlib", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_verilog_include( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.v", "") + project.add_source_file( + "file.v", "lib", file_type="verilog", include_dirs=["include"] + ) + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_verilog_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn UEXPSC", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_verilog_file_lib.log"), + "-quiet", + '-incdir "include"', + '-incdir "cds_root_xrun/tools/spectre/etc/ahdl/"', + '-xmlibdirname "."', + "-makelib lib", + '"file.v"', + "-endlib", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_verilog_define( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.v", "") + project.add_source_file( + "file.v", "lib", file_type="verilog", defines=dict(defname="defval") + ) + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_verilog_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn UEXPSC", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_verilog_file_lib.log"), + "-quiet", + '-incdir "cds_root_xrun/tools/spectre/etc/ahdl/"', + "-define defname=defval", + '-xmlibdirname "."', + "-makelib lib", + '"file.v"', + "-endlib", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") + def test_compile_project_verilog_hdlvar( + self, check_output, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface( + prefix="prefix", output_path=self.output_path, hdlvar="custom_hdlvar" + ) + project = Project() + project.add_library("lib", "lib_path") + write_file("file.v", "") + project.add_source_file( + "file.v", "lib", file_type="verilog", defines=dict(defname="defval") + ) + simif.compile_project(project) + args_file = str(Path(self.output_path) / "xrun_compile_verilog_file_lib.args") + check_output.assert_called_once_with( + [str(Path("prefix") / "xrun"), "-f", args_file], env=simif.get_env() + ) + self.assertEqual( + read_file(args_file).splitlines(), + [ + "-compile", + "-nocopyright", + "-licqueue", + "-nowarn UEXPSC", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-work work", + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-hdlvar "custom_hdlvar"', + '-log "%s"' + % str(Path(self.output_path) / "xrun_compile_verilog_file_lib.log"), + "-quiet", + '-incdir "cds_root_xrun/tools/spectre/etc/ahdl/"', + "-define defname=defval", + '-xmlibdirname "."', + "-makelib lib", + '"file.v"', + "-endlib", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + def test_create_cds_lib(self, find_cds_root_xrun, find_cds_root_virtuoso): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + XceliumInterface(prefix="prefix", output_path=self.output_path) + self.assertEqual( + read_file(str(Path(self.output_path) / "cds.lib")), + """\ +## cds.lib: Defines the locations of compiled libraries. +softinclude cds_root_xrun/tools/inca/files/cds.lib +# needed for referencing the library 'basic' for cells 'cds_alias', 'cds_thru' etc. in analog models: +# NOTE: 'virtuoso' executable not found! +# define basic ".../tools/dfII/etc/cdslib/basic" +define work "%s/libraries/work" +""" + % self.output_path, + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + def test_create_cds_lib_virtuoso(self, find_cds_root_xrun, find_cds_root_virtuoso): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = "cds_root_virtuoso" + XceliumInterface(prefix="prefix", output_path=self.output_path) + self.assertEqual( + read_file(str(Path(self.output_path) / "cds.lib")), + """\ +## cds.lib: Defines the locations of compiled libraries. +softinclude cds_root_xrun/tools/inca/files/cds.lib +# needed for referencing the library 'basic' for cells 'cds_alias', 'cds_thru' etc. in analog models: +define basic "cds_root_virtuoso/tools/dfII/etc/cdslib/basic" +define work "%s/libraries/work" +""" + % self.output_path, + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.xcelium.run_command", autospec=True, return_value=True) + def test_simulate_vhdl( + self, run_command, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + + project = Project() + project.add_library("lib", "lib_path") + write_file("file.vhd", "") + project.add_source_file("file.vhd", "lib", file_type="vhdl") + + with mock.patch( + "vunit.sim_if.check_output", autospec=True, return_value="" + ) as dummy: + simif.compile_project(project) + + config = make_config() + self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config)) + elaborate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_elaborate.args" + ) + simulate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_simulate.args" + ) + run_command.assert_has_calls( + [ + mock.call( + [ + str(Path("prefix") / "xrun"), + "-f", + Path(elaborate_args_file).name, + ], + cwd=str(Path(elaborate_args_file).parent), + env=simif.get_env(), + ), + mock.call( + [str(Path("prefix") / "xrun"), "-f", Path(simulate_args_file).name], + cwd=str(Path(simulate_args_file).parent), + env=simif.get_env(), + ), + ] + ) + + self.assertEqual( + read_file(elaborate_args_file).splitlines(), + [ + "-elaborate", + "-nocopyright", + "-licqueue", + "-errormax 10", + "-nowarn WRMNZD", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-xmerror EVBBOL", + "-xmerror EVBSTR", + "-xmerror EVBNAT", + "-work work", + '-xmlibdirname "%s"' % str(Path(self.output_path) / "libraries"), + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path("suite_output_path") / simif.name / "xrun_elaborate.log"), + "-quiet", + '-reflib "lib_path"', + '-input "@set intovf_severity_level ignore"', + '-input "@set assert_stop_level %s"' % config.vhdl_assert_stop_level, + "-access +r", + '-input "@run"', + "-top lib.ent:arch", + ], + ) + + self.assertEqual( + read_file(simulate_args_file).splitlines(), + [ + "-nocopyright", + "-licqueue", + "-errormax 10", + "-nowarn WRMNZD", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-xmerror EVBBOL", + "-xmerror EVBSTR", + "-xmerror EVBNAT", + "-work work", + '-xmlibdirname "%s"' % str(Path(self.output_path) / "libraries"), + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path("suite_output_path") / simif.name / "xrun_simulate.log"), + "-quiet", + '-reflib "lib_path"', + '-input "@set intovf_severity_level ignore"', + '-input "@set assert_stop_level %s"' % config.vhdl_assert_stop_level, + "-access +r", + '-input "@run"', + "-top lib.ent:arch", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.xcelium.run_command", autospec=True, return_value=True) + def test_simulate_verilog( + self, run_command, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + + project = Project() + project.add_library("lib", "lib_path") + write_file("file.vhd", "") + project.add_source_file("file.vhd", "lib", file_type="vhdl") + + with mock.patch( + "vunit.sim_if.check_output", autospec=True, return_value="" + ) as dummy: + simif.compile_project(project) + + config = make_config(verilog=True) + self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config)) + elaborate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_elaborate.args" + ) + simulate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_simulate.args" + ) + run_command.assert_has_calls( + [ + mock.call( + [ + str(Path("prefix") / "xrun"), + "-f", + Path(elaborate_args_file).name, + ], + cwd=str(Path(elaborate_args_file).parent), + env=simif.get_env(), + ), + mock.call( + [str(Path("prefix") / "xrun"), "-f", Path(simulate_args_file).name], + cwd=str(Path(simulate_args_file).parent), + env=simif.get_env(), + ), + ] + ) + + self.assertEqual( + read_file(elaborate_args_file).splitlines(), + [ + "-elaborate", + "-nocopyright", + "-licqueue", + "-errormax 10", + "-nowarn WRMNZD", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-xmerror EVBBOL", + "-xmerror EVBSTR", + "-xmerror EVBNAT", + "-work work", + '-xmlibdirname "%s"' % str(Path(self.output_path) / "libraries"), + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path("suite_output_path") / simif.name / "xrun_elaborate.log"), + "-quiet", + '-reflib "lib_path"', + '-input "@set intovf_severity_level ignore"', + '-input "@set assert_stop_level %s"' % config.vhdl_assert_stop_level, + "-access +r", + '-input "@run"', + "-top lib.modulename:sv", + ], + ) + + self.assertEqual( + read_file(simulate_args_file).splitlines(), + [ + "-nocopyright", + "-licqueue", + "-errormax 10", + "-nowarn WRMNZD", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-xmerror EVBBOL", + "-xmerror EVBSTR", + "-xmerror EVBNAT", + "-work work", + '-xmlibdirname "%s"' % str(Path(self.output_path) / "libraries"), + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path("suite_output_path") / simif.name / "xrun_simulate.log"), + "-quiet", + '-reflib "lib_path"', + '-input "@set intovf_severity_level ignore"', + '-input "@set assert_stop_level %s"' % config.vhdl_assert_stop_level, + "-access +r", + '-input "@run"', + "-top lib.modulename:sv", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.xcelium.run_command", autospec=True, return_value=True) + def test_simulate_extra_flags( + self, run_command, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + config = make_config( + sim_options={"xcelium.xrun_sim_flags": ["custom", "flags"]} + ) + self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config)) + elaborate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_elaborate.args" + ) + simulate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_simulate.args" + ) + run_command.assert_has_calls( + [ + mock.call( + [ + str(Path("prefix") / "xrun"), + "-f", + Path(elaborate_args_file).name, + ], + cwd=str(Path(elaborate_args_file).parent), + env=simif.get_env(), + ), + mock.call( + [str(Path("prefix") / "xrun"), "-f", Path(simulate_args_file).name], + cwd=str(Path(simulate_args_file).parent), + env=simif.get_env(), + ), + ] + ) + + args = read_file(elaborate_args_file).splitlines() + self.assertIn("custom", args) + self.assertIn("flags", args) + + args = read_file(simulate_args_file).splitlines() + self.assertIn("custom", args) + self.assertIn("flags", args) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.xcelium.run_command", autospec=True, return_value=True) + def test_simulate_generics_and_parameters( + self, run_command, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + config = make_config( + verilog=True, generics={"genstr": "genval", "genint": 1, "genbool": True} + ) + self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config)) + elaborate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_elaborate.args" + ) + simulate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_simulate.args" + ) + run_command.assert_has_calls( + [ + mock.call( + [ + str(Path("prefix") / "xrun"), + "-f", + Path(elaborate_args_file).name, + ], + cwd=str(Path(elaborate_args_file).parent), + env=simif.get_env(), + ), + mock.call( + [str(Path("prefix") / "xrun"), "-f", Path(simulate_args_file).name], + cwd=str(Path(simulate_args_file).parent), + env=simif.get_env(), + ), + ] + ) + + for args_file in [elaborate_args_file, simulate_args_file]: + args = read_file(args_file).splitlines() + self.assertIn('-gpg "modulename.genstr => \\"genval\\""', args) + self.assertIn('-gpg "modulename.genint => 1"', args) + self.assertIn('-gpg "modulename.genbool => \\"True\\""', args) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.xcelium.run_command", autospec=True, return_value=True) + def test_simulate_hdlvar( + self, run_command, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface( + prefix="prefix", output_path=self.output_path, hdlvar="custom_hdlvar" + ) + config = make_config() + self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config)) + elaborate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_elaborate.args" + ) + simulate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_simulate.args" + ) + run_command.assert_has_calls( + [ + mock.call( + [ + str(Path("prefix") / "xrun"), + "-f", + Path(elaborate_args_file).name, + ], + cwd=str(Path(elaborate_args_file).parent), + env=simif.get_env(), + ), + mock.call( + [str(Path("prefix") / "xrun"), "-f", Path(simulate_args_file).name], + cwd=str(Path(simulate_args_file).parent), + env=simif.get_env(), + ), + ] + ) + + for args_file in [elaborate_args_file, simulate_args_file]: + args = read_file(args_file).splitlines() + self.assertIn('-hdlvar "custom_hdlvar"', args) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.xcelium.run_command", autospec=True, return_value=True) + def test_elaborate(self, run_command, find_cds_root_xrun, find_cds_root_virtuoso): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + config = make_config(verilog=True) + self.assertTrue( + simif.simulate( + "suite_output_path", "test_suite_name", config, elaborate_only=True + ) + ) + elaborate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_elaborate.args" + ) + run_command.assert_has_calls( + [ + mock.call( + [ + str(Path("prefix") / "xrun"), + "-f", + Path(elaborate_args_file).name, + ], + cwd=str(Path(elaborate_args_file).parent), + env=simif.get_env(), + ) + ] + ) + + self.assertEqual( + read_file(elaborate_args_file).splitlines(), + [ + "-elaborate", + "-nocopyright", + "-licqueue", + "-errormax 10", + "-nowarn WRMNZD", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-xmerror EVBBOL", + "-xmerror EVBSTR", + "-xmerror EVBNAT", + "-work work", + '-xmlibdirname "%s"' % str(Path(self.output_path) / "libraries"), + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path("suite_output_path") / simif.name / "xrun_elaborate.log"), + "-quiet", + '-input "@set intovf_severity_level ignore"', + '-input "@set assert_stop_level %s"' % config.vhdl_assert_stop_level, + "-access +r", + '-input "@run"', + "-top lib.modulename:sv", + ], + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.xcelium.run_command", autospec=True, return_value=False) + def test_elaborate_fail( + self, run_command, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + config = make_config() + self.assertFalse(simif.simulate("suite_output_path", "test_suite_name", config)) + elaborate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_elaborate.args" + ) + run_command.assert_has_calls( + [ + mock.call( + [ + str(Path("prefix") / "xrun"), + "-f", + Path(elaborate_args_file).name, + ], + cwd=str(Path(elaborate_args_file).parent), + env=simif.get_env(), + ) + ] + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch( + "vunit.sim_if.xcelium.run_command", autospec=True, side_effect=[True, False] + ) + def test_simulate_fail( + self, run_command, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + simif = XceliumInterface(prefix="prefix", output_path=self.output_path) + config = make_config() + self.assertFalse(simif.simulate("suite_output_path", "test_suite_name", config)) + elaborate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_elaborate.args" + ) + simulate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_simulate.args" + ) + run_command.assert_has_calls( + [ + mock.call( + [ + str(Path("prefix") / "xrun"), + "-f", + Path(elaborate_args_file).name, + ], + cwd=str(Path(elaborate_args_file).parent), + env=simif.get_env(), + ), + mock.call( + [str(Path("prefix") / "xrun"), "-f", Path(simulate_args_file).name], + cwd=str(Path(simulate_args_file).parent), + env=simif.get_env(), + ), + ] + ) + + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_virtuoso") + @mock.patch("vunit.sim_if.xcelium.XceliumInterface.find_cds_root_xrun") + @mock.patch("vunit.sim_if.xcelium.run_command", autospec=True, return_value=True) + def test_simulate_gui( + self, run_command, find_cds_root_xrun, find_cds_root_virtuoso + ): + find_cds_root_xrun.return_value = "cds_root_xrun" + find_cds_root_virtuoso.return_value = None + + project = Project() + project.add_library("lib", "lib_path") + write_file("file.vhd", "") + project.add_source_file("file.vhd", "lib", file_type="vhdl") + + simif = XceliumInterface( + prefix="prefix", output_path=self.output_path, gui=True + ) + with mock.patch( + "vunit.sim_if.check_output", autospec=True, return_value="" + ) as dummy: + simif.compile_project(project) + config = make_config() + self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config)) + elaborate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_elaborate.args" + ) + simulate_args_file = str( + Path("suite_output_path") / simif.name / "xrun_simulate.args" + ) + run_command.assert_has_calls( + [ + mock.call( + [ + str(Path("prefix") / "xrun"), + "-f", + Path(elaborate_args_file).name, + ], + cwd=str(Path(elaborate_args_file).parent), + env=simif.get_env(), + ), + mock.call( + [str(Path("prefix") / "xrun"), "-f", Path(simulate_args_file).name], + cwd=str(Path(simulate_args_file).parent), + env=simif.get_env(), + ), + ] + ) + self.assertEqual( + read_file(elaborate_args_file).splitlines(), + [ + "-elaborate", + "-nocopyright", + "-licqueue", + "-errormax 10", + "-nowarn WRMNZD", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-xmerror EVBBOL", + "-xmerror EVBSTR", + "-xmerror EVBNAT", + "-work work", + '-xmlibdirname "%s"' % str(Path(self.output_path) / "libraries"), + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path("suite_output_path") / simif.name / "xrun_elaborate.log"), + "-quiet", + '-reflib "lib_path"', + '-input "@set intovf_severity_level ignore"', + '-input "@set assert_stop_level %s"' % config.vhdl_assert_stop_level, + "-access +rwc", + "-gui", + "-top lib.ent:arch", + ], + ) + + self.assertEqual( + read_file(simulate_args_file).splitlines(), + [ + "-nocopyright", + "-licqueue", + "-errormax 10", + "-nowarn WRMNZD", + "-nowarn DLCPTH", + "-nowarn DLCVAR", + "-xmerror EVBBOL", + "-xmerror EVBSTR", + "-xmerror EVBNAT", + "-work work", + '-xmlibdirname "%s"' % str(Path(self.output_path) / "libraries"), + '-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"), + '-log "%s"' + % str(Path("suite_output_path") / simif.name / "xrun_simulate.log"), + "-quiet", + '-reflib "lib_path"', + '-input "@set intovf_severity_level ignore"', + '-input "@set assert_stop_level %s"' % config.vhdl_assert_stop_level, + "-access +rwc", + "-gui", + "-top lib.ent:arch", + ], + ) + + def setUp(self): + self.output_path = str(Path(__file__).parent / "test_xcelium_out") + renew_path(self.output_path) + self.project = Project() + self.cwd = os.getcwd() + os.chdir(self.output_path) + + def tearDown(self): + os.chdir(self.cwd) + if Path(self.output_path).exists(): + rmtree(self.output_path) + + +def make_config(sim_options=None, generics=None, verilog=False): + """ + Utility to reduce boiler plate in tests + """ + cfg = mock.Mock(spec=Configuration) + cfg.library_name = "lib" + + if verilog: + cfg.entity_name = "modulename" + cfg.architecture_name = None + else: + cfg.entity_name = "ent" + cfg.architecture_name = "arch" + + cfg.sim_options = {} if sim_options is None else sim_options + cfg.generics = {} if generics is None else generics + return cfg diff --git a/tools/xcelium_verilog_fixup.py b/tools/xcelium_verilog_fixup.py new file mode 100644 index 000000000..0bd276470 --- /dev/null +++ b/tools/xcelium_verilog_fixup.py @@ -0,0 +1,60 @@ +# 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) 2014-2021, Lars Asplund lars.anders.asplund@gmail.com + +""" +Perform necessary modifications to VUnit Verilog code to support +Cadence Xcelium +""" + +import os +import re +from pathlib import Path + + +def replace_stop_by_finish(file_name): + """ + Replace $stop by $finish + """ + + with Path(file_name).open("r", encoding="iso-8859-1") as fptr: + text = fptr.read() + + text = text.replace("$stop(", "$finish(") + + with Path(file_name).open("w", encoding="iso-8859-1") as fptr: + fptr.write(text) + + +def add_finish_after_error(file_name): + """ + Add $finish after a $error + """ + + with Path(file_name).open("r", encoding="iso-8859-1") as fptr: + text = fptr.read() + + text = re.sub(r"(\$error\(.*\))", "\\1; $finish(1)", text) + + with Path(file_name).open("w", encoding="iso-8859-1") as fptr: + fptr.write(text) + + +def main(): + """ + Remove xcelium incompatabilities from source code + """ + where = "../vunit/verilog" + root = os.path.abspath(os.path.join(os.path.dirname(__file__), where)) + for base, _, files in os.walk(root): + for file_name in files: + if file_name.endswith(".sv") or file_name.endswith(".svh"): + replace_stop_by_finish(os.path.join(base, file_name)) + add_finish_after_error(os.path.join(base, file_name)) + + +if __name__ == "__main__": + #main() + print("nothing to do") diff --git a/vunit/configuration.py b/vunit/configuration.py index b3ea9f1b6..1e0910505 100644 --- a/vunit/configuration.py +++ b/vunit/configuration.py @@ -12,7 +12,7 @@ import inspect from pathlib import Path from copy import copy -from vunit.sim_if.factory import SIMULATOR_FACTORY + LOGGER = logging.getLogger(__name__) @@ -123,6 +123,7 @@ def set_sim_option(self, name, value): """ Set sim option """ + from vunit.sim_if.factory import SIMULATOR_FACTORY SIMULATOR_FACTORY.check_sim_option(name, value) self.sim_options[name] = copy(value) diff --git a/vunit/project.py b/vunit/project.py index 81411749a..d35c94303 100644 --- a/vunit/project.py +++ b/vunit/project.py @@ -27,6 +27,7 @@ ) from vunit.vhdl_standard import VHDL, VHDLStandard from vunit.library import Library +from typing import List LOGGER = logging.getLogger(__name__) @@ -430,7 +431,7 @@ def _get_compile_timestamps(self, files): timestamps[source_file] = ostools.get_modification_time(hash_file_name) return timestamps - def get_files_in_compile_order(self, incremental=True, dependency_graph=None, files=None): + def get_files_in_compile_order(self, incremental=True, dependency_graph=None, files=None) -> List[SourceFile]: """ Get a list of all files in compile order param: incremental: Only return files that need recompile if True diff --git a/vunit/sim_if/__init__.py b/vunit/sim_if/__init__.py index 8b472dd62..78a6b13f3 100644 --- a/vunit/sim_if/__init__.py +++ b/vunit/sim_if/__init__.py @@ -49,6 +49,8 @@ class SimulatorInterface(object): # pylint: disable=too-many-public-methods # True if simulator supports ANSI colors in GUI mode supports_colors_in_gui = False + incremental_compile = True + def __init__(self, output_path, gui): self._output_path = output_path self._gui = gui @@ -259,7 +261,7 @@ def compile_source_files( failures = [] if target_files is None: - source_files = project.get_files_in_compile_order(dependency_graph=dependency_graph) + source_files = project.get_files_in_compile_order(incremental=self.incremental_compile, dependency_graph=dependency_graph) else: source_files = project.get_minimal_file_set_in_compile_order(target_files) diff --git a/vunit/sim_if/cds_file.py b/vunit/sim_if/cds_file.py index b7034d8dd..a7b430e39 100644 --- a/vunit/sim_if/cds_file.py +++ b/vunit/sim_if/cds_file.py @@ -5,7 +5,7 @@ # Copyright (c) 2014-2022, Lars Asplund lars.anders.asplund@gmail.com """ -Handles Cadence Incisive .cds files +Handles Cadence Incisive/Xcelium .cds files """ import re @@ -14,7 +14,7 @@ class CDSFile(dict): """ - Handles Cadence Incisive .cds files + Handles Cadence Incisive/Xcelium .cds files Only cares about 'define' but other lines are kept intact """ diff --git a/vunit/sim_if/factory.py b/vunit/sim_if/factory.py index 038b30609..a572a3283 100644 --- a/vunit/sim_if/factory.py +++ b/vunit/sim_if/factory.py @@ -11,6 +11,7 @@ import os from .activehdl import ActiveHDLInterface from .ghdl import GHDLInterface +from .xcelium import XceliumInterface from .incisive import IncisiveInterface from .modelsim import ModelSimInterface from .rivierapro import RivieraProInterface @@ -32,6 +33,7 @@ def supported_simulators(): RivieraProInterface, ActiveHDLInterface, GHDLInterface, + XceliumInterface, IncisiveInterface, ] diff --git a/vunit/sim_if/incisive.py b/vunit/sim_if/incisive.py index 52c934053..e57aaaa1f 100644 --- a/vunit/sim_if/incisive.py +++ b/vunit/sim_if/incisive.py @@ -38,22 +38,7 @@ class IncisiveInterface(SimulatorInterface): # pylint: disable=too-many-instanc sim_options = [ListOfStringOption("incisive.irun_sim_flags")] - @staticmethod - def add_arguments(parser): - """ - Add command line arguments - """ - group = parser.add_argument_group("Incisive irun", description="Incisive irun-specific flags") - group.add_argument( - "--cdslib", - default=None, - help="The cds.lib file to use. If not given, VUnit maintains its own cds.lib file.", - ) - group.add_argument( - "--hdlvar", - default=None, - help="The hdl.var file to use. If not given, VUnit does not use a hdl.var file.", - ) + # NOTE: Incisive shares the command-line arguments with Xcelium @classmethod def from_args(cls, args, output_path, **kwargs): @@ -102,14 +87,14 @@ def find_cds_root_irun(self): """ Finds irun cds root """ - return subprocess.check_output([str(Path(self._prefix) / "cds_root"), "irun"]).splitlines()[0] + return subprocess.check_output([str(Path(self._prefix) / "cds_root"), "irun"]).splitlines()[0].decode() def find_cds_root_virtuoso(self): """ Finds virtuoso cds root """ try: - return subprocess.check_output([str(Path(self._prefix) / "cds_root"), "virtuoso"]).splitlines()[0] + return subprocess.check_output([str(Path(self._prefix) / "cds_root"), "virtuoso"]).splitlines()[0].decode() except subprocess.CalledProcessError: return None diff --git a/vunit/sim_if/xcelium.py b/vunit/sim_if/xcelium.py new file mode 100644 index 000000000..5cd0fe408 --- /dev/null +++ b/vunit/sim_if/xcelium.py @@ -0,0 +1,694 @@ +# 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) 2014-2021, Lars Asplund lars.anders.asplund@gmail.com + +""" +Interface for the Cadence Xcelium simulator +""" + +from pathlib import Path +from os.path import relpath +from typing import Dict, List +from copy import copy +import sys +import os +import stat +import subprocess +import logging +from ..exceptions import CompileError +from ..ostools import write_file, file_exists, simplify_path +from ..vhdl_standard import VHDL +from . import SimulatorInterface, run_command, ListOfStringOption, check_output +from .cds_file import CDSFile +from ..color_printer import NO_COLOR_PRINTER +from ..configuration import Configuration +from ..project import Project +from vunit.source_file import SourceFile +from vunit.library import Library + + +LOGGER = logging.getLogger(__name__) + + +class XceliumInterface( # pylint: disable=too-many-instance-attributes + SimulatorInterface +): + """ + Interface for the Cadence Xcelium simulator + """ + + name = "xcelium" + supports_gui_flag = True + package_users_depend_on_bodies = False + incremental = False + + compile_options = [ + ListOfStringOption("xcelium.xrun_vhdl_flags"), + ListOfStringOption("xcelium.xrun_verilog_flags"), + ListOfStringOption("xcelium.xrun_cdslib"), + ] + + sim_options = [ListOfStringOption("xcelium.xrun_sim_flags"), + ListOfStringOption("xcelium.xrun_sim_flags.gui")] + + _global_compile_options: Dict + + @staticmethod + def add_arguments(parser): + """ + Add command line arguments + """ + group = parser.add_argument_group( + "Xcelium/Incisive", description="Xcelium/Incisive specific flags" + ) + group.add_argument( + "--cdslib", + default=None, + help="The cds.lib file to use. If not given, VUnit maintains its own cds.lib file.", + ) + group.add_argument( + "--hdlvar", + default=None, + help="The hdl.var file to use. If not given, VUnit does not use a hdl.var file.", + ) + group.add_argument( + "--use_indago", + default=False, + help="Indicate whether to use Indago instead of Simvision when running in GUI mode.", + action="store_true", + ) + + @classmethod + def from_args(cls, args, output_path, **kwargs): + """ + Create new instance from command line arguments object + """ + return cls( + prefix=cls.find_prefix(), + output_path=output_path, + log_level=args.log_level, + gui=args.gui, + cdslib=args.cdslib, + hdlvar=args.hdlvar, + use_indago=args.use_indago + ) + + @classmethod + def find_prefix_from_path(cls): + """ + Find xcelium simulator from PATH environment variable + """ + return cls.find_toolchain(["xrun"]) + + + @staticmethod + def supports_vhdl_contexts(): + """ + Returns True when this simulator supports VHDL 2008 contexts + """ + return True + + def __init__( # pylint: disable=too-many-arguments + self, prefix, output_path, gui=False, log_level=None, cdslib=None, hdlvar=None, use_indago=False + ): + SimulatorInterface.__init__(self, output_path, gui) + self._global_compile_options = {} + self._prefix = prefix + self._libraries = [] + self._log_level = log_level + if cdslib is None: + self._cdslib = str((Path(output_path) / "cds.lib").resolve()) + else: + self._cdslib = str(Path(cdslib).resolve()) + self._hdlvar = hdlvar + self._use_indago = use_indago + self._cds_root_xrun = self.find_cds_root_xrun() + + + def find_cds_root_xrun(self): + """ + Finds xrun cds root + """ + return subprocess.check_output( + [str(Path(self._prefix) / "cds_root"), "xrun"] + ).splitlines()[0].decode() + + def find_cds_root_virtuoso(self): + """ + Finds virtuoso cds root + """ + try: + return subprocess.check_output( + [str(Path(self._prefix) / "cds_root"), "virtuoso"], + stderr=subprocess.STDOUT + ).splitlines()[0].decode() + except subprocess.CalledProcessError: + return None + + def _create_cdslib(self): + """ + Create the cds.lib file in the output directory if it does not exist + """ + cds_root_virtuoso = self.find_cds_root_virtuoso() + + if cds_root_virtuoso is None: + contents = """\ +## cds.lib: Defines the locations of compiled libraries. +softinclude {0}/tools/inca/files/cds.lib +# needed for referencing the library 'basic' for cells 'cds_alias', 'cds_thru' etc. in analog models: +# NOTE: 'virtuoso' executable not found! +# define basic ".../tools/dfII/etc/cdslib/basic" +define work "{1}/libraries/work" + +# user defined cds by changing: global.xcelium.xrun_cdslib +""".format( + self._cds_root_xrun, self._output_path + ) + else: + contents = """\ +## cds.lib: Defines the locations of compiled libraries. +softinclude {0}/tools/inca/files/cds.lib +# needed for referencing the library 'basic' for cells 'cds_alias', 'cds_thru' etc. in analog models: +define basic "{1}/tools/dfII/etc/cdslib/basic" +define work "{2}/libraries/work" + +# user defined cds by changing: global.xcelium.xrun_cdslib +""".format( + self._cds_root_xrun, cds_root_virtuoso, self._output_path + ) + + + # add our cdslib customization + xrun_cdslibs = self.get_global_compile_option("xcelium.xrun_cdslib") + for xrun_cdslib in xrun_cdslibs: + contents += xrun_cdslib + "\n" + + + contents += "\n" + contents += "# project libraries \n" + write_file(self._cdslib, contents) + + def set_global_compile_options(self, global_options: Dict): + self._global_compile_options = global_options + + def get_global_compile_option(self, name): + """ + Return a copy of the compile option list + """ + if name not in self._global_compile_options: + self._global_compile_options[name] = [] + + return copy(self._global_compile_options[name]) + + def setup_library_mapping(self, project: Project): + """ + Compile project using vhdl_standard + """ + self._create_cdslib() + mapped_libraries = self._get_mapped_libraries() + + for library in project.get_libraries(): + self._libraries.append(library) + self.create_library(library.name, library.directory, mapped_libraries) + + def compile_source_file_command(self, source_file): + """ + Returns the command to compile a single source file + """ + if source_file.is_vhdl: + return self.compile_vhdl_file_command(source_file) + + if source_file.is_any_verilog: + return self.compile_verilog_file_command(source_file) + + LOGGER.error("Unknown file type: %s", source_file.file_type) + raise CompileError + + def _compile_all_source_files(self, source_files_by_library: Dict[Library, List[SourceFile]], printer): + """ + Compiles all source files and prints status information + """ + try: + command = self.compile_all_files_command(source_files_by_library) + except CompileError: + command = None + printer.write("failed", fg="ri") + printer.write("\n") + printer.write(f"File type not supported by {self.name!s} simulator\n") + + return False + + try: + output = check_output(command, env=self.get_env()) + printer.write("passed", fg="gi") + printer.write("\n") + printer.write(output) + + except subprocess.CalledProcessError as err: + printer.write("failed", fg="ri") + printer.write("\n") + printer.write(f"=== Command used: ===\n{subprocess.list2cmdline(command)!s}\n") + printer.write("\n") + printer.write(f"=== Command output: ===\n{err.output!s}\n") + + return False + + return True + + def compile_source_files( + self, + project: Project, + printer=NO_COLOR_PRINTER, + continue_on_error=False, + target_files=None, + ): + """ + Use compile_source_file_command to compile all source_files + param: target_files: Given a list of SourceFiles only these and dependent files are compiled + """ + dependency_graph = project.create_dependency_graph() + failures = [] + + if target_files is None: + source_files: List[SourceFile] = project.get_files_in_compile_order(dependency_graph=dependency_graph) + else: + source_files: List[SourceFile] = project.get_minimal_file_set_in_compile_order(target_files) + + source_files_to_skip = set() + + max_library_name = 0 + max_source_file_name = 0 + if source_files: + max_library_name = max(len(source_file.library.name) for source_file in source_files) + max_source_file_name = max(len(simplify_path(source_file.name)) for source_file in source_files) + + source_files_by_library: Dict[Library, List[SourceFile]] = {} + for source_file in source_files: + if source_file.library in source_files_by_library: + source_files_by_library[source_file.library].append(source_file) + else: + source_files_by_library[source_file.library] = [source_file] + # import pprint + # pprint.pprint(source_files_by_library) + + printer.write("Compiling all source files") + sys.stdout.flush() + if self._compile_all_source_files(source_files_by_library, printer): + printer.write("All source files compiled!\n") + printer.write("Compile passed\n", fg="gi") + else: + printer.write("One or more source files failed to compile.\n") + printer.write("Compile failed\n", fg="ri") + raise CompileError + + + @staticmethod + def _vhdl_std_opt(vhdl_standard): + """ + Convert standard to format of xrun command line flag + """ + if vhdl_standard == VHDL.STD_2002: + return "-v200x -extv200x" + + if vhdl_standard == VHDL.STD_2008: + return "-v200x -extv200x -inc_v200x_pkg" + + if vhdl_standard == VHDL.STD_1993: + return "-v93" + + raise ValueError("Invalid VHDL standard %s" % vhdl_standard) + + def _compile_all_files_in_library_subcommand(self, library, source_files): + """ + Return a command to compile all source files in a library + """ + args = [] + args += ["-makelib %s" % library.directory] + search_list = [] + + for source_file in source_files: + unique_args = [] + if source_file.is_vhdl: + unique_args += ["%s" % self._vhdl_std_opt(source_file.get_vhdl_standard())] + unique_args += source_file.get_compile_option("xcelium.xrun_vhdl_flags", include_global=False) + + if source_file.is_any_verilog: + unique_args += source_file.get_compile_option("xcelium.xrun_verilog_flags", include_global=False) + for include_dir in source_file.include_dirs: + if include_dir not in search_list: + search_list.append(include_dir) + for key, value in source_file.defines.items(): + unique_args += ["-define %s=%s" % (key, value.replace('"', '\\"'))] + + args += [source_file.name] + if len(unique_args) > 0: + # args += ["-filemap %s" % source_file.name] + args += unique_args + # args += ["-endfilemap"] + else: + # args += [source_file.name] + pass + + for include_dir in search_list: + args += ['-incdir "%s"' % include_dir] + + args += ["-endlib"] + argsfile = str( + Path(self._output_path) + / ("xrun_compile_library_%s.args" % library.name) + ) + write_file(argsfile, "\n".join(args)) + return ["-F", argsfile] + + + def compile_all_files_command(self, source_files: Dict[Library, List[SourceFile]]): + """ + Return a command to compile all source files + """ + first_library = True + launch_gui = self._gui is not False + use_indago = self._use_indago is not False + + cmd = str(Path(self._prefix) / "xrun") + args = [] + + args += ["-compile"] + args += ["-nocopyright"] + args += ["-licqueue"] + # "Ignored unexpected semicolon following SystemVerilog description keyword (endfunction)." + args += ["-nowarn UEXPSC"] + # "cds.lib Invalid path" + args += ["-nowarn DLCPTH"] + # "cds.lib Invalid environment variable ''." + args += ["-nowarn DLCVAR"] + args += ['-cdslib "%s"' % self._cdslib] + args += self._hdlvar_args() + args += [ + '-log "%s"' + % str( + Path(self._output_path) + / ("xrun_compile_all.log") + ) + ] + if not self._log_level == "debug": + args += ["-quiet"] + else: + args += ["-messages"] + args += ["-libverbose"] + # for "disciplines.vams" etc. + args += ['-incdir "%s/tools/spectre/etc/ahdl/"' % self._cds_root_xrun] + + args += self.get_global_compile_option("xcelium.xrun_vhdl_flags") + args += self.get_global_compile_option("xcelium.xrun_verilog_flags") + + args += ["-define XCELIUM "] + if launch_gui and use_indago: + args += ["-debug_opts indago_interactive"] + args += ["-linedebug"] + #args += ["-uvmlinedebug"] + + for library, _source_files in source_files.items(): + if first_library: + args += ['-xmlibdirname "%s"' % str(Path(library.directory).parent)] + first_library = False + + args += self._compile_all_files_in_library_subcommand(library, _source_files) + + argsfile = str( + Path(self._output_path) + / ("xrun_compile_all.args") + ) + write_file(argsfile, "\n".join(args)) + return [cmd, "-F", argsfile, "-clean"] + + def compile_vhdl_file_command(self, source_file): + """ + Returns command to compile a VHDL file + """ + cmd = str(Path(self._prefix) / "xrun") + args = [] + args += ["-compile"] + args += ["-nocopyright"] + args += ["-licqueue"] + args += ["-nowarn DLCPTH"] # "cds.lib Invalid path" + args += ["-nowarn DLCVAR"] # "cds.lib Invalid environment variable ''." + args += ["%s" % self._vhdl_std_opt(source_file.get_vhdl_standard())] + args += ['-cdslib "%s"' % self._cdslib] + args += self._hdlvar_args() + args += [ + '-log "%s"' + % str( + Path(self._output_path) + / ("xrun_compile_vhdl_file_%s.log" % source_file.library.name) + ) + ] + if not self._log_level == "debug": + args += ["-quiet"] + else: + args += ["-messages"] + args += ["-libverbose"] + args += source_file.compile_options.get("xcelium.xrun_vhdl_flags", []) + args += ['-xmlibdirname "%s"' % str(Path(source_file.library.directory).parent)] + args += ["-makelib %s" % source_file.library.directory] + args += ['"%s"' % source_file.name] + args += ["-endlib"] + argsfile = str( + Path(self._output_path) + / ("xrun_compile_vhdl_file_%s.args" % source_file.library.name) + ) + write_file(argsfile, "\n".join(args)) + return [cmd, "-F", argsfile] + + def compile_verilog_file_command(self, source_file): + """ + Returns commands to compile a Verilog file + """ + cmd = str(Path(self._prefix) / "xrun") + args = [] + args += ["-compile"] + args += ["-nocopyright"] + args += ["-licqueue"] + # "Ignored unexpected semicolon following SystemVerilog description keyword (endfunction)." + args += ["-nowarn UEXPSC"] + # "cds.lib Invalid path" + args += ["-nowarn DLCPTH"] + # "cds.lib Invalid environment variable ''." + args += ["-nowarn DLCVAR"] + args += source_file.compile_options.get("xcelium.xrun_verilog_flags", []) + args += ['-cdslib "%s"' % self._cdslib] + args += self._hdlvar_args() + args += [ + '-log "%s"' + % str( + Path(self._output_path) + / ("xrun_compile_verilog_file_%s.log" % source_file.library.name) + ) + ] + if not self._log_level == "debug": + args += ["-quiet"] + else: + args += ["-messages"] + args += ["-libverbose"] + for include_dir in source_file.include_dirs: + args += ['-incdir "%s"' % include_dir] + + # for "disciplines.vams" etc. + args += ['-incdir "%s/tools/spectre/etc/ahdl/"' % self._cds_root_xrun] + + for key, value in source_file.defines.items(): + args += ["-define %s=%s" % (key, value.replace('"', '\\"'))] + args += ['-xmlibdirname "%s"' % str(Path(source_file.library.directory).parent)] + args += ["-makelib %s" % source_file.library.name] + args += ['"%s"' % source_file.name] + args += ["-endlib"] + argsfile = str( + Path(self._output_path) + / ("xrun_compile_verilog_file_%s.args" % source_file.library.name) + ) + write_file(argsfile, "\n".join(args)) + return [cmd, "-F", argsfile] + + def create_library(self, library_name, library_path, mapped_libraries=None): + """ + Create and map a library_name to library_path + """ + mapped_libraries = mapped_libraries if mapped_libraries is not None else {} + + lpath = str(Path(library_path).resolve().parent) + + if not file_exists(lpath): + os.makedirs(lpath) + + if ( + library_name in mapped_libraries + and mapped_libraries[library_name] == library_path + ): + return + + cds = CDSFile.parse(self._cdslib) + cds[library_name] = library_path + cds.write(self._cdslib) + + def _get_mapped_libraries(self): + """ + Get mapped libraries from cds.lib file + """ + cds = CDSFile.parse(self._cdslib) + return cds + + def simulate( # pylint: disable=too-many-locals, too-many-branches + self, output_path, test_suite_name, config:Configuration, elaborate_only=False + ): + """ + Elaborates and Simulates with entity as top level using generics + """ + + script_path = str(Path(output_path) / self.name) + launch_gui = self._gui is not False and not elaborate_only + use_indago = self._use_indago is not False + + + rerun_file_path="%s/rerun.sh" % script_path + rerun_content=[] + rerun_content+=["#/bin/bash"] + rerun_content+=["set -euo pipefail"] + rerun_content+=["echo 'running compile all'"] + rerun_content+=["xrun -F %s/xrun_compile_all.args" % Path(self._output_path)] + rerun_content+=["echo 'running elaborate'"] + rerun_content+=["xrun -F %s/xrun_elaborate.args" % script_path] + write_file(rerun_file_path, "\n".join(rerun_content)) + st = os.stat(rerun_file_path) + os.chmod(rerun_file_path, st.st_mode | stat.S_IEXEC) + + + if elaborate_only: + steps = ["elaborate"] + else: + steps = ["elaborate", "simulate"] + + for step in steps: + cmd = str(Path(self._prefix) / "xrun") + args = [] + if step == "elaborate": + args += ["-elaborate"] + args += ["-nocopyright"] + args += ["-licqueue"] + # args += ['-dumpstack'] + # args += ['-gdbsh'] + # args += ['-rebuild'] + # args += ['-gdb'] + # args += ['-gdbelab'] + args += ["-errormax 10"] + args += ["-nowarn WRMNZD"] + args += ["-nowarn DLCPTH"] # "cds.lib Invalid path" + args += ["-nowarn DLCVAR"] # "cds.lib Invalid environment variable ''." + args += [ + "-xmerror EVBBOL" + ] # promote to error: "bad boolean literal in generic association" + args += [ + "-xmerror EVBSTR" + ] # promote to error: "bad string literal in generic association" + args += [ + "-xmerror EVBNAT" + ] # promote to error: "bad natural literal in generic association" + args += [ + '-xmlibdirname "%s"' % (str(Path(self._output_path) / "libraries")) + ] # @TODO: ugly + args += config.sim_options.get("xcelium.xrun_sim_flags", []) + + args += ['-cdslib "%s"' % self._cdslib] + args += self._hdlvar_args() + args += ['-log "%s"' % str(Path(script_path) / ("xrun_%s.log" % step))] + if not self._log_level == "debug": + args += ["-quiet"] + else: + args += ["-messages"] + # args += ['-libverbose'] + args += self._generic_args(config.entity_name, config.generics) + for library in self._libraries: + args += ['-reflib "%s"' % library.directory] + args += ['-input "@set intovf_severity_level ignore"'] + if config.sim_options.get("disable_ieee_warnings", False): + args += [ + '-input "@set pack_assert_off { std_logic_arith numeric_std }"' + ] + args += [ + '-input "@set assert_stop_level %s"' % config.vhdl_assert_stop_level + ] + if launch_gui: + args += ["-access +rwc"] + args += ['-linedebug'] + args += ['-classlinedebug'] + if use_indago: + args += ["-debug_opts indago_interactive"] + if step == "elaborate": + args += ['-persistent_sources_debug'] + else: + args += ["-nolock"] + else: + # Use simvision + args += ["-gui"] + + if step == "elaborate": + pass + #args += ["-uvmlinedebug"] + + gui_options = config.sim_options.get("xcelium.xrun_sim_flags.gui", []) + if gui_options is not None: + args = gui_options + args + else: + args += ['-input "@run"'] + else: + args += ["-access +r"] + args += ['-input "@run"'] + + if config.architecture_name is None: + # we have a SystemVerilog toplevel: + args += ["-top %s.%s:sv" % (config.library_name, config.entity_name)] + else: + # we have a VHDL toplevel: + args += [ + "-top %s.%s:%s" + % ( + config.library_name, + config.entity_name, + config.architecture_name, + ) + ] + argsfile = "%s/xrun_%s.args" % (script_path, step) + write_file(argsfile, "\n".join(args)) + if not run_command( + [cmd, "-F", relpath(argsfile, script_path)], + cwd=script_path, + env=self.get_env(), + ): + return False + + return True + + def _hdlvar_args(self): + """ + Return hdlvar argument if available + """ + if self._hdlvar is None: + return [] + return ['-hdlvar "%s"' % self._hdlvar] + + @staticmethod + def _generic_args(entity_name, generics): + """ + Create xrun arguments for generics/parameters + """ + args = [] + for name, value in generics.items(): + if _generic_needs_quoting(value): + args += ['''-gpg "%s.%s => \\"%s\\""''' % (entity_name, name, value)] + else: + args += ['''-gpg "%s.%s => %s"''' % (entity_name, name, value)] + return args + + +def _generic_needs_quoting(value): # pylint: disable=missing-docstring + return isinstance(value, (str, bool)) diff --git a/vunit/source_file.py b/vunit/source_file.py index c0ae6e0a7..7cc05ab91 100644 --- a/vunit/source_file.py +++ b/vunit/source_file.py @@ -8,11 +8,10 @@ Functionality to represent and operate on VHDL and Verilog source files """ from pathlib import Path -from typing import Union +from typing import Union, Dict import logging from copy import copy import traceback -from vunit.sim_if.factory import SIMULATOR_FACTORY from vunit.hashing import hash_string from vunit.vhdl_parser import VHDLReference from vunit.cached import file_content_hash @@ -28,14 +27,16 @@ class SourceFile(object): """ Represents a generic source file """ + _global_compile_options: Dict def __init__(self, name, library, file_type): self.name = name - self.library = library - self.file_type = file_type + self.library: Library = library + self.file_type: str = file_type self.design_units = [] self._content_hash = None self._compile_options = {} + self._global_compile_options = {} # The file name before preprocessing self.original_name = name @@ -74,6 +75,7 @@ def set_compile_option(self, name, value): """ Set compile option """ + from vunit.sim_if.factory import SIMULATOR_FACTORY SIMULATOR_FACTORY.check_compile_option(name, value) self._compile_options[name] = copy(value) @@ -81,6 +83,7 @@ def add_compile_option(self, name, value): """ Add compile option """ + from vunit.sim_if.factory import SIMULATOR_FACTORY SIMULATOR_FACTORY.check_compile_option(name, value) if name not in self._compile_options: @@ -88,28 +91,41 @@ def add_compile_option(self, name, value): else: self._compile_options[name] += value + def set_global_compile_options(self, global_options: Dict): + self._global_compile_options = global_options + @property def compile_options(self): return self._compile_options - def get_compile_option(self, name): + def get_compile_option(self, name, include_global=True): """ Return a copy of the compile option list """ + from vunit.sim_if.factory import SIMULATOR_FACTORY SIMULATOR_FACTORY.check_compile_option_name(name) if name not in self._compile_options: self._compile_options[name] = [] - return copy(self._compile_options[name]) + if include_global and name in self._global_compile_options: + return copy(self._compile_options[name] + self._global_compile_options[name]) + else: + return copy(self._compile_options[name]) - def _compile_options_hash(self): + def _compile_options_hash(self, include_global=True): """ Compute hash of compile options Needs to be updated if there are nested dictionaries """ - return hash_string(repr(sorted(self._compile_options.items()))) + if include_global: + return hash_string( + repr(sorted(self._compile_options.items())) + + repr(sorted(self._global_compile_options.items())) + ) + else: + return hash_string(repr(sorted(self._compile_options.items()))) @property def content_hash(self): diff --git a/vunit/ui/__init__.py b/vunit/ui/__init__.py index 67e22a6ec..848449e2d 100644 --- a/vunit/ui/__init__.py +++ b/vunit/ui/__init__.py @@ -16,7 +16,8 @@ import logging import json import os -from typing import Optional, Set, Union +from copy import copy +from typing import Optional, Set, Union, Dict from pathlib import Path from fnmatch import fnmatch @@ -54,6 +55,7 @@ class VUnit(object): # pylint: disable=too-many-instance-attributes, too-many-p from vunit import VUnit """ + _global_compile_options : Dict @classmethod def from_argv( @@ -190,6 +192,7 @@ def test_filter(name, attribute_names): """ ) print(hline) + self._global_compile_options = {} def _create_database(self): """ @@ -489,6 +492,26 @@ def add_compile_option(self, name: str, value: str, allow_empty: Optional[bool] for source_file in check_not_empty(source_files, allow_empty, "No source files found"): source_file.add_compile_option(name, value) + + def set_global_compile_options(self, name: str, value: str, allow_empty: Optional[bool] = False): + self._global_compile_options[name] = copy(value) + + source_files = self._project.get_source_files_in_order() + for source_file in check_not_empty(source_files, allow_empty, "No source files found"): + source_file.set_global_compile_options(self._global_compile_options) + + + def add_global_compile_options(self, name: str, value: str, allow_empty: Optional[bool] = False): + if name not in self._global_compile_options: + self._global_compile_options[name] = copy(value) + else: + self._global_compile_options[name] += value + + source_files = self._project.get_source_files_in_order() + for source_file in check_not_empty(source_files, allow_empty, "No source files found"): + source_file.set_global_compile_options(self._global_compile_options) + + def get_source_file(self, file_name: Union[str, Path], library_name: Optional[str] = None): """ Get a source file @@ -795,6 +818,11 @@ def _main_run(self, post_run): Main with running tests """ simulator_if = self._create_simulator_if() + try: + simulator_if.set_global_compile_options(self._global_compile_options) + except Exception as e: + pass + test_list = self._create_tests(simulator_if) self._compile(simulator_if) print() diff --git a/vunit/ui/source.py b/vunit/ui/source.py index 8244034ee..5eaf87f14 100644 --- a/vunit/ui/source.py +++ b/vunit/ui/source.py @@ -7,6 +7,7 @@ """ UI classes SourceFile and SourceFileList """ +from typing import Dict from .. import ostools @@ -15,9 +16,11 @@ class SourceFileList(list): """ A list of :class:`.SourceFile` """ + _global_compile_options : Dict def __init__(self, source_files): list.__init__(self, source_files) + self._global_compile_options = {} def set_compile_option(self, name, value): """ @@ -45,6 +48,11 @@ def add_compile_option(self, name, value): for source_file in self: source_file.add_compile_option(name, value) + def set_global_compile_options(self, global_options: Dict): + self._global_compile_options = global_options + for source_file in self: + source_file.set_global_compile_options(global_options) + def add_dependency_on(self, source_file): """ Add manual dependency of these files on other file(s) @@ -66,11 +74,13 @@ class SourceFile(object): """ A single file """ + _global_compile_options : Dict def __init__(self, source_file, project, ui): self._source_file = source_file self._project = project self._ui = ui + self._global_compile_options = {} @property def name(self): @@ -129,6 +139,12 @@ def get_compile_option(self, name): """ return self._source_file.get_compile_option(name) + def set_global_compile_options(self, global_options: Dict): + self._global_compile_options = global_options + + def get_global_compile_options(self): + return self._global_compile_options + def add_dependency_on(self, source_file): """ Add manual dependency of this file other file(s) diff --git a/vunit/verilog/check/test/check_tb.sv b/vunit/verilog/check/test/check_tb.sv index 18501fc6e..08482c030 100644 --- a/vunit/verilog/check/test/check_tb.sv +++ b/vunit/verilog/check/test/check_tb.sv @@ -43,6 +43,10 @@ module check_tb; begin $sformat(err_msg, "CHECK_EQUAL_ERROR: Failure message not as expected.\n RECV: |%f|\n EXP: |%f|\n", actual, expected); $error(err_msg); + `ifdef XCELIUM + $finish(1); + `else + `endif end; endfunction; `TEST_SUITE begin diff --git a/vunit/verilog/include/vunit_defines.svh b/vunit/verilog/include/vunit_defines.svh index 651f08882..a86d0ba2a 100644 --- a/vunit/verilog/include/vunit_defines.svh +++ b/vunit/verilog/include/vunit_defines.svh @@ -26,7 +26,13 @@ `define TEST_CASE_SETUP if (__runner__.is_test_case_setup()) `define TEST_CASE_CLEANUP if (__runner__.is_test_case_cleanup()) -`define __ERROR_FUNC(msg) $error(msg) + +`ifdef XCELIUM + `define __ERROR_FUNC(msg) $error(msg); $finish(1) +`else + `define __ERROR_FUNC(msg) $error(msg) +`endif + `define CREATE_ARG_STRING(arg, arg_str) \ $swrite(arg_str, arg); \ for (int i=0; i