class VUnit(object): # pylint: disable=too-many-instance-attributes, too-many-public-methods """ The public interface of VUnit """ @classmethod def from_argv(cls, argv=None, compile_builtins=True): """ Create VUnit instance from command line arguments Can take arguments from 'argv' if not None instead of sys.argv """ args = VUnitCLI().parse_args(argv=argv) return cls.from_args(args, compile_builtins=compile_builtins) @classmethod def from_args(cls, args, compile_builtins=True): """ Create VUnit instance from args namespace """ def test_filter(name): return any(fnmatch(name, pattern) for pattern in args.test_patterns) return cls(output_path=args.output_path, clean=args.clean, vhdl_standard=select_vhdl_standard(), use_debug_codecs=args.use_debug_codecs, no_color=args.no_color, verbose=args.verbose, xunit_xml=args.xunit_xml, log_level=args.log_level, test_filter=test_filter, list_only=args.list, compile_only=args.compile, elaborate_only=args.elaborate, compile_builtins=compile_builtins, simulator_factory=SimulatorFactory(args), num_threads=args.num_threads, exit_0=args.exit_0) def __init__(self, # pylint: disable=too-many-locals, too-many-arguments output_path, simulator_factory, clean=False, use_debug_codecs=False, no_color=False, verbose=False, xunit_xml=None, log_level="warning", test_filter=None, list_only=False, compile_only=False, elaborate_only=False, vhdl_standard='2008', compile_builtins=True, num_threads=1, exit_0=False): self._configure_logging(log_level) self._output_path = output_path if no_color: self._printer = NO_COLOR_PRINTER else: self._printer = COLOR_PRINTER self._verbose = verbose self._xunit_xml = xunit_xml self._test_filter = test_filter if test_filter is not None else lambda name: True self._list_only = list_only self._compile_only = compile_only self._vhdl_standard = vhdl_standard self._tb_filter = tb_filter self._configuration = TestConfiguration(elaborate_only=elaborate_only) self._external_preprocessors = [] self._location_preprocessor = None self._check_preprocessor = None self._use_debug_codecs = use_debug_codecs self._simulator_factory = simulator_factory self._create_output_path(clean) self._project = None self._create_project() self._num_threads = num_threads self._exit_0 = exit_0 if compile_builtins: self.add_builtins(library_name="vunit_lib") def _create_project(self): """ Create Project instance """ database = self._create_database() self._project = Project( vhdl_parser=CachedVHDLParser(database=database), depend_on_package_body=self._simulator_factory.package_users_depend_on_bodies()) def _create_database(self): """ Create a persistent database to store expensive parse results Check for Python version used to create the database is the same as the running python instance or re-create """ project_database_file_name = join(self._output_path, "project_database") create_new = False key = b"version" version = str((4, sys.version)).encode() database = None try: database = DataBase(project_database_file_name) create_new = (key not in database) or (database[key] != version) except KeyboardInterrupt: raise except: # pylint: disable=bare-except traceback.print_exc() create_new = True if create_new: database = DataBase(project_database_file_name, new=True) database[key] = version return PickledDataBase(database) @staticmethod def _configure_logging(log_level): """ Configure logging based on log_level string """ level = getattr(logging, log_level.upper()) logging.basicConfig(filename=None, format='%(levelname)7s - %(message)s', level=level) def add_external_library(self, library_name, path): """ Add external black box library """ self._project.add_library(library_name, abspath(path), is_external=True) return self._create_library_facade(library_name) def add_library(self, library_name): """ Add vunit managed white box library """ path = join(self._simulator_factory.simulator_output_path, "libraries", library_name) self._project.add_library(library_name, abspath(path)) return self._create_library_facade(library_name) def library(self, library_name): """ Get reference to library """ if not self._project.has_library(library_name): raise KeyError(library_name) return self._create_library_facade(library_name) def _create_library_facade(self, library_name): """ Create a Library object to be exposed to users """ return LibraryFacade(library_name, self, self._project, self._configuration) def set_generic(self, name, value): """ Globally set generic """ self._configuration.set_generic(name.lower(), value, scope=create_scope()) def set_parameter(self, name, value): """ Globally set parameter """ self.set_generic(name, value) def set_sim_option(self, name, value): """ Globally set simulation option """ self._configuration.set_sim_option(name, value, scope=create_scope()) def set_pli(self, value): """ Globally set pli """ self._configuration.set_pli(value, scope=create_scope()) def disable_ieee_warnings(self): """ Globally disable ieee warnings """ self._configuration.disable_ieee_warnings(scope=create_scope()) def add_source_files(self, pattern, library_name, preprocessors=None, include_dirs=None): """ Add source files matching wildcard pattern to library """ for file_name in glob(pattern): self.add_source_file(file_name, library_name, preprocessors, include_dirs) def add_source_file(self, file_name, library_name, preprocessors=None, include_dirs=None): """ Add source file to library """ file_type = file_type_of(file_name) if file_type == "verilog": include_dirs = include_dirs if include_dirs is not None else [] add_verilog_include_dir(include_dirs) file_name = self._preprocess(library_name, abspath(file_name), preprocessors) self._project.add_source_file(file_name, library_name, file_type=file_type, include_dirs=include_dirs) def _preprocess(self, library_name, file_name, preprocessors): """ Preprocess file_name within library_name using explicit preprocessors if preprocessors is None then use implicit globally defined processors """ # @TODO dependency checking etc... if preprocessors is None: preprocessors = [self._location_preprocessor, self._check_preprocessor] preprocessors = [p for p in preprocessors if p is not None] preprocessors = self._external_preprocessors + preprocessors if len(preprocessors) == 0: return file_name code = ostools.read_file(file_name) for preprocessor in preprocessors: code = preprocessor.run(code, basename(file_name)) pp_file_name = join(self._preprocessed_path, library_name, basename(file_name)) idx = 1 while ostools.file_exists(pp_file_name): LOGGER.debug("Preprocessed file exists '%s', adding prefix", pp_file_name) pp_file_name = join(self._preprocessed_path, library_name, "%i_%s" % (idx, basename(file_name))) idx += 1 ostools.write_file(pp_file_name, code) return pp_file_name def add_preprocessor(self, preprocessor): """ Add a custom preprocessor to be used on all files, must be called before adding any files """ self._external_preprocessors.append(preprocessor) def enable_location_preprocessing(self, additional_subprograms=None): """ Enable location preprocessing, must be called before adding any files """ preprocessor = LocationPreprocessor() if additional_subprograms is not None: for subprogram in additional_subprograms: preprocessor.add_subprogram(subprogram) self._location_preprocessor = preprocessor def enable_check_preprocessing(self): """ Enable check preprocessing, must be called before adding any files """ self._check_preprocessor = CheckPreprocessor() def main(self): """ Run vunit main function and exit with code """ try: all_ok = self._main() except KeyboardInterrupt: exit(1) except CompileError: exit(1) except TestScannerError: exit(1) except: # pylint: disable=bare-except traceback.print_exc() exit(1) if (not all_ok) and (not self._exit_0): exit(1) exit(0) def _main(self): """ Base vunit main function without performing exit """ if self._list_only: return self._main_list_only() if self._compile_only: return self._main_compile_only() simulator_if = self._create_simulator_if() test_cases = self._create_tests(simulator_if) self._compile(simulator_if) start_time = ostools.get_time() report = TestReport(printer=self._printer) try: self._run_test(test_cases, report) simulator_if.post_process(self._simulator_factory.simulator_output_path) except KeyboardInterrupt: print() LOGGER.debug("_main: Caught Ctrl-C shutting down") finally: del test_cases del simulator_if report.set_real_total_time(ostools.get_time() - start_time) self._post_process(report) return report.all_ok() def _main_list_only(self): """ Main function when only listing test cases """ simulator_if = None test_suites = self._create_tests(simulator_if) num_tests = 0 for test_suite in test_suites: for name in test_suite.test_cases: print(name) num_tests += 1 print("Listed %i tests" % num_tests) return True def _main_compile_only(self): """ Main function when only compiling """ simulator_if = self._create_simulator_if() self._compile(simulator_if) return True def _create_output_path(self, clean): """ Create or re-create the output path if necessary """ if clean: ostools.renew_path(self._output_path) elif not exists(self._output_path): os.makedirs(self._output_path) ostools.renew_path(self._preprocessed_path) def _create_simulator_if(self): """ Create a simulator interface instance """ return self._simulator_factory.create() @property def vhdl_standard(self): return self._vhdl_standard @property def _preprocessed_path(self): return join(self._output_path, "preprocessed") @property def codecs_path(self): return join(self._output_path, "codecs") @property def use_debug_codecs(self): return self._use_debug_codecs def _create_tests(self, simulator_if): """ Create the test suites by scanning the project """ scanner = TestScanner(simulator_if, self._configuration) test_list = scanner.from_project(self._project, entity_filter=self._tb_filter) test_list.keep_matches(self._test_filter) return test_list def _compile(self, simulator_if): """ Compile entire project """ simulator_if.compile_project(self._project, self._vhdl_standard) def _run_test(self, test_cases, report): """ Run the test suites and return the report """ runner = TestRunner(report, join(self._output_path, "tests"), verbose=self._verbose, num_threads=self._num_threads) runner.run(test_cases) def _post_process(self, report): """ Print the report to stdout and optionally write it to an XML file """ report.print_str() if self._xunit_xml is not None: xml = report.to_junit_xml_str() ostools.write_file(self._xunit_xml, xml) def add_builtins(self, library_name="vunit_lib", mock_lang=False, mock_log=False): """ Add vunit VHDL builtin libraries """ library = self.add_library(library_name) add_vhdl_builtins(library, self._vhdl_standard, mock_lang, mock_log) def add_com(self, library_name="vunit_lib", use_debug_codecs=None): """ Add communication package """ if not self._project.has_library(library_name): library = self.add_library(library_name) else: library = self.library(library_name) if use_debug_codecs is not None: self._use_debug_codecs = use_debug_codecs add_com(library, self._vhdl_standard, use_debug_codecs=self._use_debug_codecs) def add_array_util(self, library_name="vunit_lib"): """ Add array utility package """ library = self.library(library_name) add_array_util(library, self._vhdl_standard) def add_osvvm(self, library_name="osvvm"): """ Add osvvm library """ if not self._project.has_library(library_name): library = self.add_library(library_name) else: library = self.library(library_name) add_osvvm(library) def get_project_compile_order(self, target=None): """ Get all project files in compile order. An optional target file may be specified causing only its direct and indirect dependencies to be included. """ if target is not None: target = abspath(target) return self._project.get_dependencies_in_compile_order(target=target)
class VUnit(object): # pylint: disable=too-many-instance-attributes, too-many-public-methods """ The public interface of VUnit :example: .. code-block:: python from vunit import VUnit """ @classmethod def from_argv(cls, argv=None, compile_builtins=True): """ Create VUnit instance from command line arguments. :param argv: Use explicit argv instead of actual command line argument :param compile_builtins: Do not compile builtins. Used for VUnit internal testing. :returns: A :class:`.VUnit` object instance :example: .. code-block:: python from vunit import VUnit prj = VUnit.from_argv() """ args = VUnitCLI().parse_args(argv=argv) return cls.from_args(args, compile_builtins=compile_builtins) @classmethod def from_args(cls, args, compile_builtins=True): """ Create VUnit instance from args namespace. Intended for users who adds custom command line options. See :class:`vunit.vunit_cli.VUnitCLI` class to learn about adding custom command line options. :param args: The parsed argument namespace object :param compile_builtins: Do not compile builtins. Used for VUnit internal testing. :returns: A :class:`.VUnit` object instance """ def test_filter(name): return any(fnmatch(name, pattern) for pattern in args.test_patterns) return cls(output_path=args.output_path, clean=args.clean, vhdl_standard=select_vhdl_standard(), use_debug_codecs=args.use_debug_codecs, no_color=args.no_color, verbose=args.verbose, xunit_xml=args.xunit_xml, log_level=args.log_level, test_filter=test_filter, list_only=args.list, list_files_only=args.files, compile_only=args.compile, keep_compiling=args.keep_compiling, elaborate_only=args.elaborate, compile_builtins=compile_builtins, simulator_factory=SimulatorFactory(args), num_threads=args.num_threads, exit_0=args.exit_0) def __init__(self, # pylint: disable=too-many-locals, too-many-arguments output_path, simulator_factory, clean=False, use_debug_codecs=False, no_color=False, verbose=False, xunit_xml=None, log_level="warning", test_filter=None, list_only=False, list_files_only=False, compile_only=False, keep_compiling=False, elaborate_only=False, vhdl_standard='2008', compile_builtins=True, num_threads=1, exit_0=False): self._configure_logging(log_level) self._elaborate_only = elaborate_only self._output_path = abspath(output_path) if no_color: self._printer = NO_COLOR_PRINTER else: self._printer = COLOR_PRINTER self._verbose = verbose self._xunit_xml = xunit_xml self._test_filter = test_filter if test_filter is not None else lambda name: True self._list_only = list_only self._list_files_only = list_files_only self._compile_only = compile_only self._keep_compiling = keep_compiling self._vhdl_standard = vhdl_standard self._tb_filter = tb_filter self._configuration = TestConfiguration() self._external_preprocessors = [] self._location_preprocessor = None self._check_preprocessor = None self._use_debug_codecs = use_debug_codecs self._simulator_factory = simulator_factory self._create_output_path(clean) self._project = None self._create_project() self._num_threads = num_threads self._exit_0 = exit_0 if compile_builtins: self.add_builtins(library_name="vunit_lib") def _create_project(self): """ Create Project instance """ database = self._create_database() self._project = Project( vhdl_parser=CachedVHDLParser(database=database), verilog_parser=VerilogParser(database=database), depend_on_package_body=self._simulator_factory.package_users_depend_on_bodies()) def _create_database(self): """ Create a persistent database to store expensive parse results Check for Python version used to create the database is the same as the running python instance or re-create """ project_database_file_name = join(self._output_path, "project_database") create_new = False key = b"version" version = str((6, sys.version)).encode() database = None try: database = DataBase(project_database_file_name) create_new = (key not in database) or (database[key] != version) except KeyboardInterrupt: raise except: # pylint: disable=bare-except traceback.print_exc() create_new = True if create_new: database = DataBase(project_database_file_name, new=True) database[key] = version return PickledDataBase(database) @staticmethod def _configure_logging(log_level): """ Configure logging based on log_level string """ level = getattr(logging, log_level.upper()) logging.basicConfig(filename=None, format='%(levelname)7s - %(message)s', level=level) def add_external_library(self, library_name, path): """ Add an externally compiled library as a black-box :param library_name: The name of the external library :param path: The path to the external library :returns: The created :class:`.Library` object :example: .. code-block:: python prj.add_external_library("unisim", "path/to/unisim/") """ self._project.add_library(library_name, abspath(path), is_external=True) return self._create_library_facade(library_name) def add_library(self, library_name): """ Add a library managed by VUnit. :param library_name: The name of the library :returns: The created :class:`.Library` object :example: .. code-block:: python library = prj.add_library("lib") """ path = join(self._simulator_factory.simulator_output_path, "libraries", library_name) self._project.add_library(library_name, abspath(path)) return self._create_library_facade(library_name) def library(self, library_name): """ Get a library :param library_name: The name of the library :returns: A :class:`.Library` object """ if not self._project.has_library(library_name): raise KeyError(library_name) return self._create_library_facade(library_name) def _create_library_facade(self, library_name): """ Create a Library object to be exposed to users """ return Library(library_name, self, self._project, self._configuration) def set_generic(self, name, value): """ Globally set a value of generic :param name: The name of the generic :param value: The value of the generic :example: .. code-block:: python prj.set_generic("data_width", 16) """ self._configuration.set_generic(name.lower(), value, scope=create_scope()) def set_parameter(self, name, value): """ Globally set value of parameter :param name: The name of the parameter :param value: The value of the parameter :example: .. code-block:: python prj.set_parameter("data_width", 16) """ self._configuration.set_generic(name, value, scope=create_scope()) def set_sim_option(self, name, value): """ Globally set simulation option :param name: |simulation_options| :param value: The value of the simulation option :example: .. code-block:: python prj.set_sim_option("ghdl.flags", ["--no-vital-checks"]) """ self._configuration.set_sim_option(name, value, scope=create_scope()) def set_compile_option(self, name, value): """ Globally set compile option :param name: |compile_option| :param value: The value of the compile option :example: .. code-block:: python prj.set_compile_option("ghdl.flags", ["--no-vital-checks"]) """ for source_file in self._project.get_source_files_in_order(): source_file.set_compile_option(name, value) def add_compile_option(self, name, value): """ Globally add compile option :param name: |compile_option| :param value: The value of the compile option """ for source_file in self._project.get_source_files_in_order(): source_file.add_compile_option(name, value) def set_pli(self, value): """ Globally Set pli :param value: A list of PLI object file names """ self._configuration.set_pli(value, scope=create_scope()) def disable_ieee_warnings(self): """ Globally disable ieee warnings """ self._configuration.disable_ieee_warnings(scope=create_scope()) def get_source_file(self, file_name, library_name=None): """ Get a source file :param file_name: The name of the file as a relative or absolute path :param library_name: The name of a specific library to search if not all libraries :returns: A :class:`.SourceFile` object """ files = self.get_source_files(file_name, library_name, allow_empty=True) if len(files) > 1: raise ValueError("Found file named '%s' in multiple-libraries, " "add explicit library_name." % file_name) elif len(files) == 0: if library_name is None: raise ValueError("Found no file named '%s'" % file_name) else: raise ValueError("Found no file named '%s' in library '%s'" % (file_name, library_name)) return files[0] def get_source_files(self, pattern="*", library_name=None, allow_empty=False): """ Get a list of source files :param pattern: A wildcard pattern matching either an absolute or relative path :param library_name: The name of a specific library to search if not all libraries :param allow_empty: To disable an error if no files matched the pattern :returns: A :class:`.SourceFileList` object """ results = [] for source_file in self._project.get_source_files_in_order(): if library_name is not None: if source_file.library.name != library_name: continue if not (fnmatch(abspath(source_file.name), pattern) or fnmatch(ostools.simplify_path(source_file.name), pattern)): continue results.append(SourceFile(source_file, self._project, self)) if (not allow_empty) and len(results) == 0: raise ValueError(("Pattern %r did not match any file. " "Use allow_empty=True to avoid exception,") % pattern) return SourceFileList(results) def add_source_files(self, # pylint: disable=too-many-arguments files, library_name, preprocessors=None, include_dirs=None, defines=None, allow_empty=False): """ Add source files matching wildcard pattern to library :param files: A wildcard pattern matching the files to add or a list of files :param library_name: The name of the library to add files into :param include_dirs: A list of include directories :param defines: A dictionary containing Verilog defines to be set :param allow_empty: To disable an error if no files matched the pattern :returns: A list of files (:class:`.SourceFileList`) which were added :example: .. code-block:: python prj.add_source_files("*.vhd", "lib") """ if _is_iterable_not_string(files): files = [files] file_names = [] for pattern in files: new_file_names = glob(pattern) if (not allow_empty) and len(new_file_names) == 0: raise ValueError(("Pattern %r did not match any file. " "Use allow_empty=True to avoid exception,") % pattern) file_names += new_file_names return SourceFileList(source_files=[ self.add_source_file(file_name, library_name, preprocessors, include_dirs, defines) for file_name in file_names]) def add_source_file(self, file_name, library_name, preprocessors=None, include_dirs=None, defines=None): """ Add source file to library :param file_name: The name of the file :param library_name: The name of the library to add the file into :param include_dirs: A list of include directories :param defines: A dictionary containing Verilog defines to be set :returns: The :class:`.SourceFile` which was added :example: .. code-block:: python prj.add_source_file("file.vhd", "lib") """ file_type = file_type_of(file_name) if file_type == "verilog": include_dirs = include_dirs if include_dirs is not None else [] include_dirs = add_verilog_include_dir(include_dirs) file_name = self._preprocess(library_name, abspath(file_name), preprocessors) return SourceFile(self._project.add_source_file(file_name, library_name, file_type=file_type, include_dirs=include_dirs, defines=defines), self._project, self) def _preprocess(self, library_name, file_name, preprocessors): """ Preprocess file_name within library_name using explicit preprocessors if preprocessors is None then use implicit globally defined processors """ # @TODO dependency checking etc... if preprocessors is None: preprocessors = [self._location_preprocessor, self._check_preprocessor] preprocessors = [p for p in preprocessors if p is not None] preprocessors = self._external_preprocessors + preprocessors if len(preprocessors) == 0: return file_name code = ostools.read_file(file_name) for preprocessor in preprocessors: code = preprocessor.run(code, basename(file_name)) pp_file_name = join(self._preprocessed_path, library_name, basename(file_name)) idx = 1 while ostools.file_exists(pp_file_name): LOGGER.debug("Preprocessed file exists '%s', adding prefix", pp_file_name) pp_file_name = join(self._preprocessed_path, library_name, "%i_%s" % (idx, basename(file_name))) idx += 1 ostools.write_file(pp_file_name, code) return pp_file_name def add_preprocessor(self, preprocessor): """ Add a custom preprocessor to be used on all files, must be called before adding any files """ self._external_preprocessors.append(preprocessor) def enable_location_preprocessing(self, additional_subprograms=None): """ Enable location preprocessing, must be called before adding any files """ preprocessor = LocationPreprocessor() if additional_subprograms is not None: for subprogram in additional_subprograms: preprocessor.add_subprogram(subprogram) self._location_preprocessor = preprocessor def enable_check_preprocessing(self): """ Enable check preprocessing, must be called before adding any files """ self._check_preprocessor = CheckPreprocessor() def main(self): """ Run vunit main function and exit """ try: all_ok = self._main() except KeyboardInterrupt: exit(1) except CompileError: exit(1) except TestScannerError: exit(1) except SystemExit: exit(1) except: # pylint: disable=bare-except traceback.print_exc() exit(1) if (not all_ok) and (not self._exit_0): exit(1) exit(0) def _main(self): """ Base vunit main function without performing exit """ if self._list_only: return self._main_list_only() if self._list_files_only: return self._main_list_files_only() if self._compile_only: return self._main_compile_only() simulator_if = self._create_simulator_if() test_cases = self._create_tests(simulator_if) self._compile(simulator_if) start_time = ostools.get_time() report = TestReport(printer=self._printer) try: self._run_test(test_cases, report) simulator_if.post_process(self._simulator_factory.simulator_output_path) except KeyboardInterrupt: print() LOGGER.debug("_main: Caught Ctrl-C shutting down") finally: del test_cases del simulator_if report.set_real_total_time(ostools.get_time() - start_time) self._post_process(report) return report.all_ok() def _main_list_only(self): """ Main function when only listing test cases """ simulator_if = None test_suites = self._create_tests(simulator_if) for test_suite in test_suites: for name in test_suite.test_cases: print(name) print("Listed %i tests" % test_suites.num_tests()) return True def _main_list_files_only(self): """ Main function when only listing files """ files = self.get_compile_order() for source_file in files: print("%s, %s" % (source_file.library.name, source_file.name)) print("Listed %i files" % len(files)) return True def _main_compile_only(self): """ Main function when only compiling """ simulator_if = self._create_simulator_if() self._compile(simulator_if) return True def _create_output_path(self, clean): """ Create or re-create the output path if necessary """ if clean: ostools.renew_path(self._output_path) elif not exists(self._output_path): os.makedirs(self._output_path) ostools.renew_path(self._preprocessed_path) def _create_simulator_if(self): """ Create a simulator interface instance """ return self._simulator_factory.create() @property def vhdl_standard(self): return self._vhdl_standard @property def _preprocessed_path(self): return join(self._output_path, "preprocessed") @property def codecs_path(self): return join(self._output_path, "codecs") @property def use_debug_codecs(self): return self._use_debug_codecs def _create_tests(self, simulator_if): """ Create the test suites by scanning the project """ scanner = TestScanner(simulator_if, self._configuration, elaborate_only=self._elaborate_only) test_list = scanner.from_project(self._project, entity_filter=self._tb_filter) if test_list.num_tests() == 0: LOGGER.warning("Test scanner found no test benches using current filter rule:\n%s", self._tb_filter.__doc__) test_list.keep_matches(self._test_filter) return test_list def _compile(self, simulator_if): """ Compile entire project """ simulator_if.compile_project(self._project, self._vhdl_standard, continue_on_error=self._keep_compiling) def _run_test(self, test_cases, report): """ Run the test suites and return the report """ runner = TestRunner(report, join(self._output_path, "tests"), verbose=self._verbose, num_threads=self._num_threads) runner.run(test_cases) def _post_process(self, report): """ Print the report to stdout and optionally write it to an XML file """ report.print_str() if self._xunit_xml is not None: xml = report.to_junit_xml_str() ostools.write_file(self._xunit_xml, xml) def add_builtins(self, library_name="vunit_lib", mock_lang=False, mock_log=False): """ Add vunit VHDL builtin libraries """ library = self.add_library(library_name) supports_context = self._simulator_factory.supports_vhdl_2008_contexts() add_vhdl_builtins(library, self._vhdl_standard, mock_lang, mock_log, supports_context=supports_context) def add_com(self, library_name="vunit_lib", use_debug_codecs=None): """ Add communication package :param use_debug_codecs: Use human readable debug codecs `None`: Use command line argument setting `False`: Never use debug codecs `True`: Always use debug codecs """ if not self._project.has_library(library_name): library = self.add_library(library_name) else: library = self.library(library_name) if use_debug_codecs is not None: self._use_debug_codecs = use_debug_codecs supports_context = self._simulator_factory.supports_vhdl_2008_contexts() add_com(library, self._vhdl_standard, use_debug_codecs=self._use_debug_codecs, supports_context=supports_context) def add_array_util(self, library_name="vunit_lib"): """ Add array utility package """ library = self.library(library_name) add_array_util(library, self._vhdl_standard) def add_osvvm(self, library_name="osvvm"): """ Add osvvm library """ if not self._project.has_library(library_name): library = self.add_library(library_name) else: library = self.library(library_name) add_osvvm(library) def get_compile_order(self, source_files=None): """ Get the compile order of all or specific source files and their dependencies :param source_files: A list of :class:`.SourceFile` objects or `None` meaing all :returns: A list of :class:`.SourceFile` objects in compile order. """ if source_files is None: source_files = self.get_source_files() target_files = [source_file._source_file # pylint: disable=protected-access for source_file in source_files] source_files = self._project.get_dependencies_in_compile_order(target_files) return SourceFileList([SourceFile(source_file, self._project, self) for source_file in source_files])
class TestTestConfiguration(unittest.TestCase): """ Test the global test bench configuration """ def setUp(self): self.cfg = TestConfiguration() self.output_path = out() renew_path(self.output_path) def test_has_default_configuration(self): scope = create_scope("lib", "tb_entity") self.assertEqual(self.cfg.get_configurations(scope), [cfg()]) def test_set_generic(self): scope = create_scope("lib", "tb_entity") self.assertEqual(self.cfg.get_configurations(scope), [cfg()]) self.cfg.set_generic("global_generic", "global", scope=create_scope()) self.assertEqual(self.cfg.get_configurations(scope), [cfg(generics={"global_generic": "global"})]) self.cfg.set_generic("global_generic", "library", scope=create_scope("lib")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(generics={"global_generic": "library"})]) self.cfg.set_generic("global_generic", "entity", scope=create_scope("lib", "tb_entity")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(generics={"global_generic": "entity"})]) def test_set_pli(self): scope = create_scope("lib", "tb_entity") self.assertEqual(self.cfg.get_configurations(scope), [cfg("")]) self.cfg.set_pli(["libglobal.so"], scope=create_scope()) self.cfg.set_pli(["libfoo.so"], scope=create_scope("lib2")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(pli=["libglobal.so"])]) self.cfg.set_pli(["libfoo.so"], scope=create_scope("lib")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(pli=["libfoo.so"])]) self.cfg.set_pli(["libfoo2.so"], scope=create_scope("lib", "tb_entity")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(pli=["libfoo2.so"])]) def test_add_config(self): for value in range(1, 3): self.cfg.add_config(scope=create_scope("lib", "tb_entity"), name="value=%i" % value, generics=dict(value=value, global_value="local value")) self.cfg.add_config(scope=create_scope("lib", "tb_entity", "configured test"), name="specific_test_config", generics=dict()) # Local value should take precedence self.cfg.set_generic("global_value", "global value") self.assertEqual( self.cfg.get_configurations(create_scope("lib", "tb_entity")), [ cfg("value=1", generics={ "value": 1, "global_value": "local value" }), cfg("value=2", generics={ "value": 2, "global_value": "local value" }) ]) self.assertEqual( self.cfg.get_configurations( create_scope("lib", "tb_entity", "test")), [ cfg("value=1", generics={ "value": 1, "global_value": "local value" }), cfg("value=2", generics={ "value": 2, "global_value": "local value" }) ]) self.assertEqual( self.cfg.get_configurations( create_scope("lib", "tb_entity", "configured test")), [cfg("specific_test_config", dict(global_value="global value"))]) def test_disable_ieee_warnings(self): lib_scope = create_scope("lib") ent_scope = create_scope("lib", "entity") self.assertEqual(self.cfg.get_configurations(lib_scope), [cfg(disable_ieee_warnings=False)]) self.assertEqual(self.cfg.get_configurations(ent_scope), [cfg(disable_ieee_warnings=False)]) self.cfg.disable_ieee_warnings(ent_scope) self.assertEqual(self.cfg.get_configurations(lib_scope), [cfg(disable_ieee_warnings=False)]) self.assertEqual(self.cfg.get_configurations(ent_scope), [cfg(disable_ieee_warnings=True)]) self.cfg.disable_ieee_warnings(lib_scope) self.assertEqual(self.cfg.get_configurations(lib_scope), [cfg(disable_ieee_warnings=True)]) self.assertEqual(self.cfg.get_configurations(ent_scope), [cfg(disable_ieee_warnings=True)]) def test_more_specific_configurations(self): self.cfg.set_generic("name", "value", scope=create_scope("lib", "entity3")) self.cfg.set_generic("name", "value", scope=create_scope("lib", "entity", "test")) self.cfg.disable_ieee_warnings( scope=create_scope("lib", "entity_ieee", "test")) self.cfg.add_config(name="name", generics=dict(), scope=create_scope("lib", "entity2", "test")) self.cfg.set_sim_option("ghdl.flags", [], scope=create_scope("lib", "entity4", "test")) self.assertEqual( self.cfg.more_specific_configurations(create_scope( "lib", "entity")), [create_scope("lib", "entity", "test")]) self.assertEqual( self.cfg.more_specific_configurations( create_scope("lib", "entity2")), [create_scope("lib", "entity2", "test")]) self.assertEqual( self.cfg.more_specific_configurations( create_scope("lib", "entity3")), []) self.assertEqual( self.cfg.more_specific_configurations( create_scope("lib", "entity4")), [create_scope("lib", "entity4", "test")]) self.assertEqual( self.cfg.more_specific_configurations( create_scope("lib", "entity_ieee")), [create_scope("lib", "entity_ieee", "test")]) def test_config_with_post_check(self): scope = create_scope("lib", "entity") def post_check(): return True self.cfg.add_config(name="name", generics=dict(), post_check=post_check, scope=scope) self.assertEqual(self.cfg.get_configurations(scope), [cfg("name", post_check=post_check)]) def test_config_with_pre_config(self): scope = create_scope("lib", "entity") def pre_config(): return True self.cfg.add_config(name="name", generics=dict(), pre_config=pre_config, scope=scope) self.assertEqual(self.cfg.get_configurations(scope), [cfg("name", pre_config=pre_config)]) def test_sim_options(self): scope = create_scope("lib", "entity") sim_options = {"modelsim.vsim_flags": "-voptargs=+acc"} for name, value in sim_options.items(): self.cfg.set_sim_option(name=name, value=value, scope=scope) self.assertEqual(self.cfg.get_configurations(create_scope("lib")), [cfg()]) self.assertEqual(self.cfg.get_configurations(scope), [cfg(sim_options=sim_options)]) self.assertEqual( self.cfg.get_configurations(create_scope("lib", "entity", "test")), [cfg(sim_options=sim_options)]) def test_fail_on_unknown_sim_option(self): self.assertRaises(ValueError, self.cfg.set_sim_option, "unknown", "value") def test_issue_65(self): self.cfg.set_generic(name="name", value=1, scope=create_scope()) self.cfg.set_sim_option(name="modelsim.vsim_flags", value="-quiet", scope=create_scope()) @staticmethod def write_file(name, contents): with open(name, "w") as fwrite: fwrite.write(contents)
class TestTestConfiguration(unittest.TestCase): """ Test the global test bench configuration """ def setUp(self): self.cfg = TestConfiguration() self.output_path = out() renew_path(self.output_path) def test_has_default_configuration(self): scope = create_scope("lib", "tb_entity") self.assertEqual(self.cfg.get_configurations(scope), [cfg()]) def test_set_generic(self): scope = create_scope("lib", "tb_entity") self.assertEqual(self.cfg.get_configurations(scope), [cfg()]) self.cfg.set_generic("global_generic", "global", scope=create_scope()) self.assertEqual(self.cfg.get_configurations(scope), [cfg(generics={"global_generic": "global"})]) self.cfg.set_generic("global_generic", "library", scope=create_scope("lib")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(generics={"global_generic": "library"})]) self.cfg.set_generic("global_generic", "entity", scope=create_scope("lib", "tb_entity")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(generics={"global_generic": "entity"})]) def test_set_pli(self): scope = create_scope("lib", "tb_entity") self.assertEqual(self.cfg.get_configurations(scope), [cfg("")]) self.cfg.set_pli(["libglobal.so"], scope=create_scope()) self.cfg.set_pli(["libfoo.so"], scope=create_scope("lib2")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(pli=["libglobal.so"])]) self.cfg.set_pli(["libfoo.so"], scope=create_scope("lib")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(pli=["libfoo.so"])]) self.cfg.set_pli(["libfoo2.so"], scope=create_scope("lib", "tb_entity")) self.assertEqual(self.cfg.get_configurations(scope), [cfg(pli=["libfoo2.so"])]) def test_add_config(self): for value in range(1, 3): self.cfg.add_config(scope=create_scope("lib", "tb_entity"), name="value=%i" % value, generics=dict(value=value, global_value="local value")) self.cfg.add_config(scope=create_scope("lib", "tb_entity", "configured test"), name="specific_test_config", generics=dict()) # Local value should take precedence self.cfg.set_generic("global_value", "global value") self.assertEqual(self.cfg.get_configurations(create_scope("lib", "tb_entity")), [cfg("value=1", generics={"value": 1, "global_value": "local value"}), cfg("value=2", generics={"value": 2, "global_value": "local value"})]) self.assertEqual(self.cfg.get_configurations(create_scope("lib", "tb_entity", "test")), [cfg("value=1", generics={"value": 1, "global_value": "local value"}), cfg("value=2", generics={"value": 2, "global_value": "local value"})]) self.assertEqual(self.cfg.get_configurations(create_scope("lib", "tb_entity", "configured test")), [cfg("specific_test_config", dict(global_value="global value"))]) def test_disable_ieee_warnings(self): lib_scope = create_scope("lib") ent_scope = create_scope("lib", "entity") self.assertEqual(self.cfg.get_configurations(lib_scope), [cfg(disable_ieee_warnings=False)]) self.assertEqual(self.cfg.get_configurations(ent_scope), [cfg(disable_ieee_warnings=False)]) self.cfg.disable_ieee_warnings(ent_scope) self.assertEqual(self.cfg.get_configurations(lib_scope), [cfg(disable_ieee_warnings=False)]) self.assertEqual(self.cfg.get_configurations(ent_scope), [cfg(disable_ieee_warnings=True)]) self.cfg.disable_ieee_warnings(lib_scope) self.assertEqual(self.cfg.get_configurations(lib_scope), [cfg(disable_ieee_warnings=True)]) self.assertEqual(self.cfg.get_configurations(ent_scope), [cfg(disable_ieee_warnings=True)]) def test_more_specific_configurations(self): self.cfg.set_generic("name", "value", scope=create_scope("lib", "entity3")) self.cfg.set_generic("name", "value", scope=create_scope("lib", "entity", "test")) self.cfg.disable_ieee_warnings(scope=create_scope("lib", "entity_ieee", "test")) self.cfg.add_config(name="name", generics=dict(), scope=create_scope("lib", "entity2", "test")) self.cfg.set_sim_option("vsim_extra_args", "", scope=create_scope("lib", "entity4", "test")) self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity")), [create_scope("lib", "entity", "test")]) self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity2")), [create_scope("lib", "entity2", "test")]) self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity3")), []) self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity4")), [create_scope("lib", "entity4", "test")]) self.assertEqual(self.cfg.more_specific_configurations(create_scope("lib", "entity_ieee")), [create_scope("lib", "entity_ieee", "test")]) def test_no_post_check_when_elaborate_only(self): self.cfg = TestConfiguration(elaborate_only=True) scope = create_scope("lib", "entity") def pre_config(): return True def post_check(): return True self.cfg.add_config(name="name", generics=dict(), pre_config=pre_config, post_check=post_check, scope=scope) self.assertEqual(self.cfg.get_configurations(scope), [cfg("name", pre_config=pre_config, elaborate_only=True)]) def test_config_with_post_check(self): scope = create_scope("lib", "entity") def post_check(): return True self.cfg.add_config(name="name", generics=dict(), post_check=post_check, scope=scope) self.assertEqual(self.cfg.get_configurations(scope), [cfg("name", post_check=post_check)]) def test_config_with_pre_config(self): scope = create_scope("lib", "entity") def pre_config(): return True self.cfg.add_config(name="name", generics=dict(), pre_config=pre_config, scope=scope) self.assertEqual(self.cfg.get_configurations(scope), [cfg("name", pre_config=pre_config)]) def test_sim_options(self): scope = create_scope("lib", "entity") sim_options = {"vsim_extra_args": "-voptargs=+acc"} for name, value in sim_options.items(): self.cfg.set_sim_option(name=name, value=value, scope=scope) self.assertEqual(self.cfg.get_configurations(create_scope("lib")), [cfg()]) self.assertEqual(self.cfg.get_configurations(scope), [cfg(sim_options=sim_options)]) self.assertEqual(self.cfg.get_configurations(create_scope("lib", "entity", "test")), [cfg(sim_options=sim_options)]) def test_fail_on_unknown_sim_option(self): self.assertRaises(ValueError, self.cfg.set_sim_option, "unknown", "value") def test_issue_65(self): self.cfg.set_generic(name="name", value=1, scope=create_scope()) self.cfg.set_sim_option(name="vsim_extra_args", value="-quiet", scope=create_scope()) @staticmethod def write_file(name, contents): with open(name, "w") as fwrite: fwrite.write(contents)