././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3587027 cocotb-2.0.1/0000755000175100017510000000000015106070715012433 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/LICENSE0000644000175100017510000000304415106067236013445 0ustar00runnerrunnerCopyright cocotb contributors Copyright (c) 2013 Potential Ventures Ltd Copyright (c) 2013 SolarFlare Communications Inc All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/MANIFEST.in0000644000175100017510000000021315106067236014171 0ustar00runnerrunnerrecursive-include src/cocotb/share * recursive-include src/cocotb/_vendor * include README.md include LICENSE include cocotb_build_libs.py ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3587027 cocotb-2.0.1/PKG-INFO0000644000175100017510000000542015106070715013531 0ustar00runnerrunnerMetadata-Version: 2.4 Name: cocotb Version: 2.0.1 Summary: cocotb is a coroutine based cosimulation library for writing VHDL and Verilog testbenches in Python. Home-page: https://www.cocotb.org Author: Chris Higgs, Stuart Hodgson Maintainer: cocotb contributors Maintainer-email: cocotb@lists.librecores.org License: BSD-3-Clause Project-URL: Bug Tracker, https://github.com/cocotb/cocotb/issues Project-URL: Source Code, https://github.com/cocotb/cocotb Project-URL: Documentation, https://docs.cocotb.org Platform: any Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA) Classifier: Framework :: cocotb Requires-Python: >=3.6.2 Description-Content-Type: text/markdown License-File: LICENSE Requires-Dist: find_libpython Dynamic: author Dynamic: classifier Dynamic: description Dynamic: description-content-type Dynamic: home-page Dynamic: license Dynamic: license-file Dynamic: maintainer Dynamic: maintainer-email Dynamic: platform Dynamic: project-url Dynamic: requires-dist Dynamic: requires-python Dynamic: summary **cocotb** is a framework empowering users to write VHDL and Verilog testbenches in Python. [![Documentation Status](https://readthedocs.org/projects/cocotb/badge/?version=development)](https://docs.cocotb.org/en/stable/) [![CI](https://github.com/cocotb/cocotb/actions/workflows/build-test-dev.yml/badge.svg?branch=master)](https://github.com/cocotb/cocotb/actions/workflows/build-test-dev.yml) [![PyPI](https://img.shields.io/pypi/dm/cocotb.svg?label=PyPI%20downloads)](https://pypi.org/project/cocotb/) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/cocotb/cocotb) [![codecov](https://codecov.io/gh/cocotb/cocotb/branch/master/graph/badge.svg)](https://codecov.io/gh/cocotb/cocotb) * Check out the [tutorial](https://docs.cocotb.org/en/stable/quickstart.html) * Read the [docs](https://docs.cocotb.org/en/stable/) * Find more info in the [wiki](https://github.com/cocotb/cocotb/wiki) * Discover [useful extensions](https://github.com/cocotb/cocotb/wiki/Further-Resources#utility-libraries-and-frameworks) * Join the discussion in the [Gitter chat room](https://gitter.im/cocotb/Lobby) * [Ask a question](https://github.com/cocotb/cocotb/discussions) * [Raise a bug / request an enhancement](https://github.com/cocotb/cocotb/issues/new) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/README.md0000644000175100017510000000246015106067236013720 0ustar00runnerrunner**cocotb** is a framework empowering users to write VHDL and Verilog testbenches in Python. [![Documentation Status](https://readthedocs.org/projects/cocotb/badge/?version=development)](https://docs.cocotb.org/en/stable/) [![CI](https://github.com/cocotb/cocotb/actions/workflows/build-test-dev.yml/badge.svg?branch=master)](https://github.com/cocotb/cocotb/actions/workflows/build-test-dev.yml) [![PyPI](https://img.shields.io/pypi/dm/cocotb.svg?label=PyPI%20downloads)](https://pypi.org/project/cocotb/) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/cocotb/cocotb) [![codecov](https://codecov.io/gh/cocotb/cocotb/branch/master/graph/badge.svg)](https://codecov.io/gh/cocotb/cocotb) * Check out the [tutorial](https://docs.cocotb.org/en/stable/quickstart.html) * Read the [docs](https://docs.cocotb.org/en/stable/) * Find more info in the [wiki](https://github.com/cocotb/cocotb/wiki) * Discover [useful extensions](https://github.com/cocotb/cocotb/wiki/Further-Resources#utility-libraries-and-frameworks) * Join the discussion in the [Gitter chat room](https://gitter.im/cocotb/Lobby) * [Ask a question](https://github.com/cocotb/cocotb/discussions) * [Raise a bug / request an enhancement](https://github.com/cocotb/cocotb/issues/new) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/cocotb_build_libs.py0000755000175100017510000006655515106067236016476 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import distutils import logging import os import subprocess import sys import sysconfig import textwrap from distutils.ccompiler import get_default_compiler from distutils.file_util import copy_file from typing import List from setuptools import Extension from setuptools.command.build_ext import build_ext as _build_ext logger = logging.getLogger(__name__) cocotb_share_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), "src", "cocotb", "share") ) _base_warns = [ "-Wall", "-Wextra", "-Wcast-qual", "-Wwrite-strings", "-Wconversion", # -Wno-missing-field-initializers is required on GCC 4.x to prevent a # spurious warning `error: missing initializer for member ...` when # compiling `PyTypeObject type = {};` in `simulatormodule.cpp`. # (See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750.) This flag can be # removed once we require later GCC versions. "-Wno-missing-field-initializers", "-Werror=shadow", ] _ccx_warns = [*_base_warns, "-Wnon-virtual-dtor", "-Woverloaded-virtual"] _extra_cxx_compile_args = [ "-std=c++11", "-fvisibility=hidden", "-fvisibility-inlines-hidden", *_ccx_warns, ] if os.name != "nt": _extra_cxx_compile_args += ["-flto"] _extra_cxx_compile_args_msvc = ["/permissive-"] # Make PRI* format macros available with C++11 compiler but older libc, e.g. on RHEL6. _extra_defines = [("__STDC_FORMAT_MACROS", "")] def create_sxs_assembly_manifest( name: str, filename: str, libraries: List[str], dependency_only=False ) -> str: """ Create side-by-side (sxs) assembly manifest It contains dependencies to other assemblies (in our case the assemblies are equal to the other libraries). For more details see: - https://docs.microsoft.com/en-us/windows/win32/sbscs/assembly-manifests - https://docs.microsoft.com/en-us/windows/win32/sbscs/using-side-by-side-assemblies Args: name: The name of the assembly for which the manifest is generated, e.g. ``libcocotbutils``. filename: The filename of the library, e.g. ``libcocotbutils.dll``. libraries: A list of names of dependent manifests, e.g. ``["libgpilog"]``. """ architecture = "amd64" if sys.maxsize > 2**32 else "x86" dependencies = [] for lib in libraries: dependencies.append( textwrap.dedent( """\ """ ) % (lib, architecture) ) if not dependency_only: manifest_body = textwrap.dedent( """\ %s """ ) % ( name, architecture, filename, textwrap.indent("".join(dependencies), " ").strip(), ) else: manifest_body = textwrap.dedent( """\ %s """ ) % (textwrap.indent("".join(dependencies), " ").strip()) return manifest_body def create_sxs_appconfig(filename): """ Create side-by-side (sxs) application configuration file. The application configuration specifies additional search paths for manifests. For more details see: https://docs.microsoft.com/en-us/windows/win32/sbscs/application-configuration-files """ config_body = textwrap.dedent( """\ """ ) dirpath = os.path.dirname(filename) os.makedirs(dirpath, exist_ok=True) with open(filename + ".2.config", "w", encoding="utf-8") as f: f.write(config_body) def create_rc_file(rc_filename, name, filename, libraries, runtime_libraries): """ Creates windows resource definition script to embed the side-by-side assembly manifest into the libraries. For more details see: https://docs.microsoft.com/en-us/windows/win32/menurc/about-resource-files """ manifest = create_sxs_assembly_manifest(name, filename, libraries) # Escape double quotes and put every line between double quotes for embedding into rc file manifest = manifest.replace('"', '""') manifest = "\n".join([f'"{x}\\r\\n"' for x in manifest.splitlines()]) rc_body = ( textwrap.dedent( """\ #pragma code_page(65001) // UTF-8 #include LANGUAGE 0x00, 0x00 ISOLATIONAWARE_MANIFEST_RESOURCE_ID RT_MANIFEST BEGIN %s END """ ) % manifest ) if runtime_libraries is not None: manifest = create_sxs_assembly_manifest( name, filename, runtime_libraries, dependency_only=True ) # Escape double quotes and put every line between double quotes for embedding into rc file manifest = manifest.replace('"', '""') manifest = "\n".join([f'"{x}\\r\\n"' for x in manifest.splitlines()]) rc_body += ( textwrap.dedent( """\ 1000 RT_MANIFEST BEGIN %s END """ ) % manifest ) with open(rc_filename, "w", encoding="utf-8") as f: f.write(rc_body) def _get_lib_ext_name(): """Get name of default library file extension on given OS.""" if os.name == "nt": ext_name = "dll" else: ext_name = "so" return ext_name class build_ext(_build_ext): def _uses_msvc(self): if self.compiler == "msvc": return True if self.compiler is None: return get_default_compiler() == "msvc" else: return getattr(self.compiler, "compiler_type", None) == "msvc" def run(self): if os.name == "nt": create_sxs_appconfig( self.get_ext_fullpath(os.path.join("cocotb", "simulator")) ) super().run() def build_extensions(self): if os.name == "nt": if self._uses_msvc(): # Initialize the compiler now so that compiler/linker flags are populated if not self.compiler.initialized: self.compiler.initialize() # Setuptools defaults to activate automatic manifest generation for msvc, # disable it here as we manually generate it to also support mingw on windows for k, ldflags in self.compiler._ldflags.items(): self.compiler._ldflags[k] = [ x for x in ldflags if not x.startswith("/MANIFEST") ] + ["/MANIFEST:NO"] self.compiler.compile_options = [ x for x in self.compiler.compile_options if not x.startswith("/W") ] + ["/W4"] ext_names = {os.path.split(ext.name)[-1] for ext in self.extensions} for ext in self.extensions: fullname = self.get_ext_fullname(ext.name) filename = self.get_ext_filename(fullname) name = os.path.split(fullname)[-1] filename = os.path.split(filename)[-1] libraries = {"lib" + lib for lib in ext.libraries}.intersection( ext_names ) rc_filename = name + ".rc" runtime_libraries = None # Add the runtime dependency on libcocotb to libembed if name == "libembed": runtime_libraries = ["libcocotb"] # Strip lib prefix for msvc if self._uses_msvc(): name = name[3:] if name.startswith("lib") else name libraries = { (lib[3:] if lib.startswith("lib") else lib) for lib in libraries } if runtime_libraries is not None: runtime_libraries = { (lib[3:] if lib.startswith("lib") else lib) for lib in runtime_libraries } create_rc_file( rc_filename, name, filename, libraries, runtime_libraries ) def_dir = os.path.join(cocotb_share_dir, "def") self._gen_import_libs(def_dir) for e in self.extensions: e.library_dirs += [def_dir] super().build_extensions() def build_extension(self, ext): """Build each extension in its own temp directory to make gcov happy. A normal PEP 517 install still works as the temp directories are discarded anyway. """ lib_name = os.path.split(ext.name)[-1] if self._uses_msvc(): ext.extra_compile_args += _extra_cxx_compile_args_msvc else: ext.extra_compile_args += _extra_cxx_compile_args if os.name == "nt": # Align behavior of gcc with msvc and export only symbols marked with __declspec(dllexport) ext.extra_link_args += ["-Wl,--exclude-all-symbols"] else: ext.extra_link_args += ["-flto"] rpaths = [] if lib_name == "simulator": rpaths += ["$ORIGIN/libs"] install_name = None else: rpaths += ["$ORIGIN"] install_name = lib_name if sys.platform == "darwin": rpaths = [ rpath.replace("$ORIGIN", "@loader_path") for rpath in rpaths ] if install_name is not None: ext.extra_link_args += [ f"-Wl,-install_name,@rpath/{install_name}.so" ] if sys.platform == "linux": # Avoid a runtime dependency on libstdc++. Some simulators # ship a version of libstdc++6.so which is older than the # one cocotb has been compiled with, which will then lead to # load-time errors like "libstdc++.so.6: version # `GLIBCXX_3.4.29' not found (required by # /path/to/libcocotbvhpi_modelsim.so)." ext.extra_link_args += ["-static-libstdc++"] ext.extra_link_args += [f"-Wl,-rpath,{rpath}" for rpath in rpaths] # vpi_user.h and vhpi_user.h require that WIN32 is defined if os.name == "nt": ext.define_macros += [("WIN32", "")] if lib_name == "libembed": if self._uses_msvc(): embed_lib_name = "cocotb" else: embed_lib_name = "libcocotb" ext.define_macros += [ ("EMBED_IMPL_LIB", embed_lib_name + "." + _get_lib_ext_name()) ] old_build_temp = self.build_temp self.build_temp = os.path.join(self.build_temp, ext.name) super().build_extension(ext) self.build_temp = old_build_temp # Needed for Windows to not assume python module (generate interface in def file) def get_export_symbols(self, ext): return None # For proper cocotb library naming, based on https://github.com/cython/cython/issues/1740 def get_ext_filename(self, ext_name): """ Like the base class method, but for libraries that are not python extension: - removes the ``.cpython-36m-x86_64-linux-gnu.`` or ``-cpython-36m.`` part before the extension - replaces ``.pyd`` with ``.dll`` on windows. """ filename = _build_ext.get_ext_filename(self, ext_name) # for the simulator python extension library, leaving suffix in place if os.path.split(ext_name)[-1] == "simulator": return filename head, tail = os.path.split(filename) tail_split = tail.split(".") # mingw on msys2 uses `-` as separator tail_split = tail_split[0].split("-") # strip lib prefix if msvc is used if self._uses_msvc() and tail_split[0].startswith("lib"): tail_split[0] = tail_split[0][3:] filename_short = os.path.join(head, tail_split[0] + "." + _get_lib_ext_name()) # icarus requires vpl extension filename_short = filename_short.replace( "libcocotbvpi_icarus.so", "libcocotbvpi_icarus.vpl" ) filename_short = filename_short.replace( "libcocotbvpi_icarus.dll", "libcocotbvpi_icarus.vpl" ) filename_short = filename_short.replace( "cocotbvpi_icarus.dll", "cocotbvpi_icarus.vpl" ) return filename_short def finalize_options(self): """Like the base class method,but add extra library_dirs path.""" super().finalize_options() for ext in self.extensions: ext.library_dirs.append(os.path.join(self.build_lib, "cocotb", "libs")) def copy_extensions_to_source(self): """Like the base class method, but copy libs into proper directory in develop.""" build_py = self.get_finalized_command("build_py") for ext in self.extensions: fullname = self.get_ext_fullname(ext.name) filename = self.get_ext_filename(fullname) modpath = fullname.split(".") package = ".".join(modpath[:-1]) package_dir = build_py.get_package_dir(package) # unlike the method from `setuptools`, we do not call `os.path.basename` here dest_filename = os.path.join(package_dir, filename) src_filename = os.path.join(self.build_lib, filename) os.makedirs(os.path.dirname(dest_filename), exist_ok=True) copy_file( src_filename, dest_filename, verbose=self.verbose, dry_run=self.dry_run ) if ext._needs_stub: self.write_stub(package_dir or os.curdir, ext, True) def _gen_import_libs(self, def_dir): """ On Windows generate import libraries that contains the code required to load the DLL (.a) based on module definition files (.def) """ for sim in ["icarus", "modelsim", "aldec", "ghdl", "nvcvhpi"]: if self._uses_msvc(): subprocess.run( [ self.compiler.lib, "/def:" + os.path.join(def_dir, sim + ".def"), "/out:" + os.path.join(def_dir, sim + ".lib"), "/machine:" + ("X64" if sys.maxsize > 2**32 else "X86"), ], check=True, ) else: subprocess.run( [ "dlltool", "-d", os.path.join(def_dir, sim + ".def"), "-l", os.path.join(def_dir, "lib" + sim + ".a"), ], check=True, ) def _get_python_lib_link(): """Get name of python library used for linking""" if sys.platform == "darwin": ld_library = sysconfig.get_config_var("LIBRARY") else: ld_library = sysconfig.get_config_var("LDLIBRARY") if ld_library is not None: python_lib_link = os.path.splitext(ld_library)[0][3:] else: python_version = sysconfig.get_python_version().replace(".", "") python_lib_link = "python" + python_version return python_lib_link def _get_python_lib(): """Get the library for embedded the python interpreter""" if os.name == "nt": python_lib = _get_python_lib_link() + "." + _get_lib_ext_name() elif sys.platform == "darwin": python_lib = os.path.join( sysconfig.get_config_var("LIBDIR"), "lib" + _get_python_lib_link() + "." ) if os.path.exists(python_lib + "dylib"): python_lib += "dylib" else: python_lib += "so" else: python_lib = "lib" + _get_python_lib_link() + "." + _get_lib_ext_name() return python_lib def _get_common_lib_ext(include_dirs, share_lib_dir): """ Defines common libraries. All libraries go into the same directory to enable loading without modifying the library path (e.g. LD_LIBRARY_PATH). """ # # libcocotbutils # libcocotbutils_sources = [os.path.join(share_lib_dir, "utils", "cocotb_utils.cpp")] if os.name == "nt": libcocotbutils_sources += ["libcocotbutils.rc"] libcocotbutils_libraries = ["gpilog"] if sys.platform.startswith(("linux", "darwin", "cygwin", "msys")): libcocotbutils_libraries.append("dl") # dlopen, dlerror, dlsym libcocotbutils = Extension( os.path.join("cocotb", "libs", "libcocotbutils"), define_macros=[("COCOTBUTILS_EXPORTS", ""), *_extra_defines], include_dirs=include_dirs, libraries=libcocotbutils_libraries, sources=libcocotbutils_sources, ) # # libgpilog # python_lib_dirs = [] if sys.platform == "darwin": python_lib_dirs = [sysconfig.get_config_var("LIBDIR")] libgpilog_sources = [os.path.join(share_lib_dir, "gpi_log", "gpi_logging.cpp")] if os.name == "nt": libgpilog_sources += ["libgpilog.rc"] libgpilog = Extension( os.path.join("cocotb", "libs", "libgpilog"), define_macros=[("GPILOG_EXPORTS", ""), *_extra_defines], include_dirs=include_dirs, sources=libgpilog_sources, ) # # libpygpilog # libpygpilog_sources = [ os.path.join(share_lib_dir, "py_gpi_log", "py_gpi_logging.cpp") ] if os.name == "nt": libpygpilog_sources += ["libpygpilog.rc"] libpygpilog = Extension( os.path.join("cocotb", "libs", "libpygpilog"), define_macros=[("PYGPILOG_EXPORTS", ""), *_extra_defines], include_dirs=include_dirs, libraries=["gpilog"], sources=libpygpilog_sources, ) # # libembed # libembed_sources = [os.path.join(share_lib_dir, "embed", "embed.cpp")] if os.name == "nt": libembed_sources += ["libembed.rc"] libembed = Extension( os.path.join("cocotb", "libs", "libembed"), define_macros=[ ("COCOTB_EMBED_EXPORTS", ""), ("PYTHON_LIB", _get_python_lib()), *_extra_defines, ], include_dirs=include_dirs, libraries=["gpilog", "cocotbutils"], sources=libembed_sources, ) # # libcocotb # libcocotb_sources = [os.path.join(share_lib_dir, "embed", "gpi_embed.cpp")] if os.name == "nt": libcocotb_sources += ["libcocotb.rc"] libcocotb = Extension( os.path.join("cocotb", "libs", "libcocotb"), define_macros=_extra_defines, include_dirs=include_dirs, libraries=["gpilog", "cocotbutils", "pygpilog", "gpi"], sources=libcocotb_sources, ) # # libgpi # libgpi_sources = [ os.path.join(share_lib_dir, "gpi", "GpiCbHdl.cpp"), os.path.join(share_lib_dir, "gpi", "GpiCommon.cpp"), ] if os.name == "nt": libgpi_sources += ["libgpi.rc"] libgpi = Extension( os.path.join("cocotb", "libs", "libgpi"), define_macros=[ ("GPI_EXPORTS", ""), ("LIB_EXT", _get_lib_ext_name()), ("SINGLETON_HANDLES", ""), *_extra_defines, ], include_dirs=include_dirs, libraries=["cocotbutils", "gpilog", "embed"], sources=libgpi_sources, ) # # simulator # simulator_sources = [ os.path.join(share_lib_dir, "simulator", "simulatormodule.cpp"), ] if os.name == "nt": simulator_sources += ["simulator.rc"] libsim = Extension( os.path.join("cocotb", "simulator"), define_macros=_extra_defines, include_dirs=include_dirs, libraries=["cocotbutils", "gpilog", "gpi", "pygpilog"], library_dirs=python_lib_dirs, sources=simulator_sources, ) # The libraries in this list are compiled in order of their appearance. # If there is a linking dependency on one library to another, # the linked library must be built first. return [libgpilog, libpygpilog, libcocotbutils, libembed, libgpi, libcocotb, libsim] def _get_vpi_lib_ext( include_dirs, share_lib_dir, sim_define, extra_lib=[], extra_lib_dir=[] ): lib_name = "libcocotbvpi_" + sim_define.lower() libcocotbvpi_sources = [ os.path.join(share_lib_dir, "vpi", "VpiImpl.cpp"), os.path.join(share_lib_dir, "vpi", "VpiCbHdl.cpp"), os.path.join(share_lib_dir, "vpi", "VpiObj.cpp"), os.path.join(share_lib_dir, "vpi", "VpiIterator.cpp"), os.path.join(share_lib_dir, "vpi", "VpiSignal.cpp"), ] if os.name == "nt": libcocotbvpi_sources += [lib_name + ".rc"] libcocotbvpi = Extension( os.path.join("cocotb", "libs", lib_name), define_macros=[("COCOTBVPI_EXPORTS", ""), (sim_define, ""), *_extra_defines], include_dirs=include_dirs, libraries=["gpi", "gpilog", *extra_lib], library_dirs=extra_lib_dir, sources=libcocotbvpi_sources, ) return libcocotbvpi def _get_vhpi_lib_ext( include_dirs, share_lib_dir, sim_define, extra_lib=[], extra_lib_dir=[] ): lib_name = "libcocotbvhpi_" + sim_define.lower() libcocotbvhpi_sources = [ os.path.join(share_lib_dir, "vhpi", "VhpiImpl.cpp"), os.path.join(share_lib_dir, "vhpi", "VhpiCbHdl.cpp"), ] if os.name == "nt": libcocotbvhpi_sources += [lib_name + ".rc"] libcocotbvhpi = Extension( os.path.join("cocotb", "libs", lib_name), include_dirs=include_dirs, define_macros=[("COCOTBVHPI_EXPORTS", ""), (sim_define, ""), *_extra_defines], libraries=["gpi", "gpilog", *extra_lib], library_dirs=extra_lib_dir, sources=libcocotbvhpi_sources, ) return libcocotbvhpi def get_ext(): cfg_vars = distutils.sysconfig.get_config_vars() if sys.platform == "darwin": cfg_vars["LDSHARED"] = cfg_vars["LDSHARED"].replace("-bundle", "-dynamiclib") cfg_vars["LDCXXSHARED"] = cfg_vars["LDSHARED"].replace("-bundle", "-dynamiclib") share_lib_dir = os.path.relpath(os.path.join(cocotb_share_dir, "lib")) include_dirs = [ os.path.relpath(os.path.join(cocotb_share_dir, "include")), os.path.relpath(os.path.join(os.path.dirname(__file__), "src", "cocotb")), ] ext = [] logger.info("Compiling interface libraries for cocotb ...") ext += _get_common_lib_ext(include_dirs, share_lib_dir) # # Icarus Verilog # icarus_extra_lib = [] logger.info("Compiling libraries for Icarus Verilog") if os.name == "nt": icarus_extra_lib = ["icarus"] icarus_vpi_ext = _get_vpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="ICARUS", extra_lib=icarus_extra_lib, ) ext.append(icarus_vpi_ext) # # Modelsim/Questa # modelsim_extra_lib = [] logger.info("Compiling libraries for Modelsim/Questa") if os.name == "nt": modelsim_extra_lib = ["modelsim"] modelsim_vpi_ext = _get_vpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="MODELSIM", extra_lib=modelsim_extra_lib, ) ext.append(modelsim_vpi_ext) modelsim_vhpi_ext = _get_vhpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="MODELSIM", extra_lib=modelsim_extra_lib, ) ext.append(modelsim_vhpi_ext) lib_name = "libcocotbfli_modelsim" fli_sources = [ os.path.join(share_lib_dir, "fli", "FliImpl.cpp"), os.path.join(share_lib_dir, "fli", "FliCbHdl.cpp"), os.path.join(share_lib_dir, "fli", "FliObjHdl.cpp"), ] if os.name == "nt": fli_sources += [lib_name + ".rc"] fli_ext = Extension( os.path.join("cocotb", "libs", lib_name), define_macros=[("COCOTBFLI_EXPORTS", ""), *_extra_defines], include_dirs=include_dirs, libraries=["gpi", "gpilog", *modelsim_extra_lib], sources=fli_sources, ) ext.append(fli_ext) # # GHDL # ghdl_extra_lib = [] logger.info("Compiling libraries for GHDL") if os.name == "nt": ghdl_extra_lib = ["ghdl"] ghdl_vpi_ext = _get_vpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="GHDL", extra_lib=ghdl_extra_lib, ) ext.append(ghdl_vpi_ext) # # IUS # if os.name == "posix": logger.info("Compiling libraries for Incisive/Xcelium") ius_vpi_ext = _get_vpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="IUS" ) ext.append(ius_vpi_ext) ius_vhpi_ext = _get_vhpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="IUS" ) ext.append(ius_vhpi_ext) # # VCS # if os.name == "posix": logger.info("Compiling libraries for VCS") vcs_vpi_ext = _get_vpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="VCS" ) ext.append(vcs_vpi_ext) # # Aldec Riviera Pro # aldec_extra_lib = [] logger.info("Compiling libraries for Riviera") if os.name == "nt": aldec_extra_lib = ["aldec"] aldec_vpi_ext = _get_vpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="ALDEC", extra_lib=aldec_extra_lib, ) ext.append(aldec_vpi_ext) aldec_vhpi_ext = _get_vhpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="ALDEC", extra_lib=aldec_extra_lib, ) ext.append(aldec_vhpi_ext) # # Verilator # if os.name == "posix": logger.info("Compiling libraries for Verilator") verilator_vpi_ext = _get_vpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="VERILATOR", ) ext.append(verilator_vpi_ext) # # NVC # nvc_extra_lib = [] if os.name == "nt": nvc_extra_lib = ["nvcvhpi"] logger.info("Compiling libraries for NVC") nvc_vhpi_ext = _get_vhpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="NVC", extra_lib=nvc_extra_lib, ) ext.append(nvc_vhpi_ext) # # DSim # if os.name == "posix": logger.info("Compiling libraries for DSim") dsim_vpi_ext = _get_vpi_lib_ext( include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define="DSim" ) ext.append(dsim_vpi_ext) return ext ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/pyproject.toml0000644000175100017510000001377115106067236015364 0ustar00runnerrunner[build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" [tool.towncrier] package = "cocotb" directory = "docs/source/newsfragments" filename = "docs/source/release_notes.rst" issue_format = ":pr:`{issue}`" # The first underline is used for the version/date header, # the second underline for the subcategories (like 'Features') underlines = ["=", "-"] all_bullets = false [[tool.towncrier.type]] directory = "feature" name = "Features" showcontent = true [[tool.towncrier.type]] directory = "bugfix" name = "Bugfixes" showcontent = true [[tool.towncrier.type]] directory = "doc" name = "Improved Documentation" showcontent = true [[tool.towncrier.type]] directory = "removal" name = "Deprecations and Removals" showcontent = true [[tool.towncrier.type]] directory = "change" name = "Changes" showcontent = true [tool.ruff] extend-exclude = [ "docs/source/conf.py", "makefiles", "venv", "_vendor", ".nox/", ] target-version = "py37" [tool.ruff.format] docstring-code-format = true [tool.ruff.lint] extend-select = [ "I", # isort "UP", # pyupgrade "PL", # pylint "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "C4", # flake8-comprehension "LOG", # flake8-logging "G", # flake8-logging-format "ISC", # implicit string concat "TC", # flake8-typechecking "SIM103", # return the condition directly "SIM300", # yoda conditions "RUF100", # unused noqa "RUF101", # redirected noqa "RUF010", # explicit type conversion in f-string "RUF005", # collection literal concatenation "RUF022", # unsorted __all__ "PERF101", # unnecessary list cast "PERF102", # unnecessary dict.items() "B007", # unused loop variable "PYI030", # unnecessary literal union ] ignore = [ "E741", # ambiguous variable name (preference) "E501", # line too long (preference) "PLR0912", # Too many branches (>12) (preference) "PLR0913", # Too many arguments to function call (>5) (preference) "PLR0915", # Too many statements (>50) (preference) "PLR2004", # Magic value used in comparison (preference) "PLW0603", # Using the global statement (preference) "PLR0911", # Too many return statements (preference) "PLW1641", # __eq__ without __hash__ (mypy compatibility) "UP021", # subprocess.run() universal_newlines => text (not supported in 3.6) ] [tool.ruff.lint.per-file-ignores] # necessary because of how file is included into documentation "examples/doc_examples/quickstart/test_my_design.py" = [ "E402", "F811", ] [tool.ruff.lint.isort] known-first-party = [ "cocotb", "cocotb_tools", "pygpi", ] known-third-party = [ "pytest", ] [tool.cibuildwheel] # Build for supported platforms only. # Even though we only support 64 bit operating systems, we still support 32 bit # userspace applications (Python and simulators) on Windows and Linux. # # - CPython on Linux i686 and x86_64 with glibc # - CPython on Windows i686 and x86_64 # - CPython on macOS x86_64 build = "cp*-manylinux_x86_64 cp*-manylinux_i686 cp*-win_amd64 cp*-win32 cp*-macosx_x86_64 cp*-macosx_arm64" # Build with optimizations and debugging # -O2 Enables reasonable optimizations. -O3 is unnecessary with the virtual-call-heavy code in the GPI and may bloat binary size. # -g Generate standard debugging info. # -flto Enable LTO which can reduce binary size and improve inlining. environment = {CFLAGS = "-O2 -g -flto", CPPFLAGS = "-O2 -g -flto", LDFLAGS = "-O2 -g -flto"} # By default, build on manylinux2014 for compatibility with CentOS/RHEL 7+ (once # the user updates Python) and Ubuntu 20.04+ (with system Python). manylinux-x86_64-image = "manylinux2014" manylinux-i686-image = "manylinux2014" # Build with optimizations and debugging (Windows) # /O2 Enables reasonable optimizations. # /Z7 Enables debugging and places info in the binary (/Zi puts debug info in a different file). # /Zo Improves debugging when optimizations are also enabled. # /LTCG Enables LTO which can reduce binary size and improve inlining. [tool.cibuildwheel.windows] environment = {CL = "/O2 /Z7 /Zo /LTCG"} [[tool.cibuildwheel.overrides]] # Build CPython 3.6 wheels on manylinux1 to support Ubuntu 18.04, CentOS/RHEL 7 # and CentOS/RHEL 8 with their default Python 3.6/pip 9 installation. select = "cp36-*" manylinux-x86_64-image = "manylinux1" manylinux-i686-image = "manylinux1" [tool.pytest.ini_options] # Note: Do *not* add files within the cocotb/ tree here. Add them to the # noxfile instead. testpaths = [ "tests/pytest", ] # Ensure that all markers used in pytests are declared (in here). addopts = "--strict-markers" markers = [ "simulator_required: mark tests as needing a simulator", "compile: the compile step in runner-based tests", ] # log_cli = true # log_cli_level = DEBUG [tool.coverage.paths] source = [ "src/cocotb/", ".nox/**/cocotb/", ] [tool.coverage.report] omit = [ "*/cocotb_tools/*", "*/_vendor/*", ] exclude_lines = [ # copy-pasted from coveragepy source # TODO when we can move to a newer version of coverage "#\\s*(pragma|PRAGMA)[:\\s]?\\s*(no|NO)\\s*(cover|COVER)", "^\\s*(((async )?def .*?)?\\)(\\s*->.*?)?:\\s*)?\\.\\.\\.\\s*(#|$)", "if (typing\\.)?TYPE_CHECKING:", ] [tool.codespell] ignore-words-list = [ "AFE", "Synopsys", "afe", "afile", "alog", "ccompiler", "datas", "implementors", "inout", "nam", "sting", "synopsys", ] [tool.mypy] packages = ["cocotb", "pygpi"] modules = ["noxfile"] disallow_untyped_defs = true disallow_any_unimported = true disallow_untyped_calls = true disallow_untyped_decorators = true no_implicit_optional = true warn_redundant_casts = true warn_unused_ignores = true implicit_reexport = false show_error_codes = true pretty = true ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3587027 cocotb-2.0.1/setup.cfg0000644000175100017510000000004615106070715014254 0ustar00runnerrunner[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/setup.py0000755000175100017510000001161015106067236014153 0ustar00runnerrunner#!/usr/bin/env python # Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import sys if sys.version_info[:3] < (3, 6, 2): # noqa: UP036 | bug in ruff version_str = ".".join(sys.version_info[:3]) msg = [ "This version of cocotb requires at least Python 3.6.2,", f"you are running Python {version_str}." "For more information please refer to the documentation at ", "https://cocotb.readthedocs.io.", ] raise SystemExit("\n".join(msg)) import logging import os import subprocess from io import StringIO from os import path, walk from setuptools import find_packages, setup # Note: cocotb is not installed properly yet and is missing dependencies and binaries # We can still import other files next to setup.py, as long as they're in MANIFEST.in # The below line is necessary for PEP517 support sys.path.append(path.dirname(__file__)) from cocotb_build_libs import build_ext, get_ext __version__ = "2.0.1" max_python3_minor_version = 13 if "COCOTB_IGNORE_PYTHON_REQUIRES" not in os.environ and sys.version_info >= ( 3, max_python3_minor_version + 1, ): raise RuntimeError( f"cocotb {__version__} only supports a maximum Python version of 3.{max_python3_minor_version}.\n" "You can suppress this error by defining the environment variable COCOTB_IGNORE_PYTHON_REQUIRES\n" "There is no guarantee this will work and no support will be provided." ) def read_file(fname): with open(path.join(path.dirname(__file__), fname), encoding="utf8") as f: return f.read() def package_files(directory): paths = [] for fpath, _, filenames in walk(directory): for filename in filenames: paths.append(path.join("..", "..", fpath, filename)) return paths version_file_path = path.join("src", "cocotb", "_version.py") if "dev" in __version__: try: rev = subprocess.check_output( ["git", "rev-parse", "--short", "HEAD"], universal_newlines=True ).strip() __version__ += f"+{rev}" except Exception as e: # if this is not a git repository and _version.py already exists, # we are probably installing from an sdist, so use the existing _version.py if path.exists(version_file_path): exec(read_file(version_file_path)) else: print(e, file=sys.stderr) with open(version_file_path, "w") as f: f.write("# Package version\n") f.write("# Generated by setup.py -- do not modify directly\n\n") f.write(f'__version__ = "{__version__}"\n') # store log from build_libs and display at the end in verbose mode # see https://github.com/pypa/pip/issues/6634 log_stream = StringIO() handler = logging.StreamHandler(log_stream) log = logging.getLogger("cocotb_build_libs") log.setLevel(logging.INFO) log.addHandler(handler) setup( name="cocotb", cmdclass={"build_ext": build_ext}, version=__version__, description="cocotb is a coroutine based cosimulation library for writing VHDL and Verilog testbenches in Python.", url="https://www.cocotb.org", license="BSD-3-Clause", long_description=read_file("README.md"), long_description_content_type="text/markdown", author="Chris Higgs, Stuart Hodgson", maintainer="cocotb contributors", maintainer_email="cocotb@lists.librecores.org", install_requires=[ "find_libpython", ], python_requires=">=3.6.2", packages=find_packages(where="src"), package_dir={"": "src"}, package_data={ "cocotb": ( package_files("src/cocotb/share/include") + package_files("src/cocotb/share/def") + package_files("src/cocotb/share/lib/verilator") ), "cocotb_tools": (package_files("src/cocotb_tools/makefiles")), }, ext_modules=get_ext(), entry_points={ "console_scripts": [ "cocotb-config=cocotb_tools.config:main", ] }, platforms="any", classifiers=[ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", "Framework :: cocotb", ], # these appear in the sidebar on PyPI project_urls={ "Bug Tracker": "https://github.com/cocotb/cocotb/issues", "Source Code": "https://github.com/cocotb/cocotb", "Documentation": "https://docs.cocotb.org", }, ) print(log_stream.getvalue()) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3347023 cocotb-2.0.1/src/0000755000175100017510000000000015106070715013222 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3417025 cocotb-2.0.1/src/cocotb/0000755000175100017510000000000015106070715014473 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_ANSI.py0000644000175100017510000000423715106067236015750 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013, 2018 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause from cocotb._py_compat import StrEnum _ESCAPE = "\033[" class ANSI(StrEnum): """ANSI escape codes for coloring output. The color names supported are ``[BRIGHT_]{BLACK|RED|GREEN|YELLOW|BLUE|MAGENTA|CYAN|WHITE}{_FG|_BG}``. Variables that end in ``_FG`` will color the character or symbol ("foreground") and variables that end in ``_BG`` will color the background. Foreground and background colors can be combined together with a ``+``. Setting a new foreground color will override the previous foreground, likewise with background colors. Use ``DEFAULT_FG`` and ``DEFAULT_BG`` to reset the coloring to the default colors for the foreground and background, respectively. Or use ``DEFAULT`` to reset both. """ DEFAULT_FG = _ESCAPE + "39m" DEFAULT_BG = _ESCAPE + "49m" DEFAULT = DEFAULT_BG + DEFAULT_FG BLACK_FG = _ESCAPE + "30m" RED_FG = _ESCAPE + "31m" GREEN_FG = _ESCAPE + "32m" YELLOW_FG = _ESCAPE + "33m" BLUE_FG = _ESCAPE + "34m" MAGENTA_FG = _ESCAPE + "35m" CYAN_FG = _ESCAPE + "36m" WHITE_FG = _ESCAPE + "37m" BLACK_BG = _ESCAPE + "40m" RED_BG = _ESCAPE + "41m" GREEN_BG = _ESCAPE + "42m" YELLOW_BG = _ESCAPE + "43m" BLUE_BG = _ESCAPE + "44m" MAGENTA_BG = _ESCAPE + "45m" CYAN_BG = _ESCAPE + "46m" WHITE_BG = _ESCAPE + "47m" BRIGHT_BLACK_FG = _ESCAPE + "90m" BRIGHT_RED_FG = _ESCAPE + "91m" BRIGHT_GREEN_FG = _ESCAPE + "92m" BRIGHT_YELLOW_FG = _ESCAPE + "93m" BRIGHT_BLUE_FG = _ESCAPE + "94m" BRIGHT_MAGENTA_FG = _ESCAPE + "95m" BRIGHT_CYAN_FG = _ESCAPE + "96m" BRIGHT_WHITE_FG = _ESCAPE + "97m" BRIGHT_BLACK_BG = _ESCAPE + "100m" BRIGHT_RED_BG = _ESCAPE + "101m" BRIGHT_GREEN_BG = _ESCAPE + "102m" BRIGHT_YELLOW_BG = _ESCAPE + "103m" BRIGHT_BLUE_BG = _ESCAPE + "104m" BRIGHT_MAGENTA_BG = _ESCAPE + "105m" BRIGHT_CYAN_BG = _ESCAPE + "106m" BRIGHT_WHITE_BG = _ESCAPE + "107m" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/__init__.py0000644000175100017510000000636215106067236016617 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import sys from typing import TYPE_CHECKING, Dict, List, Union from cocotb._decorators import ( parametrize, test, ) from cocotb._test import create_task, start, start_soon from cocotb._test_functions import pass_test from ._version import __version__ as _version if TYPE_CHECKING: from logging import Logger from types import SimpleNamespace from cocotb._scheduler import Scheduler from cocotb.handle import SimHandleBase from cocotb.regression import RegressionManager __all__ = ( "RANDOM_SEED", "SIM_NAME", "SIM_VERSION", "__version__", "argv", "create_task", "is_simulation", "log", "packages", "parametrize", "pass_test", "plusargs", "start", "start_soon", "test", "top", ) # Set __module__ on re-exports test.__module__ = __name__ start_soon.__module__ = __name__ start.__module__ = __name__ create_task.__module__ = __name__ parametrize.__module__ = __name__ pass_test.__module__ = __name__ __version__: str = _version """The version of cocotb.""" log: "Logger" """An easily accessible :class:`~logging.Logger` for the user. This logger defaults to the :data:`logging.INFO` log level. .. versionchanged:: 2.0 This was previously the ``"cocotb"`` Logger. It is now a Logger under the ``"test"`` namespace. """ _scheduler_inst: "Scheduler" """The global scheduler instance.""" _regression_manager: "RegressionManager" """The global regression manager instance.""" argv: List[str] """The argument list as seen by the simulator.""" plusargs: Dict[str, Union[bool, str]] """A dictionary of "plusargs" handed to the simulation. See :envvar:`COCOTB_PLUSARGS` for details. """ packages: "SimpleNamespace" """A :class:`python:types.SimpleNamespace` of package handles. This will be populated with handles at test time if packages can be discovered via the GPI. .. versionadded:: 2.0 """ SIM_NAME: str """The product information of the running simulator.""" SIM_VERSION: str """The version of the running simulator.""" RANDOM_SEED: int """The last value used to seed the global PRNG. During test collection, this is set to the value provided by :envvar:`COCOTB_RANDOM_SEED`, if given, or a random value based on the state of the operating system. During test run, this is set to a new value computed by combining the value used during test collection, with the full test name (e.g. ``my_test_module.my_test``). """ top: "SimHandleBase" r""" A handle to the :envvar:`COCOTB_TOPLEVEL` entity/module. This is equivalent to the :term:`DUT` parameter given to cocotb tests, so it can be used wherever that variable can be used. It is particularly useful for extracting information about the :term:`DUT` in module-level class and function definitions; and in parameters to :class:`.TestFactory`\ s. """ is_simulation: bool = False """``True`` if cocotb was loaded in a simulation.""" if sys.version_info < (3, 9): import warnings warnings.warn( "Support for Python versions < 3.9 will be dropped in version 2.1", FutureWarning, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_base_triggers.py0000644000175100017510000003632015106067236020034 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """A collection of triggers which a testbench can :keyword:`await`.""" import logging import warnings from typing import ( AsyncContextManager, Callable, Generator, List, Optional, Union, ) from cocotb._deprecation import deprecated from cocotb._py_compat import Self, cached_property from cocotb._utils import pointer_str class Trigger: """A future event that a Task can wait upon.""" def __init__(self) -> None: self._primed = False @cached_property def _log(self) -> logging.Logger: return logging.getLogger(f"cocotb.{type(self).__qualname__}.0x{id(self):x}") def _prime(self, callback: Callable[["Self"], None]) -> None: """Set a callback to be invoked when the trigger fires. The callback will be invoked with a single argument, `self`. Sub-classes must override this, but should end by calling the base class method. .. warning:: Do not call this directly within a :term:`task`. It is intended to be used only by the scheduler. """ # Set _primed so the trigger can test if it's already been primed and behave appropriately. self._primed = True def _unprime(self) -> None: """Remove the callback, and perform cleanup if necessary. After being un-primed, a Trigger may be re-primed again in the future. Calling `_unprime` multiple times is allowed, subsequent calls should be a no-op. Sub-classes may override this, but should end by calling the base class method. .. warning:: Do not call this directly within a :term:`task`. It is intended to be used only by the scheduler. """ self._cleanup() def _cleanup(self) -> None: # Clear _primed so this Trigger can be re-primed. self._primed = False def __await__(self) -> Generator["Self", None, "Self"]: yield self return self class _Event(Trigger): """Unique instance used by the Event object. One created for each attempt to wait on the event so that the scheduler can maintain a unique mapping of triggers to tasks. """ _callback: Callable[["_Event"], None] def __init__(self, parent: "Event") -> None: super().__init__() self._parent = parent def _prime(self, callback: Callable[["_Event"], None]) -> None: if self._primed: return if self._parent.is_set(): # If the event is already set, we need to call the callback # immediately, so we don't need to wait for the scheduler. callback(self) return self._callback = callback return super()._prime(callback) def _unprime(self) -> None: if not self._primed: return return super()._unprime() def _set(self) -> None: if self._primed: self._callback(self) def __repr__(self) -> str: return f"<{self._parent!r}.wait() at {pointer_str(self)}>" class Event: r"""A way to signal an event across :class:`~cocotb.task.Task`\ s. :keyword:`await`\ ing the result of :meth:`wait()` will block the :keyword:`await`\ ing :class:`~cocotb.task.Task` until :meth:`set` is called. Args: name: Name for the Event. Usage: .. code-block:: python e = Event() async def task1(): await e.wait() print("resuming!") cocotb.start_soon(task1()) # do stuff e.set() await NullTrigger() # allows task1 to execute # resuming! .. versionremoved:: 2.0 Removed the undocumented *data* attribute and argument to :meth:`set`, and the *name* attribute and argument to the constructor. """ def __init__(self, name: Optional[str] = None) -> None: self._event: _Event = _Event(self) self._name: Union[str, None] = None if name is not None: warnings.warn( "The 'name' argument will be removed in a future release.", DeprecationWarning, stacklevel=2, ) self.name = name self._fired: bool = False self._data: object = None @property @deprecated("The 'name' field will be removed in a future release.") def name(self) -> Union[str, None]: """Name of the Event. .. deprecated:: 2.0 The *name* field will be removed in a future release. """ return self._name @name.setter @deprecated("The 'name' field will be removed in a future release.") def name(self, new_name: Union[str, None]) -> None: self._name = new_name @property @deprecated("The data field will be removed in a future release.") def data(self) -> object: """The data associated with the Event. .. deprecated:: 2.0 The data field will be removed in a future release. Use a separate variable to store the data instead. """ return self._data @data.setter @deprecated("The data field will be removed in a future release.") def data(self, new_data: object) -> None: self._data = new_data def set(self, data: Optional[object] = None) -> None: """Set the Event and unblock all Tasks blocked on this Event.""" self._fired = True if data is not None: warnings.warn( "The data field will be removed in a future release.", DeprecationWarning, stacklevel=2, ) self._data = data self._event._set() def wait(self) -> Trigger: """Block the current Task until the Event is set. If the event has already been set, the trigger will fire immediately. To set the Event call :meth:`set`. To reset the Event (and enable the use of :meth:`wait` again), call :meth:`clear`. """ return self._event def clear(self) -> None: """Clear this event that has been set. Subsequent calls to :meth:`~cocotb.triggers.Event.wait` will block until :meth:`~cocotb.triggers.Event.set` is called again. """ self._fired = False def is_set(self) -> bool: """Return ``True`` if event has been set.""" return self._fired def __repr__(self) -> str: if self._name is None: fmt = "<{0} at {2}>" else: fmt = "<{0} for {1} at {2}>" return fmt.format(type(self).__qualname__, self._name, pointer_str(self)) class _InternalEvent(Trigger): """Event used internally for triggers that need cross-:class:`~cocotb.task.Task` synchronization. This Event can only be waited on once, by a single :class:`~cocotb.task.Task`. Provides transparent :func`repr` pass-through to the :class:`Trigger` using this event, providing a better debugging experience. """ def __init__(self, parent: object) -> None: super().__init__() self._parent = parent self._callback: Optional[Callable[[_InternalEvent], None]] = None self.fired: bool = False def _prime(self, callback: Callable[["_InternalEvent"], None]) -> None: if self._primed: raise RuntimeError("This Trigger may only be awaited once") self._callback = callback super()._prime(callback) if self.fired: self._callback(self) def _cleanup(self) -> None: # Don't clear _primed so a second call to _prime() fails. pass def set(self) -> None: """Wake up coroutine blocked on this event.""" self.fired = True if self._callback is not None: self._callback(self) def is_set(self) -> bool: """Return true if event has been set.""" return self.fired def __await__( self, ) -> Generator["Self", None, "Self"]: if self._primed: raise RuntimeError("Only one Task may await this Trigger") yield self return self def __repr__(self) -> str: return repr(self._parent) class _Lock(Trigger): """Unique instance used by the Lock object. One created for each attempt to acquire the Lock so that the scheduler can maintain a unique mapping of triggers to tasks. """ def __init__(self, parent: "Lock") -> None: super().__init__() self._parent = parent def _prime(self, callback: Callable[["Self"], None]) -> None: if self._primed: raise RuntimeError( "Lock.acquire() result can only be used by one task at a time" ) self._callback = callback self._parent._prime_lock(self) return super()._prime(callback) def _unprime(self) -> None: if not self._primed: return self._parent._unprime_lock(self) return super()._unprime() def __repr__(self) -> str: return f"<{self._parent!r}.acquire() at {pointer_str(self)}>" class Lock(AsyncContextManager[None]): """A mutual exclusion lock. Guarantees fair scheduling. Lock acquisition is given in order of attempted lock acquisition. Usage: By directly calling :meth:`acquire` and :meth:`release`. .. code-block:: python lock = Lock() ... await lock.acquire() try: # do some stuff ... finally: lock.release() Or... .. code-block:: python async with Lock(): # do some stuff ... .. versionchanged:: 1.4 The lock can be used as an asynchronous context manager in an :keyword:`async with` statement """ def __init__(self, name: Optional[str] = None) -> None: self._pending_primed: List[_Lock] = [] self._name: Union[str, None] = None if name is not None: warnings.warn( "The 'name' argument will be removed in a future release.", DeprecationWarning, stacklevel=2, ) self._name = name self._locked: bool = False @property @deprecated("The 'name' field will be removed in a future release.") def name(self) -> Union[str, None]: """Name of the Lock. .. deprecated:: 2.0 The *name* field will be removed in a future release. """ return self._name @name.setter @deprecated("The 'name' field will be removed in a future release.") def name(self, new_name: Union[str, None]) -> None: self._name = new_name def locked(self) -> bool: """Return ``True`` if the lock has been acquired. .. versionchanged:: 2.0 This is now a method to match :meth:`asyncio.Lock.locked`, rather than an attribute. """ return self._locked def _acquire_and_fire(self, lock: _Lock) -> None: self._locked = True lock._callback(lock) def _prime_lock(self, lock: _Lock) -> None: if not self._locked: self._acquire_and_fire(lock) else: self._pending_primed.append(lock) def _unprime_lock(self, lock: _Lock) -> None: if lock in self._pending_primed: self._pending_primed.remove(lock) def acquire(self) -> Trigger: """Produce a trigger which fires when the lock is acquired.""" trig = _Lock(self) return trig def release(self) -> None: """Release the lock.""" if not self._locked: raise RuntimeError(f"Attempt to release an unacquired Lock {self!s}") self._locked = False # nobody waiting for this lock if not self._pending_primed: return lock = self._pending_primed.pop(0) self._acquire_and_fire(lock) def __repr__(self) -> str: if self._name is None: fmt = "<{0} [{2} waiting] at {3}>" else: fmt = "<{0} for {1} [{2} waiting] at {3}>" return fmt.format( type(self).__qualname__, self._name, len(self._pending_primed), pointer_str(self), ) async def __aenter__(self) -> None: await self.acquire() async def __aexit__(self, *args: object) -> None: self.release() class NullTrigger(Trigger): """Trigger that fires immediately. Mostly useful when building or using higher-order functions which need to take or return Triggers. The scheduling order of the Task awaiting this Trigger with respect to any other Task is not deterministic and should generally not be relied upon. Instead of using this Trigger to push the Task until "after" another Task has run, use other synchronization techniques, such as using an :class:`.Event`. **Do not** do this: .. code-block:: python :class: removed transaction_data = None def monitor(dut): while dut.valid.value != 1 and dut.ready.value != 1: await RisingEdge(dut.clk) transaction_data = dut.data.value def use_transaction(dut): while True: await RisingEdge(dut.clk) # We need the NullTrigger here because both Tasks react to RisingEdge, # but there's no guarantee about which Task is run first, # so we need to force this one to run "later" using NullTrigger. await NullTrigger() if transaction_data is not None: process(transaction_data) use_task = cocotb.start_soon(use_transaction(cocotb.top)) monitor_task = cocotb.start_soon(monitor(cocotb.top)) Instead use an :class:`!Event` to explicitly synchronize the two Tasks, like so: .. code-block:: python :class: new transaction_data = None transaction_event = Event() def monitor(dut): while dut.valid.value != 1 and dut.ready.value != 1: await RisingEdge(dut.clk) transaction_data = dut.data.value transaction_event.set() def use_transaction(dut): # Now we don't need the NullTrigger. # This Task will wake up *strictly* after `monitor_task` sets the transaction. await transaction_event.wait() process(transaction_data) use_task = cocotb.start_soon(use_transaction(cocotb.top)) monitor_task = cocotb.start_soon(monitor(cocotb.top)) .. versionremoved:: 2.0 The *outcome* parameter was removed. There is no alternative. """ def __init__(self, name: Optional[str] = None) -> None: super().__init__() self.name = name def _prime(self, callback: Callable[["Self"], None]) -> None: if self._primed: return callback(self) return super()._prime(callback) def __repr__(self) -> str: if self.name is None: fmt = "<{0} at {2}>" else: fmt = "<{0} for {1} at {2}>" return fmt.format(type(self).__qualname__, self.name, pointer_str(self)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_bridge.py0000644000175100017510000001357215106067236016454 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import functools import logging import threading from enum import IntEnum from typing import ( TYPE_CHECKING, Callable, Coroutine, Generic, TypeVar, Union, ) import cocotb from cocotb import debug from cocotb._base_triggers import Event, Trigger from cocotb._exceptions import InternalError from cocotb._py_compat import ParamSpec if TYPE_CHECKING: from cocotb._outcomes import Outcome P = ParamSpec("P") Result = TypeVar("Result") def resume( func: "Callable[P, Coroutine[Trigger, None, Result]]", ) -> "Callable[P, Result]": """Converts a coroutine function into a blocking function. This allows a :term:`coroutine function` that awaits cocotb triggers to be called from a :term:`blocking function` converted by :func:`.bridge`. This completes the bridge through non-:keyword:`async` code. When a converted coroutine function is called the current function blocks until the converted function exits. Results of the converted function are returned from the function call. Args: func: The :term:`coroutine function` to convert into a :term:`blocking function`. Returns: *func* as a :term:`blocking function`. Raises: RuntimeError: If the function that is returned is subsequently called from a thread that was not started with :class:`.bridge`. .. versionchanged:: 2.0 Renamed from ``function``. No longer implemented as a type. The ``log`` attribute is no longer available. """ @functools.wraps(func) def wrapper(*args: "P.args", **kwargs: "P.kwargs") -> Result: return cocotb._scheduler_inst._queue_function(func(*args, **kwargs)) return wrapper def bridge( func: "Callable[P, Result]", ) -> "Callable[P, Coroutine[Trigger, None, Result]]": r"""Converts a blocking function into a coroutine function. This function converts a :term:`blocking function` into a :term:`coroutine function` with the expectation that the function being converted is intended to call a :func:`.resume` converted function. This creates a bridge through non-:keyword:`async` code for code wanting to eventually :keyword:`await` on cocotb triggers. When a converted function call is used in an :keyword:`await` statement, the current Task blocks until the converted function finishes. Results of the converted function are returned from the :keyword:`await` expression. .. note:: Bridge threads *must* either finish or block on a :func:`.resume` converted function before control is given back to the simulator. This is done to prevent any code from executing in parallel with the simulation. Args: func: The :term:`blocking function` to convert into a :term:`coroutine function`. Returns: *func* as a :term:`coroutine function`. .. versionchanged:: 2.0 Renamed from ``external``. No longer implemented as a type. The ``log`` attribute is no longer available. """ @functools.wraps(func) def wrapper( *args: "P.args", **kwargs: "P.kwargs" ) -> Coroutine[Trigger, None, Result]: return cocotb._scheduler_inst._run_in_executor(func, *args, **kwargs) return wrapper class external_state(IntEnum): INIT = 0 RUNNING = 1 PAUSED = 2 EXITED = 3 class external_waiter(Generic[Result]): def __init__(self) -> None: self._outcome: Union[Outcome[Result], None] = None self.thread: threading.Thread self.event = Event() self.state = external_state.INIT self.cond = threading.Condition() self._log = logging.getLogger(f"cocotb.bridge.0x{id(self):x}") @property def result(self) -> Result: if self._outcome is None: raise InternalError("Got result of external before it finished") return self._outcome.get() def _propagate_state(self, new_state: external_state) -> None: with self.cond: if debug.debug: self._log.debug( f"Changing state from {self.state} -> {new_state} from {threading.current_thread()}" ) self.state = new_state self.cond.notify() def thread_done(self) -> None: if debug.debug: self._log.debug(f"Thread finished from {threading.current_thread()}") self._propagate_state(external_state.EXITED) def thread_suspend(self) -> None: self._propagate_state(external_state.PAUSED) def thread_start(self) -> None: if self.state > external_state.INIT: return if not self.thread.is_alive(): self._propagate_state(external_state.RUNNING) self.thread.start() def thread_resume(self) -> None: self._propagate_state(external_state.RUNNING) def thread_wait(self) -> external_state: if debug.debug: self._log.debug( f"Waiting for the condition lock {threading.current_thread()}" ) with self.cond: while self.state == external_state.RUNNING: self.cond.wait() if debug.debug: if self.state == external_state.EXITED: self._log.debug( f"Thread {self.thread} has exited from {threading.current_thread()}" ) elif self.state == external_state.PAUSED: self._log.debug( f"Thread {self.thread} has called yield from {threading.current_thread()}" ) if self.state == external_state.INIT: raise Exception( f"Thread {self.thread} state was not allowed from {threading.current_thread()}" ) return self.state ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_decorators.py0000644000175100017510000004177115106067236017367 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import functools import inspect from enum import Enum from itertools import product from typing import ( Callable, Coroutine, Dict, Iterable, List, Optional, Sequence, Tuple, Type, Union, cast, overload, ) from cocotb._base_triggers import Trigger from cocotb._py_compat import Protocol, TypeAlias from cocotb._typing import TimeUnit class Test: """A cocotb test in a regression. Args: func: The test function object. name: The name of the test function. Defaults to ``func.__qualname__`` (the dotted path to the test function in the module). module: The name of the module containing the test function. Defaults to ``func.__module__`` (the name of the module containing the test function). doc: The docstring for the test. Defaults to ``func.__doc__`` (the docstring of the test function). timeout_time: Simulation time duration before the test is forced to fail with a :exc:`~cocotb.triggers.SimTimeoutError`. timeout_unit: Unit of ``timeout_time``, accepts any unit that :class:`~cocotb.triggers.Timer` does. expect_fail: If ``True`` and the test fails a functional check via an :keyword:`assert` statement, :func:`pytest.raises`, :func:`pytest.warns`, or :func:`pytest.deprecated_call`, the test is considered to have passed. If ``True`` and the test passes successfully, the test is considered to have failed. expect_error: Mark the result as a pass only if one of the given exception types is raised in the test. skip: Don't execute this test as part of the regression. The test can still be run manually by setting :envvar:`COCOTB_TESTCASE`. stage: Order tests logically into stages. Tests from earlier stages are run before tests from later stages. """ def __init__( self, *, func: Callable[..., Coroutine[Trigger, None, None]], name: Optional[str] = None, module: Optional[str] = None, doc: Optional[str] = None, timeout_time: Optional[float] = None, timeout_unit: TimeUnit = "step", expect_fail: bool = False, expect_error: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = (), skip: bool = False, stage: int = 0, ) -> None: self.func: Callable[..., Coroutine[Trigger, None, None]] = func self.timeout_time = timeout_time self.timeout_unit = timeout_unit self.expect_fail = expect_fail if isinstance(expect_error, type): expect_error = (expect_error,) self.expect_error = expect_error self.skip = skip self.stage = stage self.name = self.func.__qualname__ if name is None else name self.module = self.func.__module__ if module is None else module self.doc = self.func.__doc__ if doc is None else doc if self.doc is not None: # cleanup docstring using `trim` function from PEP257 self.doc = inspect.cleandoc(self.doc) self.fullname = f"{self.module}.{self.name}" TestFuncType: TypeAlias = Callable[..., Coroutine[Trigger, None, None]] class Parameterized: def __init__( self, test_function: TestFuncType, options: List[ Union[ Tuple[str, Sequence[object]], Tuple[Sequence[str], Sequence[Sequence[object]]], ] ], ) -> None: self.test_template = Test(func=test_function) self.options = options # we are assuming the input checking is done in parametrize() self._option_reprs: Dict[str, List[str]] = {} for name, values in options: if isinstance(name, str): self._option_reprs[name] = _reprs(values) else: # transform to Dict[name, values] transformed: Dict[str, List[object]] = {} for nam_idx, nam in enumerate(name): transformed[nam] = [] for value_array in cast("Sequence[Sequence[object]]", values): value = value_array[nam_idx] transformed[nam].append(value) for n, vs in transformed.items(): self._option_reprs[n] = _reprs(vs) def generate_tests(self) -> Iterable[Test]: test_func = self.test_template.func test_func_name = self.test_template.name # this value is a list of ranges of the same length as each set of values in self.options for passing to itertools.product option_indexes = [range(len(option[1])) for option in self.options] # go through the cartesian product of all values of all options for selected_options in product(*option_indexes): test_kwargs: Dict[str, object] = {} test_name_pieces: List[str] = [test_func_name] for option_idx, select_idx in enumerate(selected_options): option_name, option_values = self.options[option_idx] selected_value = option_values[select_idx] if isinstance(option_name, str): # single params per option selected_value = cast("Sequence[object]", selected_value) test_kwargs[option_name] = selected_value test_name_pieces.append( f"/{option_name}={self._option_reprs[option_name][select_idx]}" ) else: # multiple params per option selected_value = cast("Sequence[object]", selected_value) for n, v in zip(option_name, selected_value): test_kwargs[n] = v test_name_pieces.append( f"/{n}={self._option_reprs[n][select_idx]}" ) parametrized_test_name = "".join(test_name_pieces) # create wrapper function to bind kwargs @functools.wraps(test_func) async def _my_test( dut: object, kwargs: Dict[str, object] = test_kwargs ) -> None: await test_func(dut, **kwargs) yield Test( func=_my_test, name=parametrized_test_name, timeout_time=self.test_template.timeout_time, timeout_unit=self.test_template.timeout_unit, expect_fail=self.test_template.expect_fail, expect_error=self.test_template.expect_error, skip=self.test_template.skip, stage=self.test_template.stage, ) def _reprs(values: Sequence[object]) -> List[str]: result: List[str] = [] for value in values: value_repr = _repr(value) if value_repr is None: # non-representable value in option, so default to index strings and give up return [str(i) for i in range(len(values))] else: result.append(value_repr) return result def _repr(v: object) -> Optional[str]: if isinstance(v, Enum): return v.name elif isinstance(v, str): if len(v) <= 10 and v.isidentifier(): return v else: return None elif isinstance(v, (int, float, bool, type(None))): return repr(v) elif isinstance(v, type): return v.__qualname__ elif hasattr(v, "__qualname__"): return v.__qualname__ else: return None class TestDecoratorType(Protocol): # TODO use position only argument for *obj* so we aren't tied to that name. @overload def __call__(self, obj: TestFuncType) -> Test: ... @overload def __call__(self, obj: Parameterized) -> Parameterized: ... @overload def test(obj: TestFuncType) -> Test: ... @overload def test(obj: Parameterized) -> Parameterized: ... @overload def test( *, timeout_time: Optional[float] = None, timeout_unit: TimeUnit = "step", expect_fail: bool = False, expect_error: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = (), skip: bool = False, stage: int = 0, name: Optional[str] = None, ) -> TestDecoratorType: ... def test( obj: Optional[Union[TestFuncType, Parameterized]] = None, *, timeout_time: Optional[float] = None, timeout_unit: TimeUnit = "step", expect_fail: bool = False, expect_error: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = (), skip: bool = False, stage: int = 0, name: Optional[str] = None, ) -> Union[ Test, Parameterized, TestDecoratorType, ]: r""" Decorator to register a Callable which returns a Coroutine as a test. The test decorator provides a test timeout, and allows us to mark tests as skipped or expecting errors or failures. Tests are evaluated in the order they are defined in a test module. Usage: .. code-block:: python @cocotb.test(timeout_time=10, timeout_unit="ms") async def test_thing(dut): ... Args: timeout_time: Simulation time duration before timeout occurs. .. versionadded:: 1.3 .. note:: Test timeout is intended for protection against deadlock. Users should use :class:`~cocotb.triggers.with_timeout` if they require a more general-purpose timeout mechanism. timeout_unit: Units of timeout_time, accepts any units that :class:`~cocotb.triggers.Timer` does. .. versionadded:: 1.3 .. versionchanged:: 2.0 Passing ``None`` as the *timeout_unit* argument was removed, use ``'step'`` instead. expect_fail: If ``True`` and the test fails a functional check via an :keyword:`assert` statement, :class:`pytest.raises`, :class:`pytest.warns`, or :class:`pytest.deprecated_call` the test is considered to have passed. If ``True`` and the test passes successfully, the test is considered to have failed. expect_error: Mark the result as a pass only if one of the exception types is raised in the test. This is primarily for cocotb internal regression use for when a simulator error is expected. Users are encouraged to use the following idiom instead:: @cocotb.test() async def my_test(dut): try: await thing_that_should_fail() except ExceptionIExpect: pass else: assert False, "Exception did not occur" .. versionchanged:: 1.3 Specific exception types can be expected .. versionchanged:: 2.0 Passing a :class:`bool` value was removed. Pass a specific :class:`Exception` or a tuple of Exceptions instead. skip: Don't execute this test as part of the regression. Test can still be run manually by setting :make:var:`COCOTB_TESTCASE`. stage: Order tests logically into stages, where multiple tests can share a stage. Defaults to 0. name: Override the default name of the test. The default test name is the :meth:`__qualname__` of the decorated test function. .. versionadded:: 2.0 Returns: The test function to which the decorator is applied. .. note:: To extend the test decorator, use the following template to create a new ``cocotb.test``\-like wrapper. .. code-block:: python import functools def test_extender(**decorator_kwargs): def decorator(obj): @cocotb.test(**decorator_kwargs) @functools.wraps(obj) async def test(dut, **test_kwargs): # your code here ... return obj return decorator .. versionchanged:: 2.0 Support using decorator on test function without supplying parameters first. Assumes all default values for the test parameters. .. code-block:: python @cocotb.test async def test_thing(dut): ... .. versionchanged:: 2.0 Decorated tests now return the decorated object. """ if obj is not None: if isinstance(obj, Parameterized): return obj else: return Test(func=obj) @overload def wrapper(obj: TestFuncType) -> Test: ... @overload def wrapper(obj: Parameterized) -> Parameterized: ... def wrapper(obj: Union[TestFuncType, Parameterized]) -> Union[Test, Parameterized]: if isinstance(obj, Parameterized): obj.test_template = Test( func=obj.test_template.func, name=name, timeout_time=timeout_time, timeout_unit=timeout_unit, expect_fail=expect_fail, expect_error=expect_error, skip=skip, stage=stage, ) return obj else: return Test( func=obj, name=name, timeout_time=timeout_time, timeout_unit=timeout_unit, expect_fail=expect_fail, expect_error=expect_error, skip=skip, stage=stage, ) return wrapper def parametrize( *options_by_tuple: Union[ Tuple[str, Sequence[object]], Tuple[Sequence[str], Sequence[Sequence[object]]] ], **options_by_name: Sequence[object], ) -> Callable[[TestFuncType], Parameterized]: """Decorator to generate parametrized tests from a single test function. Decorates a test function with named test parameters. The call to ``parametrize`` should include the name of each test parameter and the possible values each parameter can hold. This will generate a test for each of the Cartesian products of the parameters and their values. .. code-block:: python @cocotb.test( skip=False, ) @cocotb.parametrize( arg1=[0, 1], arg2=["a", "b"], ) async def my_test(arg1: int, arg2: str) -> None: ... The above is equivalent to the following. .. code-block:: python @cocotb.test(skip=False) async def my_test_0_a() -> None: arg1, arg2 = 0, "a" ... @cocotb.test(skip=False) async def my_test_0_b() -> None: arg1, arg2 = 0, "b" ... @cocotb.test(skip=False) async def my_test_1_a() -> None: arg1, arg2 = 1, "a" ... @cocotb.test(skip=False) async def my_test_1_b() -> None: arg1, arg2 = 1, "b" ... Options can also be specified in much the same way that :meth:`TestFactory.add_option ` can, either by supplying tuples of the parameter name to values, or a sequence of variable names and a sequence of values. .. code-block:: python @cocotb.parametrize( ("arg1", [0, 1]), (("arg2", "arg3"), [(1, 2), (3, 4)]), ) async def my_test_2(arg1: int, arg2: int, arg3: int) -> None: ... Args: options_by_tuple: Tuple of parameter name to sequence of values for that parameter, or tuple of sequence of parameter names to sequence of sequences of values for that pack of parameters. options_by_name: Mapping of parameter name to sequence of values for that parameter. .. versionadded:: 2.0 """ # check good inputs for i, option_by_tuple in enumerate(options_by_tuple): if len(option_by_tuple) != 2: raise ValueError( f"Invalid option tuple {i}, expected exactly two fields `(name, values)`" ) name, values = option_by_tuple if not isinstance(name, str): for n in name: if not n.isidentifier(): raise ValueError("Option names must be valid Python identifiers") values = cast("Sequence[Sequence[object]]", values) for value in values: if len(name) != len(value): raise ValueError( f"Invalid option tuple {i}, mismatching number of parameters ({name}) and values ({value})" ) elif not name.isidentifier(): raise ValueError("Option names must be valid Python identifiers") options = [*options_by_tuple, *options_by_name.items()] def wrapper(f: TestFuncType) -> Parameterized: return Parameterized(f, options) return wrapper ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_deprecation.py0000644000175100017510000000231415106067236017505 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import functools import warnings from typing import Callable, Type, TypeVar AnyCallableT = TypeVar("AnyCallableT", bound=Callable[..., object]) def deprecated( msg: str, category: Type[Warning] = DeprecationWarning ) -> Callable[[AnyCallableT], AnyCallableT]: """Emits a DeprecationWarning when the decorated function is called. This decorator works on normal functions, methods, and properties. Usage on properties requires the ``@property`` decorator to appear outside the ``@deprecated`` decorator. Concrete classes can be deprecated by decorating their ``__init__`` or ``__new__`` method. Args: msg: the deprecation message category: the warning class to use """ def decorator(f: AnyCallableT) -> AnyCallableT: @functools.wraps(f) def wrapper(*args: object, **kwargs: object) -> object: warnings.warn(msg, category=category, stacklevel=2) return f(*args, **kwargs) return wrapper # type: ignore[return-value] # type checkers get confused about this return decorator ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_exceptions.py0000644000175100017510000000037215106067236017373 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause class InternalError(BaseException): """An error internal to scheduler. If you see this, report a bug!""" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_extended_awaitables.py0000644000175100017510000003226115106067236021210 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """A collection of triggers which a testbench can :keyword:`await`.""" from abc import abstractmethod from decimal import Decimal from typing import ( Any, Awaitable, Coroutine, Generator, List, Optional, Type, TypeVar, Union, cast, overload, ) import cocotb.handle from cocotb._base_triggers import NullTrigger, Trigger, _InternalEvent from cocotb._gpi_triggers import FallingEdge, RisingEdge, Timer, ValueChange from cocotb._typing import RoundMode, TimeUnit from cocotb.task import Task T = TypeVar("T") class Waitable(Awaitable[T]): """A Trigger-like object that can be implemented using coroutines. This converts a ``_wait`` abstract method into a suitable ``__await__``. """ @abstractmethod async def _wait(self) -> T: """The coroutine function which implements the functionality of the Waitable.""" def __await__(self) -> Generator[Trigger, None, T]: return self._wait().__await__() class _AggregateWaitable(Waitable[T]): """Base class for :class:`Combine` and :class:`First`.""" def __init__(self, *trigger: Union[Trigger, Waitable[Any], Task[Any]]) -> None: self._triggers = trigger # Do some basic type-checking up front, rather than waiting until we # await them. allowed_types = (Trigger, Waitable, Task) for t in self._triggers: if not isinstance(t, allowed_types): raise TypeError( f"All triggers must be instances of Trigger! Got: {type(t).__qualname__}" ) def __repr__(self) -> str: # no _pointer_str here, since this is not a trigger, so identity # doesn't matter. return "{}({})".format( type(self).__qualname__, ", ".join(repr(t) for t in self._triggers), ) async def _wait_callback(trigger: Awaitable[T]) -> T: return await trigger class Combine(_AggregateWaitable["Combine"]): r"""Trigger that fires when all *triggers* have fired. :keyword:`await`\ ing this returns the :class:`Combine` object. This is similar to Verilog's ``join``. See :ref:`combine-tutorial` for an example. Args: trigger: One or more :keyword:`await`\ able objects. Raises: TypeError: When an unsupported *trigger* object is passed. """ async def _wait(self) -> "Combine": if len(self._triggers) == 0: await NullTrigger() elif len(self._triggers) == 1: await self._triggers[0] else: waiters: List[Task[object]] = [] completed: List[Task[object]] = [] done = _InternalEvent(self) exception: Union[BaseException, None] = None def on_done( task: Task[object], ) -> None: # have to check cancelled first otherwise exception() will throw if task.cancelled(): completed.append(task) if len(completed) == len(waiters): done.set() return e = task.exception() if e is not None: nonlocal exception exception = e done.set() else: completed.append(task) if len(completed) == len(waiters): done.set() # start a parallel task for each trigger for t in self._triggers: task = Task[object](_wait_callback(t)) task._add_done_callback(on_done) cocotb.start_soon(task) waiters.append(task) try: # wait for the last waiter to complete await done finally: # kill remaining waiters for w in waiters: w.cancel() if exception is not None: raise exception return self class First(_AggregateWaitable[object]): r"""Fires when the first trigger in *triggers* fires. :keyword:`await`\ ing this object returns the result of the first trigger that fires. This is similar to Verilog's ``join_any``. See :ref:`first-tutorial` for an example. Args: trigger: One or more :keyword:`await`\ able objects. Raises: TypeError: When an unsupported *trigger* object is passed. ValueError: When no triggers are passed. .. note:: The event loop is single threaded, so while events may be simultaneous in simulation time, they can never be simultaneous in real time. For this reason, the value of ``t_ret is t1`` in the following example is implementation-defined, and will vary by simulator:: t1 = Timer(10, unit="ps") t2 = Timer(10, unit="ps") t_ret = await First(t1, t2) .. note:: In the old-style :ref:`generator-based coroutines `, ``t = yield [a, b]`` was another spelling of ``t = yield First(a, b)``. This spelling is no longer available when using :keyword:`await`-based coroutines. """ def __init__(self, *trigger: Union[Trigger, Waitable[Any], Task[Any]]) -> None: if not trigger: raise ValueError("First() requires at least one Trigger or Task argument") super().__init__(*trigger) async def _wait(self) -> object: if len(self._triggers) == 1: return await self._triggers[0] waiters: List[Task[object]] = [] done = _InternalEvent(self) completed: List[Task[object]] = [] def on_done(task: Task[object]) -> None: completed.append(task) done.set() # start a parallel task for each trigger for t in self._triggers: task = Task[object](_wait_callback(t)) task._add_done_callback(on_done) cocotb.start_soon(task) waiters.append(task) try: # wait for a waiter to complete await done finally: # kill all the other waiters for w in waiters: w.cancel() return completed[0].result() class ClockCycles(Waitable["ClockCycles"]): r"""Finishes after *num_cycles* transitions of *signal*. :keyword:`await`\ ing this Trigger returns the :class:`!ClockCycles` object. Args: signal: The signal to monitor. num_cycles: The number of cycles to count. rising: If ``True``, count rising edges; if ``False``, count falling edges. edge_type: The kind of :ref:`edge-triggers` to count. .. warning:: On many simulators transitions occur when the signal changes value from non-``0`` to ``0`` or non-``1`` to ``1``, not just from ``1`` to ``0`` or ``0`` to ``1``. .. versionadded:: 2.0 Passing the edge trigger type: :class:`.RisingEdge`, :class:`.FallingEdge`, or :class:`.ValueChange` as the third positional argument or by the keyword *edge_type*. """ @overload def __init__( self, signal: "cocotb.handle.LogicObject", num_cycles: int, ) -> None: ... @overload def __init__( self, signal: "cocotb.handle.LogicObject", num_cycles: int, edge_type: Union[ Type[RisingEdge], Type[FallingEdge], Type[ValueChange], None ] = None, ) -> None: ... @overload def __init__( self, signal: "cocotb.handle.LogicObject", num_cycles: int, *, rising: bool ) -> None: ... def __init__( self, signal: "cocotb.handle.LogicObject", num_cycles: int, edge_type: Union[ bool, Type[RisingEdge], Type[FallingEdge], Type[ValueChange], None ] = None, *, rising: Union[bool, None] = None, ) -> None: self._signal = signal self._num_cycles = num_cycles self._edge_type: Union[Type[RisingEdge], Type[FallingEdge], Type[ValueChange]] if edge_type is not None and rising is not None: raise TypeError("Passed more than one edge selection argument.") elif edge_type is True: self._edge_type = RisingEdge elif edge_type is False: self._edge_type = FallingEdge elif edge_type is not None: self._edge_type = edge_type elif rising is not None: self._edge_type = RisingEdge if rising else FallingEdge else: # default if no argument is passed self._edge_type = RisingEdge @property def signal(self) -> "cocotb.handle.LogicObject": """The signal being monitored.""" return self._signal @property def num_cycles(self) -> int: """The number of cycles to wait.""" return self._num_cycles @property def edge_type( self, ) -> Union[Type[RisingEdge], Type[FallingEdge], Type[ValueChange]]: """The type of edge trigger used.""" return self._edge_type async def _wait(self) -> "ClockCycles": trigger = self._edge_type(self._signal) for _ in range(self._num_cycles): await trigger return self def __repr__(self) -> str: return f"{type(self).__qualname__}({self._signal._path}, {self._num_cycles}, {self._edge_type.__qualname__})" class SimTimeoutError(TimeoutError): """Exception thrown when a timeout, in terms of simulation time, occurs.""" TriggerT = TypeVar("TriggerT", bound=Trigger) @overload async def with_timeout( trigger: TriggerT, timeout_time: Union[float, Decimal], timeout_unit: TimeUnit = "step", round_mode: Optional[RoundMode] = None, ) -> TriggerT: ... @overload async def with_timeout( trigger: Waitable[T], timeout_time: Union[float, Decimal], timeout_unit: TimeUnit = "step", round_mode: Optional[RoundMode] = None, ) -> T: ... @overload async def with_timeout( trigger: Task[T], timeout_time: Union[float, Decimal], timeout_unit: TimeUnit = "step", round_mode: Optional[RoundMode] = None, ) -> T: ... @overload async def with_timeout( trigger: Coroutine[Trigger, None, T], timeout_time: Union[float, Decimal], timeout_unit: TimeUnit = "step", round_mode: Optional[RoundMode] = None, ) -> T: ... async def with_timeout( trigger: Union[TriggerT, Waitable[T], Task[T], Coroutine[Trigger, None, T]], timeout_time: Union[float, Decimal], timeout_unit: TimeUnit = "step", round_mode: Optional[RoundMode] = None, ) -> Union[T, TriggerT]: r"""Wait on triggers or coroutines, throw an exception if it waits longer than the given time. When a :term:`python:coroutine` is passed, the callee coroutine is started, the caller blocks until the callee completes, and the callee's result is returned to the caller. If timeout occurs, the callee is killed and :exc:`SimTimeoutError` is raised. When a :term:`task` is passed, the caller blocks until the callee completes and the callee's result is returned to the caller. If timeout occurs, the callee `continues to run` and :exc:`SimTimeoutError` is raised. If a :class:`~cocotb.triggers.Trigger` or :class:`~cocotb.triggers.Waitable` is passed, the caller blocks until the trigger fires, and the trigger is returned to the caller. If timeout occurs, the trigger is cancelled and :exc:`SimTimeoutError` is raised. Usage: .. code-block:: python await with_timeout(coro, 100, "ns") await with_timeout(First(coro, event.wait()), 100, "ns") Args: trigger: A single object that could be right of an :keyword:`await` expression in cocotb. timeout_time: Simulation time duration before timeout occurs. timeout_unit: Unit of timeout_time, accepts any unit that :class:`~cocotb.triggers.Timer` does. round_mode: String specifying how to handle time values that sit between time steps (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``, ``None``). A ``None`` argument is converted to the current value of :attr:`.Timer.round_mode`. Returns: First trigger that completed if timeout did not occur. Raises: :exc:`SimTimeoutError`: If timeout occurs. .. versionadded:: 1.3 .. versionchanged:: 1.7 Support passing :term:`python:coroutine`\ s. .. versionchanged:: 2.0 Passing ``None`` as the *timeout_unit* argument was removed, use ``'step'`` instead. """ if isinstance(trigger, Coroutine): trigger = cocotb.start_soon(trigger) shielded = False else: shielded = True timeout_timer = Timer(timeout_time, timeout_unit, round_mode=round_mode) res = await First(timeout_timer, trigger) if res is timeout_timer: if not shielded: # shielded = False only when trigger is a Task created to wrap a Coroutine task = cast("Task[object]", trigger) task.cancel() raise SimTimeoutError else: return cast("T | TriggerT", res) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_gpi_triggers.py0000644000175100017510000003157615106067236017711 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """A collection of triggers which a testbench can :keyword:`await`.""" import warnings from decimal import Decimal from fractions import Fraction from typing import ( TYPE_CHECKING, Any, Callable, ClassVar, Generic, Optional, TypeVar, Union, ) import cocotb import cocotb.handle from cocotb import simulator from cocotb._base_triggers import Trigger from cocotb._deprecation import deprecated from cocotb._typing import RoundMode, TimeUnit from cocotb._utils import pointer_str, singleton from cocotb.utils import get_sim_steps, get_time_from_sim_steps if TYPE_CHECKING: from cocotb._py_compat import Self class GPITrigger(Trigger): """A trigger for a simulation event.""" def __init__(self) -> None: super().__init__() self._cbhdl: Optional[simulator.gpi_cb_hdl] = None def _unprime(self) -> None: """Disable a primed trigger, can be re-primed.""" if self._cbhdl is not None: self._cbhdl.deregister() return super()._unprime() def _cleanup(self) -> None: self._cbhdl = None return super()._cleanup() class Timer(GPITrigger): r"""Fire after the specified simulation time period has elapsed. This trigger will *always* consume some simulation time and will return control to the :keyword:`await`\ ing task at the beginning of the time step. Args: time: The time value. .. versionchanged:: 1.5 Previously this argument was misleadingly called `time_ps`. unit: The unit of the time value. One of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``. When *unit* is ``'step'``, the timestep is determined by the simulator (see :make:var:`COCOTB_HDL_TIMEPRECISION`). .. versionchanged:: 2.0 Renamed from ``units``. round_mode: String specifying how to handle time values that sit between time steps (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``, ``None``). A ``None`` argument is converted to the current value of :attr:`.Timer.round_mode`. Raises: ValueError: If a non-positive value is passed for Timer setup. Usage: >>> await Timer(100, unit="ps") The time can also be a ``float``: >>> await Timer(100e-9, unit="sec") which is particularly convenient when working with frequencies: >>> freq = 10e6 # 10 MHz >>> await Timer(1 / freq, unit="sec") Other built-in exact numeric types can be used too: >>> from fractions import Fraction >>> await Timer(Fraction(1, 10), unit="ns") >>> from decimal import Decimal >>> await Timer(Decimal("100e-9"), unit="sec") These are most useful when using computed durations while avoiding floating point inaccuracies. .. versionchanged:: 1.5 Raise an exception when Timer uses a negative value as it is undefined behavior. Warn for 0 as this will cause erratic behavior in some simulators as well. .. versionchanged:: 1.5 Support ``'step'`` as the *unit* argument to mean "simulator time step". .. versionchanged:: 1.6 Support rounding modes. .. versionremoved:: 2.0 Passing ``None`` as the *unit* argument was removed, use ``'step'`` instead. .. versionremoved:: 2.0 The ``time_ps`` parameter was removed, use the ``time`` parameter instead. .. versionchanged:: 2.0 Passing ``0`` as the *time* argument now raises a :exc:`ValueError`. """ round_mode: ClassVar[RoundMode] = "error" """The default rounding mode.""" def __init__( self, time: Union[float, Fraction, Decimal], unit: TimeUnit = "step", *, round_mode: Optional[RoundMode] = None, units: None = None, ) -> None: super().__init__() if time <= 0: raise ValueError("Timer argument time must be positive") if units is not None: warnings.warn( "The 'units' argument has been renamed to 'unit'.", DeprecationWarning, stacklevel=2, ) unit = units if round_mode is None: round_mode = type(self).round_mode self._sim_steps = get_sim_steps(time, unit, round_mode=round_mode) # If we round to 0, we fix it up to 1 step as rounding is imprecise, # and Timer(0) is invalid. if self._sim_steps == 0: self._sim_steps = 1 def _prime(self, callback: Callable[["Self"], None]) -> None: """Register for a timed callback.""" if self._cbhdl is None: self._cbhdl = simulator.register_timed_callback( self._sim_steps, callback, self ) if self._cbhdl is None: raise RuntimeError(f"Unable set up {self!s} Trigger") super()._prime(callback) def __repr__(self) -> str: return "<{} of {:1.2f}ps at {}>".format( type(self).__qualname__, get_time_from_sim_steps(self._sim_steps, unit="ps"), pointer_str(self), ) @singleton class ReadOnly(GPITrigger): """Fires when the current simulation timestep moves to the read-only phase. The read-only phase is entered when the current timestep no longer has any further delta steps. This will be a point where all the signal values are stable as there are no more RTL events scheduled for the timestep. The simulator will not allow scheduling of more events in this timestep. Useful for monitors which need to wait for all processes to execute (both RTL and cocotb) to ensure sampled signal values are final. """ def _prime(self, callback: Callable[["Self"], None]) -> None: if isinstance(current_gpi_trigger(), ReadOnly): raise RuntimeError( "Attempted illegal transition: awaiting ReadOnly in ReadOnly phase" ) if self._cbhdl is None: self._cbhdl = simulator.register_readonly_callback(callback, self) if self._cbhdl is None: raise RuntimeError(f"Unable set up {self!s} Trigger") super()._prime(callback) def __repr__(self) -> str: return f"{type(self).__qualname__}()" @singleton class ReadWrite(GPITrigger): """Fires when the read-write simulation phase is reached.""" def _prime(self, callback: Callable[["Self"], None]) -> None: if isinstance(current_gpi_trigger(), ReadOnly): raise RuntimeError( "Attempted illegal transition: awaiting ReadWrite in ReadOnly phase" ) if self._cbhdl is None: self._cbhdl = simulator.register_rwsynch_callback(callback, self) if self._cbhdl is None: raise RuntimeError(f"Unable set up {self!s} Trigger") super()._prime(callback) def __repr__(self) -> str: return f"{type(self).__qualname__}()" @singleton class NextTimeStep(GPITrigger): """Fires when the next time step is started.""" def _prime(self, callback: Callable[["Self"], None]) -> None: if self._cbhdl is None: self._cbhdl = simulator.register_nextstep_callback(callback, self) if self._cbhdl is None: raise RuntimeError(f"Unable set up {self!s} Trigger") super()._prime(callback) def __repr__(self) -> str: return f"{type(self).__qualname__}()" _SignalType = TypeVar("_SignalType", bound="cocotb.handle.ValueObjectBase[Any, Any]") class _EdgeBase(GPITrigger, Generic[_SignalType]): """Internal base class that fires on a given edge of a signal.""" _edge_type: ClassVar[int] signal: _SignalType @classmethod def _make(cls, signal: _SignalType) -> "Self": self = GPITrigger.__new__(cls) GPITrigger.__init__(self) self.signal = signal return self def __init__(self, _: _SignalType) -> None: pass def _prime(self, callback: Callable[["Self"], None]) -> None: if self._cbhdl is None: self._cbhdl = simulator.register_value_change_callback( self.signal._handle, callback, type(self)._edge_type, self ) if self._cbhdl is None: raise RuntimeError(f"Unable set up {self!s} Trigger") super()._prime(callback) def __repr__(self) -> str: return f"{type(self).__qualname__}({self.signal!r})" class RisingEdge(_EdgeBase["cocotb.handle.LogicObject"]): """Fires on the rising edge of *signal*, on a transition to ``1``. Only valid for scalar ``logic`` or ``bit``-typed signals. Args: signal: The signal upon which to wait for a rising edge. Raises: TypeError: If *signal* is not a 1-bit ``logic`` or ``bit``-typed object. .. note:: Prefer :attr:`await signal.rising_edge ` to ``await RisingEdge(signal)``. .. warning:: On many simulators this will trigger on transitions from non-``0``/``1`` value to ``1``, not just from ``0`` to ``1`` like the ``rising_edge`` function in VHDL. """ _edge_type = simulator.RISING def __new__(cls, signal: "cocotb.handle.LogicObject") -> "RisingEdge": if not (isinstance(signal, cocotb.handle.LogicObject)): raise TypeError( f"{cls.__qualname__} requires a scalar LogicObject. Got {signal!r} of type {type(signal).__qualname__}" ) return signal.rising_edge class FallingEdge(_EdgeBase["cocotb.handle.LogicObject"]): """Fires on the falling edge of *signal*, on a transition to ``0``. Only valid for scalar ``logic`` or ``bit``-typed signals. Args: signal: The signal upon which to wait for a rising edge. Raises: TypeError: If *signal* is not a 1-bit ``logic`` or ``bit``-typed object. .. note:: Prefer :attr:`await signal.falling_edge ` to ``await FallingEdge(signal)``. .. warning:: On many simulators this will trigger on transitions from non-``0``/``1`` value to ``0``, not just from ``1`` to ``0`` like the ``falling_edge`` function in VHDL. """ _edge_type = simulator.FALLING def __new__(cls, signal: "cocotb.handle.LogicObject") -> "FallingEdge": if not (isinstance(signal, cocotb.handle.LogicObject)): raise TypeError( f"{cls.__qualname__} requires a scalar LogicObject. Got {signal!r} of type {type(signal).__qualname__}" ) return signal.falling_edge class ValueChange(_EdgeBase["cocotb.handle._NonIndexableValueObjectBase[Any, Any]"]): """Fires on any value change of *signal*. Args: signal: The signal upon which to wait for a value change. Raises: TypeError: If the signal is not an object which can change value. .. note:: Prefer :attr:`await signal.value_change ` to ``await ValueChange(signal)``. .. versionadded:: 2.0 """ _edge_type = simulator.VALUE_CHANGE def __new__( cls, signal: "cocotb.handle._NonIndexableValueObjectBase[Any, Any]" ) -> "ValueChange": if not isinstance(signal, cocotb.handle._NonIndexableValueObjectBase): raise TypeError( f"{cls.__qualname__} requires a simulation object derived from ValueObjectBase. " f"Got {signal!r} of type {type(signal).__qualname__}" ) return signal.value_change class Edge(ValueChange): """Fires on any value change of *signal*. Args: signal: The signal upon which to wait for a value change. Raises: TypeError: If the signal is not an object which can change value. .. deprecated:: 2.0 Use :attr:`signal.value_change ` instead. """ @deprecated("Use `signal.value_change` instead.") def __new__( cls, signal: "cocotb.handle._NonIndexableValueObjectBase[Any, Any]" ) -> "Edge": if not isinstance(signal, cocotb.handle._NonIndexableValueObjectBase): raise TypeError( f"{cls.__qualname__} requires a simulation object derived from ValueObjectBase. " f"Got {signal!r} of type {type(signal).__qualname__}" ) return signal._edge # The initializer is a lie, but a useful one. Perhaps one day this can be something like `StartupTrigger`.` _current_gpi_trigger = Timer(1, "step") # type: Union[None, GPITrigger] def current_gpi_trigger() -> GPITrigger: """Return the last GPITrigger that fired.""" if _current_gpi_trigger is None: raise RuntimeError("No GPI trigger has fired.") return _current_gpi_trigger ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_init.py0000644000175100017510000002421415106067236016156 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import ast import logging import os import random import sys import time import warnings from pathlib import Path from types import SimpleNamespace from typing import Callable, List, cast import cocotb import cocotb._profiling import cocotb.handle import cocotb.logging import cocotb.simtime import cocotb.simulator from cocotb._scheduler import Scheduler from cocotb.regression import RegressionManager, RegressionMode log: logging.Logger def _setup_logging() -> None: cocotb.log = logging.getLogger("test") cocotb.log.setLevel(logging.INFO) global log log = logging.getLogger("cocotb") _shutdown_callbacks: List[Callable[[], None]] = [] """List of callbacks to be called when cocotb shuts down.""" def _register_shutdown_callback(cb: Callable[[], None]) -> None: """Register a callback to be called when cocotb shuts down.""" _shutdown_callbacks.append(cb) def _shutdown_testbench() -> None: """Call all registered shutdown callbacks.""" while _shutdown_callbacks: cb = _shutdown_callbacks.pop(0) cb() def init_package_from_simulation(argv: List[str]) -> None: """Initialize the cocotb package from a simulation context.""" # register a callback to be called if the simulation fails cocotb.simulator.set_sim_event_callback(_sim_event) cocotb.is_simulation = True cocotb.argv = argv # sys.path normally includes "" (the current directory), but does not appear to when python is embedded. # Add it back because users expect to be able to import files in their test directory. sys.path.insert(0, "") cocotb.logging._init() _setup_logging() # From https://www.python.org/dev/peps/pep-0565/#recommended-filter-settings-for-test-runners # If the user doesn't want to see these, they can always change the global # warning settings in their test module. if not sys.warnoptions: warnings.simplefilter("default") cocotb.SIM_NAME = cocotb.simulator.get_simulator_product().strip() cocotb.SIM_VERSION = cocotb.simulator.get_simulator_version().strip() log.info("Running on %s version %s", cocotb.SIM_NAME, cocotb.SIM_VERSION) cocotb._profiling.initialize() _register_shutdown_callback(cocotb._profiling.finalize) _process_plusargs() _process_packages() _setup_random_seed() _setup_root_handle() _start_user_coverage() cocotb.simtime._init() log.info( "Initialized cocotb v%s from %s", cocotb.__version__, Path(__file__).parent.absolute(), ) def run_regression(_: object) -> None: """Setup and run a regression.""" _setup_regression_manager() # setup global scheduler system cocotb._scheduler_inst = Scheduler() # start Regression Manager log.info("Running tests") cocotb._regression_manager.start_regression() def _sim_event(msg: str) -> None: """Function that can be called externally to signal an event.""" # We simply return here as the simulator will exit # so no cleanup is needed if hasattr(cocotb, "_regression_manager"): cocotb._regression_manager._fail_simulation(msg) else: log.error(msg) _shutdown_testbench() def _process_plusargs() -> None: cocotb.plusargs = {} for option in cocotb.argv: if option.startswith("+"): if option.find("=") != -1: (name, value) = option[1:].split("=", 1) cocotb.plusargs[name] = value else: cocotb.plusargs[option[1:]] = True def _process_packages() -> None: pkg_dict = {} from cocotb import simulator # noqa: PLC0415 pkgs = simulator.package_iterate() if pkgs is None: cocotb.packages = SimpleNamespace() return for pkg in pkgs: handle = cast( "cocotb.handle.HierarchyObject", cocotb.handle._make_sim_object(pkg) ) name = handle._name # Icarus doesn't support named access to package objects: # https://github.com/steveicarus/iverilog/issues/1038 # so we cannot lazily create handles if cocotb.SIM_NAME == "Icarus Verilog": handle._discover_all() pkg_dict[name] = handle cocotb.packages = SimpleNamespace(**pkg_dict) def _start_user_coverage() -> None: coverage_envvar = os.getenv("COCOTB_USER_COVERAGE") if coverage_envvar is None: coverage_envvar = os.getenv("COVERAGE") if coverage_envvar is not None: warnings.warn( "COVERAGE is deprecated in favor of COCOTB_USER_COVERAGE", DeprecationWarning, stacklevel=2, ) if coverage_envvar: try: import coverage # noqa: PLC0415 except ImportError: raise RuntimeError( "Coverage collection requested but coverage module not available. Install it using `pip install coverage`." ) from None else: config_filepath = os.getenv("COVERAGE_RCFILE") if config_filepath is None: # Exclude cocotb itself from coverage collection. log.info( "Collecting coverage of user code. No coverage config file supplied via COVERAGE_RCFILE." ) cocotb_package_dir = Path(__file__).parent.absolute() user_coverage = coverage.coverage( branch=True, omit=[f"{cocotb_package_dir}/*"] ) else: log.info( "Collecting coverage of user code. Coverage config file supplied." ) # Allow the config file to handle all configuration user_coverage = coverage.coverage(config_file=config_filepath) user_coverage.start() def stop_user_coverage() -> None: user_coverage.stop() log.debug("Writing user coverage data") user_coverage.save() _register_shutdown_callback(stop_user_coverage) def _setup_random_seed() -> None: seed_envvar = os.getenv("COCOTB_RANDOM_SEED") if seed_envvar is None: seed_envvar = os.getenv("RANDOM_SEED") if seed_envvar is not None: warnings.warn( "RANDOM_SEED is deprecated in favor of COCOTB_RANDOM_SEED", DeprecationWarning, ) if seed_envvar is None: if "ntb_random_seed" in cocotb.plusargs: warnings.warn( "Passing +ntb_random_seed will not be used to seed Python's random number generator in the future. " "Ensure you also set `COCOTB_RANDOM_SEED`.", FutureWarning, ) plusarg_seed = cocotb.plusargs["ntb_random_seed"] if not isinstance(plusarg_seed, str): raise TypeError("ntb_random_seed plusarg is not a valid seed value.") seed = ast.literal_eval(plusarg_seed) if not isinstance(seed, int): raise TypeError("ntb_random_seed plusargs is not a valid seed value.") cocotb.RANDOM_SEED = seed elif "seed" in cocotb.plusargs: warnings.warn( "Passing +seed will not be used to seed Python's random number generator in the future. " "Ensure you also set `COCOTB_RANDOM_SEED`.", FutureWarning, ) plusarg_seed = cocotb.plusargs["seed"] if not isinstance(plusarg_seed, str): raise TypeError("seed plusarg is not a valid seed value.") seed = ast.literal_eval(plusarg_seed) if not isinstance(seed, int): raise TypeError("seed plusargs is not a valid seed value.") cocotb.RANDOM_SEED = seed else: cocotb.RANDOM_SEED = int(time.time()) log.info("Seeding Python random module with %d", cocotb.RANDOM_SEED) else: cocotb.RANDOM_SEED = ast.literal_eval(seed_envvar) log.info( "Seeding Python random module with supplied seed %d", cocotb.RANDOM_SEED ) random.seed(cocotb.RANDOM_SEED) def _setup_root_handle() -> None: root_name = os.getenv("COCOTB_TOPLEVEL") if root_name is not None: root_name = root_name.strip() if root_name == "": root_name = None elif "." in root_name: # Skip any library component of the toplevel root_name = root_name.split(".", 1)[1] from cocotb import simulator # noqa: PLC0415 handle = simulator.get_root_handle(root_name) if not handle: raise RuntimeError(f"Can not find root handle {root_name!r}") cocotb.top = cocotb.handle._make_sim_object(handle) def _setup_regression_manager() -> None: cocotb._regression_manager = RegressionManager() # discover tests module_str = os.getenv("COCOTB_TEST_MODULES", "") if not module_str: raise RuntimeError( "Environment variable COCOTB_TEST_MODULES, which defines the module(s) to execute, is not defined or empty." ) modules = [s.strip() for s in module_str.split(",") if s.strip()] cocotb._regression_manager.setup_pytest_assertion_rewriting() cocotb._regression_manager.discover_tests(*modules) # filter tests testcase_str = os.getenv("COCOTB_TESTCASE", "").strip() test_filter_str = os.getenv("COCOTB_TEST_FILTER", "").strip() if testcase_str and test_filter_str: raise RuntimeError("Specify only one of COCOTB_TESTCASE or COCOTB_TEST_FILTER") elif testcase_str: warnings.warn( "COCOTB_TESTCASE is deprecated in favor of COCOTB_TEST_FILTER", DeprecationWarning, stacklevel=2, ) filters = [f"{s.strip()}$" for s in testcase_str.split(",") if s.strip()] cocotb._regression_manager.add_filters(*filters) cocotb._regression_manager.set_mode(RegressionMode.TESTCASE) elif test_filter_str: cocotb._regression_manager.add_filters(test_filter_str) cocotb._regression_manager.set_mode(RegressionMode.TESTCASE) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_outcomes.py0000644000175100017510000000243715106067236017054 0ustar00runnerrunner""" Inspired by https://github.com/python-trio/outcome An outcome is similar to the built-in :any:`concurrent.futures.Future` or :any:`asyncio.Future`, but without being tied to a particular task model. """ import abc from typing import Callable, Generic, TypeVar from cocotb._py_compat import ParamSpec from cocotb._utils import remove_traceback_frames T = TypeVar("T") P = ParamSpec("P") def capture( fn: "Callable[P, T]", *args: "P.args", **kwargs: "P.kwargs" ) -> "Outcome[T]": """Obtain an `Outcome` representing the result of a function call.""" try: return Value(fn(*args, **kwargs)) except BaseException as e: e = remove_traceback_frames(e, ["capture"]) return Error(e) class Outcome(Generic[T]): @abc.abstractmethod def get(self) -> T: """Get the value of this outcome, or throw its exception.""" class Value(Outcome[T]): def __init__(self, value: T): self.value = value def get(self) -> T: return self.value def __repr__(self) -> str: return f"Value({self.value!r})" class Error(Outcome[T]): def __init__(self, error: BaseException) -> None: self.error = error def get(self) -> T: raise self.error def __repr__(self) -> str: return f"Error({self.error!r})" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_profiling.py0000644000175100017510000000212215106067236017176 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Debug mode controlled by environment variables import cProfile import os import pstats from cocotb._py_compat import AbstractContextManager, nullcontext profiling_context: AbstractContextManager[None, None] if "COCOTB_ENABLE_PROFILING" in os.environ: _profile: cProfile.Profile def initialize() -> None: global _profile _profile = cProfile.Profile() def finalize() -> None: ps = pstats.Stats(_profile).sort_stats("cumulative") ps.dump_stats("cocotb.pstat") class _profiling_context(AbstractContextManager[None, None]): """Context manager that profiles its contents""" def __enter__(self) -> None: _profile.enable() def __exit__(self, *excinfo: object) -> None: _profile.disable() profiling_context = _profiling_context() else: def initialize() -> None: pass def finalize() -> None: pass profiling_context = nullcontext() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_py_compat.py0000644000175100017510000000732615106067236017213 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """ Backports and compatibility shims for newer python features. These are for internal use - users should use a third party library like `six` if they want to use these shims in their own code """ import sys from abc import ABC from contextlib import AbstractContextManager from typing import TypeVar, Union, overload __all__ = ( "AbstractContextManager", "Final", "Literal", "ParamSpec", "Protocol", "Self", "StrEnum", "TypeAlias", "cached_property", "insertion_ordered_dict", "nullcontext", ) T = TypeVar("T") if sys.version_info < (3, 9): from typing import Generic T_co = TypeVar("T_co", covariant=True) ExitT_co = TypeVar("ExitT_co", covariant=True) class AbstractContextManager(AbstractContextManager, Generic[T_co, ExitT_co]): ... # backport of Python 3.7's contextlib.nullcontext class nullcontext(AbstractContextManager[T, None]): """Context manager that does no additional processing. Used as a stand-in for a normal context manager, when a particular block of code is only sometimes used with a normal context manager: cm = optional_cm if condition else nullcontext() with cm: # Perform operation, using optional_cm if condition is True """ enter_result: T @overload def __init__(self: "nullcontext[None]", enter_result: None = None) -> None: ... @overload def __init__(self: "nullcontext[T]", enter_result: T) -> None: ... def __init__( self: "nullcontext[Union[T, None]]", enter_result: Union[T, None] = None ) -> None: self.enter_result = enter_result def __enter__(self) -> T: return self.enter_result def __exit__(self, *excinfo: object) -> None: pass # On python 3.7 onwards, `dict` is guaranteed to preserve insertion order. # Since `OrderedDict` is a little slower that `dict`, we prefer the latter # when possible. if sys.version_info[:2] >= (3, 7): # noqa: UP036 | bug in ruff insertion_ordered_dict = dict else: import collections insertion_ordered_dict = collections.OrderedDict # simple, but less than optimal backport of Python 3.8's cached_property if sys.version_info >= (3, 8): from functools import cached_property else: from functools import update_wrapper class cached_property: def __init__(self, method): self._method = method update_wrapper(self, method) def __get__(self, instance, owner=None): if instance is None: return self res = self._method(instance) instance.__dict__[self._method.__name__] = res return res if sys.version_info >= (3, 8): from typing import Final, Literal, Protocol else: from typing import Any class FakeGetItemMetatype(type): def __getitem__(cls, a: object) -> Any: return Any class FakeGetItemType(metaclass=FakeGetItemMetatype): ... Final = FakeGetItemType Literal = FakeGetItemType Protocol = ABC if sys.version_info >= (3, 10): from typing import ParamSpec, TypeAlias else: from typing import Any TypeAlias = Any class FakeParamSpecType: def __init__(self, name: str) -> None: ... def kwargs(self) -> Any: return Any def args(self) -> Any: return Any ParamSpec = FakeParamSpecType if sys.version_info >= (3, 11): from typing import Self else: Self = "" if sys.version_info >= (3, 11): from enum import StrEnum else: from enum import Enum class StrEnum(str, Enum): def __str__(self) -> str: return self.value ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_scheduler.py0000755000175100017510000004667715106067236017215 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013, 2018 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """Task scheduler.""" import logging import threading from bdb import BdbQuit from collections import OrderedDict from typing import Any, Callable, Coroutine, Dict, List, TypeVar, Union import cocotb import cocotb._gpi_triggers import cocotb.handle from cocotb import debug from cocotb._base_triggers import Event, Trigger from cocotb._bridge import external_state, external_waiter from cocotb._exceptions import InternalError from cocotb._gpi_triggers import ( GPITrigger, NextTimeStep, ReadWrite, ) from cocotb._outcomes import Error, Outcome, Value, capture from cocotb._profiling import profiling_context from cocotb._py_compat import ParamSpec, insertion_ordered_dict from cocotb.task import Task, _TaskState T = TypeVar("T") P = ParamSpec("P") class Scheduler: """The main Task scheduler. How It Generally Works: Tasks are `queued` to run in the scheduler with :meth:`_queue`. Queueing adds the Task and an Outcome value to :attr:`_pending_tasks`. The main scheduling loop is located in :meth:`_event_loop` and loops over the queued Tasks and `schedules` them. :meth:`_schedule` schedules a Task - continuing its execution from where it previously yielded control - by injecting the Outcome value associated with the Task from the queue. The Task's body will run until it finishes or reaches the next :keyword:`await` statement. If a Task reaches an :keyword:`await`, :meth:`_schedule` will convert the value yielded from the Task into a Trigger with :meth:`_trigger_from_any` and its friend methods. Triggers are then `primed` (with :meth:`~cocotb.triggers.Trigger._prime`) with a `react` function (:meth:`_sim_react` or :meth:`_react) so as to wake up Tasks waiting for that Trigger to `fire` (when the event encoded by the Trigger occurs). This is accomplished by :meth:`_resume_task_upon`. :meth:`_resume_task_upon` also associates the Trigger with the Task waiting on it to fire by adding them to the :attr:`_trigger2tasks` map. If, instead of reaching an :keyword:`await`, a Task finishes, :meth:`_schedule` will cause the :class:`~cocotb.task.Join` trigger to fire. Once a Trigger fires it calls the react function which queues all Tasks waiting for that Trigger to fire. Then the process repeats. When a Task is cancelled (:meth:`_unschedule`), it is removed from the Task queue if it is currently queued. Also, the Task and Trigger are deassociated in the :attr:`_trigger2tasks` map. If the cancelled Task is the last Task waiting on a Trigger, that Trigger is `unprimed` to prevent it from firing. Simulator Phases: All GPITriggers (triggers that are fired by the simulator) go through :meth:`_sim_react` which looks at the fired GPITriggers to determine and track the current simulator phase cocotb is executing in. Normal phase: Corresponds to all non-ReadWrite and non-ReadOnly phases. Any writes are cached for the next ReadWrite phase and do not happen immediately. Scheduling :class:`~cocotb.triggers.ReadWrite` and :class:`~cocotb.triggers.ReadOnly` are valid. ReadWrite phase: Corresponds to ``cbReadWriteSynch`` (VPI) or ``vhpiCbRepLastKnownDeltaCycle`` (VHPI). At the start of scheduling in this phase we play back all the *previously* cached write updates. Any writes are cached for the next ReadWrite phase and do not happen immediately. Scheduling :class:`~cocotb.triggers.ReadWrite` and :class:`~cocotb.triggers.ReadOnly` are valid. One caveat is that scheduling a :class:`~cocotb.triggers.ReadWrite` while in this phase may not be valid. If there were no writes applied at the beginning of this phase, there will be no more events in this time step, and there will not be another ReadWrite phase in this time step. Simulators generally handle this caveat gracefully by leaving you in the ReadWrite phase of the next time step. ReadOnly phase Corresponds to ``cbReadOnlySynch`` (VPI) or ``vhpiCbRepEndOfTimeStep`` (VHPI). In this state we are not allowed to perform writes. Scheduling :class:`~cocotb.triggers.ReadWrite` and :class:`~cocotb.triggers.ReadOnly` are *not* valid. Caveats and Special Cases: The scheduler treats Tests specially. If a Test finishes or a Task ends with an Exception, the scheduler is put into a `terminating` state. All currently queued Tasks are cancelled and all pending Triggers are unprimed. This is currently spread out between :meth:`_handle_termination` and :meth:`_cleanup`. In that mix of functions, the :attr:`_test_complete_cb` callback is called to inform whomever (the regression_manager) the test finished. The scheduler also is responsible for starting the next Test in the Normal phase by priming a ``Timer(1)`` with the second half of test completion handling. The scheduler is currently where simulator time phase is tracked. This is mostly because this is where :meth:`_sim_react` is most conveniently located. The scheduler can't currently be made independent of simulator-specific code because of the above special cases which have to respect simulator phasing. Currently Task cancellation is accomplished with :meth:`Task.kill() `. This function immediately cancels the Task by re-entering the scheduler. This can cause issues if you are trying to cancel the Test Task or the currently executing Task. TODO: There are attributes and methods for dealing with "externals", but I'm not quite sure how it all works yet. """ # Singleton events, recycled to avoid spurious object creation _next_time_step = NextTimeStep() _read_write = ReadWrite() def __init__(self) -> None: self.log = logging.getLogger("cocotb.scheduler") # A dictionary of pending tasks for each trigger, # indexed by trigger self._trigger2tasks: Dict[Trigger, list[Task[object]]] = ( insertion_ordered_dict() ) self._scheduled_tasks: OrderedDict[Task[object], Union[BaseException, None]] = ( OrderedDict() ) self._pending_threads: List[external_waiter[Any]] = [] self._pending_events: List[Event] = [] self._main_thread = threading.current_thread() self._current_task: Union[Task[object], None] = None def _sim_react(self, trigger: GPITrigger) -> None: """Called when a :class:`~cocotb.triggers.GPITrigger` fires. This is often the entry point into Python from the simulator, so this function is in charge of enabling profiling. It must also track the current simulator time phase, and start the unstarted event loop. """ with profiling_context: # TODO: move state tracking to global variable # and handle this via some kind of trigger-specific Python callback cocotb._gpi_triggers._current_gpi_trigger = trigger # apply inertial writes if ReadWrite if trigger is self._read_write: cocotb.handle._apply_scheduled_writes() self._react(trigger) self._event_loop() def _react(self, trigger: Trigger) -> None: """Called when a :class:`~cocotb.triggers.Trigger` fires. Finds all Tasks waiting on the Trigger that fired and queues them. """ if debug.debug: self.log.debug("Trigger fired: %s", trigger) # find all tasks waiting on trigger that fired try: scheduling = self._trigger2tasks.pop(trigger) except KeyError: # GPI triggers should only be ever pending if there is an # associated task waiting on that trigger, otherwise it would # have been unprimed already if isinstance(trigger, GPITrigger): self.log.warning( "No tasks waiting on GPITrigger that fired: %s\n" "This is due to an issue with the GPI or a simulator bug.", trigger, ) # For Python triggers this isn't actually an error - we might do # event.set() without knowing whether any tasks are actually # waiting on this event, for example elif debug.debug: self.log.debug("No tasks waiting on trigger that fired: %s", trigger) return if debug.debug: debugstr = "\n\t".join([str(task) for task in scheduling]) if len(scheduling) > 0: debugstr = "\n\t" + debugstr self.log.debug( "%d pending tasks for trigger %s%s", len(scheduling), trigger, debugstr, ) # queue all tasks to wake up for task in scheduling: # unset trigger task._trigger = None self._schedule_task_internal(task) # cleanup trigger trigger._cleanup() def _event_loop(self) -> None: """Run the main event loop. This should only be started by: * The beginning of a test, when there is no trigger to react to * A GPI trigger """ while self._scheduled_tasks: task, exc = self._scheduled_tasks.popitem(last=False) if debug.debug: self.log.debug("Scheduling task %s", task) self._resume_task(task, exc) if debug.debug: self.log.debug("Scheduled task %s", task) # remove our reference to the objects at the end of each loop, # to try and avoid them being destroyed at a weird time (as # happened in gh-957) del task # Schedule may have queued up some events so we'll burn through those while self._pending_events: if debug.debug: self.log.debug( "Scheduling pending event %s", self._pending_events[0] ) self._pending_events.pop(0).set() # no more pending tasks if debug.debug: self.log.debug("All tasks scheduled, handing control back to simulator") def _unschedule(self, task: Task[Any]) -> None: """Unschedule a task and unprime dangling pending triggers. Also: * enters the scheduler termination state if the Test Task is unscheduled. * creates and fires a :class:`~cocotb.task.Join` trigger. * forcefully ends the Test if a Task ends with an exception. """ # remove task from queue if task in self._scheduled_tasks: self._scheduled_tasks.pop(task) # Unprime the trigger this task is waiting on trigger = task._trigger if trigger is not None: task._trigger = None if task in self._trigger2tasks.setdefault(trigger, []): self._trigger2tasks[trigger].remove(task) if not self._trigger2tasks[trigger]: trigger._unprime() del self._trigger2tasks[trigger] def _schedule_task_upon(self, task: Task[Any], trigger: Trigger) -> None: """Schedule `task` to be resumed when `trigger` fires.""" # TODO Move this all into Task task._trigger = trigger task._state = _TaskState.PENDING trigger_tasks = self._trigger2tasks.setdefault(trigger, []) trigger_tasks.append(task) try: # TODO maybe associate the react method with the trigger object so # we don't have to do a type check here. if isinstance(trigger, GPITrigger): trigger._prime(self._sim_react) else: trigger._prime(self._react) except Exception as e: # discard the trigger we associated, it will never fire self._trigger2tasks.pop(trigger) # replace it with a new trigger that throws back the exception self._schedule_task_internal(task, e) def _schedule_task(self, task: Task[Any]) -> None: """Queue *task* for scheduling. It is an error to attempt to queue a task that has already been queued. """ if task.done(): raise RuntimeError( f"{task} has finished executing and can not be scheduled again. Did you call start_soon() on a finished Task?" ) if task in self._scheduled_tasks: return for tasks in self._trigger2tasks.values(): if task in tasks: return self._schedule_task_internal(task) def _schedule_task_internal( self, task: Task[Any], exc: Union[BaseException, None] = None ) -> None: # TODO Move state tracking into Task task._state = _TaskState.SCHEDULED self._scheduled_tasks[task] = exc def _queue_function(self, task: Coroutine[Trigger, None, T]) -> T: """Queue a task for execution and move the containing thread so that it does not block execution of the main thread any longer. """ # We should be able to find ourselves inside the _pending_threads list matching_threads = [ t for t in self._pending_threads if t.thread == threading.current_thread() ] if len(matching_threads) == 0: raise RuntimeError("queue_function called from unrecognized thread") # Raises if there is more than one match. This can never happen, since # each entry always has a unique thread. (t,) = matching_threads outcome: Union[Outcome[T], None] = None async def wrapper() -> None: nonlocal outcome # This function runs in the scheduler thread try: outcome = Value(await task) except (KeyboardInterrupt, SystemExit, BdbQuit): # Allow these to bubble up to the execution root to fail the sim immediately. # This follows asyncio's behavior. raise except BaseException as e: outcome = Error(e) # Notify the current (scheduler) thread that we are about to wake # up the background (`@external`) thread, making sure to do so # before the background thread gets a chance to go back to sleep by # calling thread_suspend. # We need to do this here in the scheduler thread so that no more # tasks run until the background thread goes back to sleep. t.thread_resume() event.set() event = threading.Event() # must register this with test as there's no way to clean up with threading self._schedule_task_internal(cocotb.start_soon(wrapper())) # The scheduler thread blocks in `thread_wait`, and is woken when we # call `thread_suspend` - so we need to make sure the task is # queued before that. t.thread_suspend() # This blocks the calling `@external` thread until the task finishes event.wait() assert outcome is not None return outcome.get() def _run_in_executor( self, func: "Callable[P, T]", *args: "P.args", **kwargs: "P.kwargs" ) -> Coroutine[Trigger, None, T]: """Run the task in a separate execution thread and return an awaitable object for the caller. """ # Create a thread # Create a trigger that is called as a result of the thread finishing # Create an Event object that the caller can await on # Event object set when the thread finishes execution, this blocks the # calling task (but not the thread) until the external completes waiter = external_waiter[T]() def execute_external() -> None: waiter._outcome = capture(func, *args, **kwargs) if debug.debug: self.log.debug( "Execution of external routine done %s", threading.current_thread() ) waiter.thread_done() async def wrapper() -> T: thread = threading.Thread( group=None, target=execute_external, name=func.__qualname__ + "_thread", ) waiter.thread = thread self._pending_threads.append(waiter) await waiter.event.wait() return waiter.result # raises if there was an exception return wrapper() def _resume_task(self, task: Task[object], exc: Union[BaseException, None]) -> None: """Resume *task* with *outcome*. Args: task: The task to schedule. outcome: The outcome to inject into the *task*. Scheduling runs *task* until it either finishes or reaches the next :keyword:`await` statement. If *task* completes, it is unscheduled, a Join trigger fires, and test completion is inspected. Otherwise, it reached an :keyword:`await` and we have a result object which is converted to a trigger, that trigger is primed, then that trigger and the *task* are registered with the :attr:`_trigger2tasks` map. """ if self._current_task is not None: raise InternalError("_schedule() called while another Task is executing") try: self._current_task = task trigger = task._advance(exc) if task.done(): if debug.debug: self.log.debug("%s completed with %s", task, task._outcome) assert trigger is None self._unschedule(task) if not task.done(): if debug.debug: self.log.debug("%r yielded %s", task, trigger) if not isinstance(trigger, Trigger): e = TypeError( f"Coroutine yielded an object of type {type(trigger)}, which the scheduler can't " f"handle: {trigger!r}\n" ) self._schedule_task_internal(task, e) else: self._schedule_task_upon(task, trigger) # We do not return from here until pending threads have completed, but only # from the main thread, this seems like it could be problematic in cases # where a sim might change what this thread is. if self._main_thread is threading.current_thread(): for ext in self._pending_threads: ext.thread_start() if debug.debug: self.log.debug( "Blocking from %s on %s", threading.current_thread(), ext.thread, ) state = ext.thread_wait() if debug.debug: self.log.debug( "Back from wait on self %s with newstate %s", threading.current_thread(), state, ) if state == external_state.EXITED: self._pending_threads.remove(ext) self._pending_events.append(ext.event) finally: self._current_task = None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_test.py0000644000175100017510000001777715106067236016212 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import inspect import os import pdb from typing import ( Any, Callable, Coroutine, List, Optional, Union, ) import cocotb from cocotb._base_triggers import NullTrigger, Trigger from cocotb._deprecation import deprecated from cocotb._exceptions import InternalError from cocotb._outcomes import Error, Outcome, Value from cocotb._test_functions import TestSuccess from cocotb.task import ResultType, Task _pdb_on_exception = "COCOTB_PDB_ON_EXCEPTION" in os.environ class RunningTest: """State of the currently executing Test.""" # TODO # Make the tasks list a TaskManager. # Make shutdown errors and outcome be an ExceptionGroup from that TaskManager. # Replace result() with passing the outcome to the done callback. # Make this and Task the same object which is a Coroutine. # Reimplement the logic in the body of an async function. # Make RunningTest a normal Task that the RegressionManager runs and registers a # done callback with. def __init__( self, test_complete_cb: Callable[[], None], main_task: Task[None] ) -> None: self._test_complete_cb: Callable[[], None] = test_complete_cb self._main_task: Task[None] = main_task self._main_task._add_done_callback(self._test_done_callback) self.tasks: List[Task[Any]] = [main_task] self._outcome: Union[None, Outcome[None]] = None self._shutdown_errors: list[Outcome[None]] = [] def _test_done_callback(self, task: Task[None]) -> None: self.tasks.remove(task) # If cancelled, end the Test without additional error. This case would only # occur if a child threw a CancelledError or if the Test was forced to shutdown. if task.cancelled(): self.abort(Value(None)) return # Handle outcome appropriately and shut down the Test. e = task.exception() if e is None: self.abort(Value(task.result())) elif isinstance(e, TestSuccess): task._log.info("Test stopped early by this task") self.abort(Value(None)) else: task._log.warning(e, exc_info=e) self.abort(Error(e)) def start(self) -> None: cocotb._scheduler_inst._schedule_task_internal(self._main_task) cocotb._scheduler_inst._event_loop() def result(self) -> Outcome[None]: if self._outcome is None: # pragma: no cover raise InternalError("Getting result before test is completed") if not isinstance(self._outcome, Error) and self._shutdown_errors: return self._shutdown_errors[0] return self._outcome def abort(self, outcome: Outcome[None]) -> None: """Force this test to end early.""" # If we are shutting down, save any errors if self._outcome is not None: if isinstance(outcome, Error): self._shutdown_errors.append(outcome) return # Break into pdb on test end before all Tasks are killed. if _pdb_on_exception and isinstance(outcome, Error): try: pdb.post_mortem(outcome.error.__traceback__) except BaseException: pdb.set_trace() # Set outcome and cancel Tasks. self._outcome = outcome for task in self.tasks[:]: task._cancel_now() self._test_complete_cb() def add_task(self, task: Task[Any]) -> None: self.tasks.append(task) task._add_done_callback(self._task_done_callback) def _task_done_callback(self, task: Task[Any]) -> None: self.tasks.remove(task) # if cancelled, do nothing if task.cancelled(): return # if there's a Task awaiting this one, don't fail if task.complete in cocotb._scheduler_inst._trigger2tasks: return # if no failure, do nothing e = task.exception() if e is None: return # there was a failure and no one is watching, fail test elif isinstance(e, TestSuccess): task._log.info("Test stopped early by this task") self.abort(Value(None)) else: task._log.warning(e, exc_info=e) self.abort(Error(e)) def start_soon( coro: Union[Task[ResultType], Coroutine[Trigger, None, ResultType]], *, name: Optional[str] = None, ) -> Task[ResultType]: """ Schedule a :term:`coroutine` to be run concurrently in a :class:`~cocotb.task.Task`. Note that this is not an :keyword:`async` function, and the new task will not execute until the calling task yields control. Args: coro: A :class:`!Task` or :term:`!coroutine` to be run concurrently. name: The task's name. .. versionadded:: 2.0 Returns: The :class:`~cocotb.task.Task` that is scheduled to be run. .. versionadded:: 1.6 """ task = create_task(coro, name=name) cocotb._scheduler_inst._schedule_task(task) return task @deprecated("Use ``cocotb.start_soon`` instead.") async def start( coro: Union[Task[ResultType], Coroutine[Trigger, None, ResultType]], *, name: Optional[str] = None, ) -> Task[ResultType]: """ Schedule a :term:`coroutine` to be run concurrently, then yield control to allow pending tasks to execute. The calling task will resume execution before control is returned to the simulator. When the calling task resumes, the newly scheduled task may have completed, raised an Exception, or be pending on a :class:`~cocotb.triggers.Trigger`. Args: coro: A :class:`!Task` or :term:`!coroutine` to be run concurrently. name: The task's name. .. versionadded:: 2.0 Returns: The :class:`~cocotb.task.Task` that has been scheduled and allowed to execute. .. versionadded:: 1.6 .. deprecated:: 2.0 Use :func:`cocotb.start_soon` instead. If you need the scheduled Task to start before continuing the current Task, use an :class:`.Event` to block the current Task until the scheduled Task starts, like so: .. code-block:: python async def coro(started: Event) -> None: started.set() # Do stuff... task_started = Event() task = cocotb.start_soon(coro(task_started)) await task_started.wait() """ task = start_soon(coro, name=name) await NullTrigger() return task def create_task( coro: Union[Task[ResultType], Coroutine[Trigger, None, ResultType]], *, name: Optional[str] = None, ) -> Task[ResultType]: """ Construct a :term:`!coroutine` into a :class:`~cocotb.task.Task` without scheduling the task. The task can later be scheduled with :func:`cocotb.start` or :func:`cocotb.start_soon`. Args: coro: A :class:`!Task` or a :term:`!coroutine` to be turned into a :class:`!Task`. name: The task's name. .. versionadded:: 2.0 Returns: Either the provided :class:`~cocotb.task.Task` or a new Task wrapping the coroutine. .. versionadded:: 1.6 """ if isinstance(coro, Task): if name is not None: coro.set_name(name) return coro elif isinstance(coro, Coroutine): task = Task[ResultType](coro, name=name) cocotb._regression_manager._running_test.add_task(task) return task elif inspect.iscoroutinefunction(coro): raise TypeError( f"Coroutine function {coro} should be called prior to being scheduled." ) elif inspect.isasyncgen(coro): raise TypeError( f"{coro.__qualname__} is an async generator, not a coroutine. " "You likely used the yield keyword instead of await." ) else: raise TypeError( f"Attempt to add an object of type {type(coro)} to the scheduler, " f"which isn't a coroutine: {coro!r}\n" ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_test_factory.py0000644000175100017510000002653715106067236017733 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import functools import inspect import logging import warnings from itertools import product from typing import ( TYPE_CHECKING, Callable, Coroutine, Dict, Optional, Sequence, Tuple, Type, Union, cast, overload, ) from cocotb._base_triggers import Trigger from cocotb._decorators import Test from cocotb._typing import TimeUnit if TYPE_CHECKING: from types import FrameType, FunctionType class TestFactory: """Factory to automatically generate tests. Args: test_function: A Callable that returns the test Coroutine. Must take *dut* as the first argument. *args: Remaining arguments are passed directly to the test function. Note that these arguments are not varied. An argument that varies with each test must be a keyword argument to the test function. **kwargs: Remaining keyword arguments are passed directly to the test function. Note that these arguments are not varied. An argument that varies with each test must be a keyword argument to the test function. Assuming we have a common test function that will run a test. This test function will take keyword arguments (for example generators for each of the input interfaces) and generate tests that call the supplied function. This Factory allows us to generate sets of tests based on the different permutations of the possible arguments to the test function. For example, if we have a module that takes backpressure, has two configurable features where enabling ``feature_b`` requires ``feature_a`` to be active, and need to test against data generation routines ``gen_a`` and ``gen_b``: >>> tf = TestFactory(test_function=run_test) >>> tf.add_option(name="data_in", optionlist=[gen_a, gen_b]) >>> tf.add_option("backpressure", [None, random_backpressure]) >>> tf.add_option( ... ("feature_a", "feature_b"), [(False, False), (True, False), (True, True)] ... ) >>> tf.generate_tests() We would get the following tests: * ``gen_a`` with no backpressure and both features disabled * ``gen_a`` with no backpressure and only ``feature_a`` enabled * ``gen_a`` with no backpressure and both features enabled * ``gen_a`` with ``random_backpressure`` and both features disabled * ``gen_a`` with ``random_backpressure`` and only ``feature_a`` enabled * ``gen_a`` with ``random_backpressure`` and both features enabled * ``gen_b`` with no backpressure and both features disabled * ``gen_b`` with no backpressure and only ``feature_a`` enabled * ``gen_b`` with no backpressure and both features enabled * ``gen_b`` with ``random_backpressure`` and both features disabled * ``gen_b`` with ``random_backpressure`` and only ``feature_a`` enabled * ``gen_b`` with ``random_backpressure`` and both features enabled The tests are appended to the calling module for auto-discovery. Tests are simply named ``test_function_N``. The docstring for the test (hence the test description) includes the name and description of each generator. .. versionchanged:: 1.5 Groups of options are now supported .. versionchanged:: 2.0 You can now pass :func:`cocotb.test` decorator arguments when generating tests. .. deprecated:: 2.0 Use :func:`cocotb.parametrize` instead. """ def __init__( self, test_function: Callable[..., Coroutine[Trigger, None, None]], *args: object, **kwargs: object, ) -> None: warnings.warn( "TestFactory is deprecated, use `@cocotb.parametrize` instead", DeprecationWarning, stacklevel=2, ) self.test_function = test_function self.args = args self.kwargs_constant = kwargs self.kwargs: Dict[ Union[str, Sequence[str]], Union[Sequence[object], Sequence[Sequence[object]]], ] = {} self._log = logging.getLogger(f"TestFactory({self.test_function.__name__})") @overload def add_option(self, name: str, optionlist: Sequence[object]) -> None: ... @overload def add_option( self, name: Sequence[str], optionlist: Sequence[Sequence[object]] ) -> None: ... def add_option( self, name: Union[str, Sequence[str]], optionlist: Union[Sequence[object], Sequence[Sequence[object]]], ) -> None: """Add a named option to the test. Args: name: An option name, or an iterable of several option names. Passed to test as keyword arguments. optionlist: A list of possible options for this test knob. If N names were specified, this must be a list of N-tuples or lists, where each element specifies a value for its respective option. .. versionchanged:: 1.5 Groups of options are now supported """ if not isinstance(name, str): optionlist = cast("Sequence[Sequence[object]]", optionlist) for opt in optionlist: if len(name) != len(opt): raise ValueError( "Mismatch between number of options and number of option values in group" ) self.kwargs[name] = optionlist def generate_tests( self, *, prefix: Optional[str] = None, postfix: Optional[str] = None, stacklevel: int = 0, name: Optional[str] = None, timeout_time: Optional[float] = None, timeout_unit: TimeUnit = "step", expect_fail: bool = False, expect_error: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = (), skip: bool = False, stage: int = 0, ) -> None: """ Generate an exhaustive set of tests using the cartesian product of the possible keyword arguments. The generated tests are appended to the namespace of the calling module. Args: prefix: Text string to append to start of ``test_function`` name when naming generated test cases. This allows reuse of a single ``test_function`` with multiple :class:`TestFactories <.TestFactory>` without name clashes. .. deprecated:: 2.0 Use the more flexible ``name`` field instead. postfix: Text string to append to end of ``test_function`` name when naming generated test cases. This allows reuse of a single ``test_function`` with multiple :class:`TestFactories <.TestFactory>` without name clashes. .. deprecated:: 2.0 Use the more flexible ``name`` field instead. stacklevel: Which stack level to add the generated tests to. This can be used to make a custom TestFactory wrapper. name: Passed as ``name`` argument to :func:`cocotb.test`. .. versionadded:: 2.0 timeout_time: Passed as ``timeout_time`` argument to :func:`cocotb.test`. .. versionadded:: 2.0 timeout_unit: Passed as ``timeout_unit`` argument to :func:`cocotb.test`. .. versionadded:: 2.0 expect_fail: Passed as ``expect_fail`` argument to :func:`cocotb.test`. .. versionadded:: 2.0 expect_error: Passed as ``expect_error`` argument to :func:`cocotb.test`. .. versionadded:: 2.0 skip: Passed as ``skip`` argument to :func:`cocotb.test`. .. versionadded:: 2.0 stage: Passed as ``stage`` argument to :func:`cocotb.test`. .. versionadded:: 2.0 """ if prefix is not None: warnings.warn( "``prefix`` argument is deprecated. Use the more flexible ``name`` field instead.", DeprecationWarning, stacklevel=2, ) else: prefix = "" if postfix is not None: warnings.warn( "``postfix`` argument is deprecated. Use the more flexible ``name`` field instead.", DeprecationWarning, stacklevel=2, ) else: postfix = "" # trust the user puts a reasonable stacklevel in glbs = cast("FrameType", inspect.stack()[stacklevel][0].f_back).f_globals test_func_name = self.test_function.__qualname__ if name is None else name for index, testoptions in enumerate( dict(zip(self.kwargs, v)) for v in product(*self.kwargs.values()) ): name = f"{prefix}{test_func_name}{postfix}_{(index + 1):03d}" doc: str = "Automatically generated test\n\n" # preprocess testoptions to split tuples testoptions_split: Dict[str, Sequence[object]] = {} for optname, optvalue in testoptions.items(): if isinstance(optname, str): optvalue = cast("Sequence[object]", optvalue) testoptions_split[optname] = optvalue else: # previously checked in add_option; ensure nothing has changed optvalue = cast("Sequence[Sequence[object]]", optvalue) assert len(optname) == len(optvalue) for n, v in zip(optname, optvalue): testoptions_split[n] = v for optname, optvalue in testoptions_split.items(): if callable(optvalue): optvalue = cast("FunctionType", optvalue) if optvalue.__doc__ is None: desc = "No docstring supplied" else: desc = optvalue.__doc__.split("\n")[0] doc += f"\t{optname}: {optvalue.__qualname__} ({desc})\n" else: doc += f"\t{optname}: {optvalue!r}\n" kwargs = self.kwargs_constant.copy() kwargs.update(testoptions_split) @functools.wraps(self.test_function) async def _my_test(dut: object, kwargs: Dict[str, object] = kwargs) -> None: await self.test_function(dut, *self.args, **kwargs) _my_test.__doc__ = doc _my_test.__name__ = name _my_test.__qualname__ = name if name in glbs: self._log.error( "Overwriting %s in module %s. " "This causes a previously defined testcase not to be run. " "Consider using the `name`, `prefix`, or `postfix` arguments to augment the name.", name, glbs["__name__"], ) test = Test( func=_my_test, name=name, module=glbs["__name__"], timeout_time=timeout_time, timeout_unit=timeout_unit, expect_fail=expect_fail, expect_error=expect_error, skip=skip, stage=stage, ) glbs[test.name] = test ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_test_functions.py0000644000175100017510000000214215106067236020256 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """Collection of functions to control a running test and related exceptions.""" from typing import NoReturn, Type, Union Failed: Type[BaseException] try: import pytest except ModuleNotFoundError: Failed = AssertionError else: try: with pytest.raises(Exception): pass except BaseException as _raises_e: Failed = type(_raises_e) else: assert False, "pytest.raises doesn't raise an exception when it fails" class TestSuccess(BaseException): """Implementation of :func:`pass_test`. Users are *not* intended to catch this exception type. """ def __init__(self, msg: Union[str, None]) -> None: super().__init__(msg) self.msg = msg def pass_test(msg: Union[str, None] = None) -> NoReturn: """Force a test to pass. The test will end and enter termination phase when this is called. Args: msg: The message to display when the test passes. """ raise TestSuccess(msg) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_typing.py0000644000175100017510000000051215106067236016520 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause from cocotb._py_compat import Literal, TypeAlias RoundMode: TypeAlias = Literal["error", "round", "ceil", "floor"] TimeUnit: TypeAlias = Literal["step", "fs", "ps", "ns", "us", "ms", "sec"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_utils.py0000644000175100017510000002001715106067236016350 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """Utilities for implementors.""" import traceback import types from enum import Enum, IntEnum from functools import update_wrapper, wraps from types import TracebackType from typing import ( TYPE_CHECKING, Any, Iterable, List, Optional, Tuple, Type, TypeVar, Union, cast, overload, ) ExceptionTuple = Tuple[ Type[BaseException], BaseException, TracebackType ] # TypeAlias in Python 3.10 @overload def remove_traceback_frames( tb_or_exc: ExceptionTuple, frame_names: List[str] ) -> ExceptionTuple: ... @overload def remove_traceback_frames( tb_or_exc: BaseException, frame_names: List[str] ) -> BaseException: ... @overload def remove_traceback_frames( tb_or_exc: TracebackType, frame_names: List[str] ) -> TracebackType: ... def remove_traceback_frames( tb_or_exc: Union[ExceptionTuple, BaseException, TracebackType], frame_names: List[str], ) -> Union[ExceptionTuple, BaseException, TracebackType]: """ Strip leading frames from a traceback Args: tb_or_exc: Object to strip frames from. If an exception is passed, creates a copy of the exception with a new shorter traceback. If a tuple from `sys.exc_info` is passed, returns the same tuple with the traceback shortened frame_names: Names of the frames to strip, which must be present at the top of the Traceback or Exception. Returns: Traceback or Exception passed to the function with the *frame_names* stripped out. """ # self-invoking overloads if isinstance(tb_or_exc, BaseException): exc: BaseException = tb_or_exc return exc.with_traceback( remove_traceback_frames( cast("TracebackType", exc.__traceback__), frame_names ) ) elif isinstance(tb_or_exc, tuple): exc_type, exc_value, exc_tb = tb_or_exc exc_tb = remove_traceback_frames(exc_tb, frame_names) return exc_type, exc_value, exc_tb # base case else: tb: TracebackType = tb_or_exc for frame_name in frame_names: # the assert and cast are there assuming the frame_names being removed are correct assert tb.tb_frame.f_code.co_name == frame_name tb = cast("TracebackType", tb.tb_next) return tb def walk_coro_stack( coro: "types.CoroutineType[Any, Any, Any]", ) -> Iterable[Tuple[types.FrameType, int]]: """Walk down the coroutine stack, starting at *coro*. Args: coro: The :class:`coroutine` object to traverse. Yields: Frame and line number of each frame in the coroutine. """ c: Optional[types.CoroutineType[Any, Any, Any]] = coro while c is not None: try: f = c.cr_frame except AttributeError: break else: c = c.cr_await if f is not None: yield (f, f.f_lineno) def extract_coro_stack( coro: "types.CoroutineType[Any, Any, Any]", limit: Optional[int] = None ) -> traceback.StackSummary: r"""Create a list of pre-processed entries from the coroutine stack. This is based on :func:`traceback.extract_tb`. If *limit* is omitted or ``None``, all entries are extracted. The list is a :class:`traceback.StackSummary` object, and each entry in the list is a :class:`traceback.FrameSummary` object containing attributes ``filename``, ``lineno``, ``name``, and ``line`` representing the information that is usually printed for a stack trace. The line is a string with leading and trailing whitespace stripped; if the source is not available it is ``None``. Args: coro: The :class:`coroutine` object from which to extract a stack. level: The maximum number of frames from *coro*\ s stack to extract. Returns: The stack of *coro*. """ return traceback.StackSummary.extract(walk_coro_stack(coro), limit=limit) EnumT = TypeVar("EnumT", bound=Enum) class DocEnum(Enum): """Like :class:`enum.Enum`, but allows documenting enum values. Documentation for enum members can be optionally added by setting enum values to a tuple of the intended value and the docstring. This adds the provided docstring to the ``__doc__`` field of the enum value. .. code-block:: python class MyEnum(DocEnum): \"\"\"Class documentation\"\"\" VALUE1 = 1, "Value documentation" VALUE2 = 2 # no documentation Taken from :ref:`this StackOverflow answer ` by :ref:`Eric Wieser `, as recommended by the ``enum_tools`` documentation. """ def __new__(cls: Type[EnumT], value: object, doc: Optional[str] = None) -> EnumT: # super().__new__() assumes the value is already an enum value # so we side step that and create a raw object and fill in _value_ self = object.__new__(cls) self._value_ = value if doc is not None: self.__doc__ = doc return self IntEnumT = TypeVar("IntEnumT", bound=IntEnum) class DocIntEnum(IntEnum): """Like DocEnum but for :class:`IntEnum` enum types.""" def __new__(cls: Type[IntEnumT], value: int, doc: Optional[str] = None) -> IntEnumT: self = int.__new__(cls, value) self._value_ = value if doc is not None: self.__doc__ = doc return self if TYPE_CHECKING: F = TypeVar("F") def cached_method(f: F) -> F: ... else: class cached_method: def __init__(self, method): self._method = method update_wrapper(self, method) def __get__(self, instance, objtype=None): if instance is None: return self cache = {} @wraps(self._method) def lookup(*args, **kwargs): key = (args, tuple(kwargs.items())) try: return cache[key] except KeyError: res = self._method(instance, *args, **kwargs) cache[key] = res return res lookup.cache = cache setattr(instance, self._method.__name__, lookup) return lookup def __call__(self, instance, *args, **kwargs): func = getattr(instance, self._method.__name__) return func(*args, **kwargs) T = TypeVar("T") if TYPE_CHECKING: def singleton(orig_cls: T) -> T: ... else: def singleton(orig_cls): """Class decorator which turns a type into a Singleton type.""" orig_new = orig_cls.__new__ orig_init = orig_cls.__init__ instance = None @wraps(orig_cls.__new__) def __new__(cls, *args, **kwargs): nonlocal instance if instance is None: instance = orig_new(cls, *args, **kwargs) orig_init(instance, *args, **kwargs) return instance @wraps(orig_cls.__init__) def __init__(self, *args, **kwargs): pass orig_cls.__new__ = __new__ orig_cls.__init__ = __init__ return orig_cls def pointer_str(obj: object) -> str: """Get the memory address of *obj* as used in :meth:`object.__repr__`. This is equivalent to ``sprintf("%p", id(obj))``, but Python does not support ``%p``. """ full_repr = object.__repr__(obj) # gives "<{type} object at {address}>" return full_repr.rsplit(" ", 1)[1][:-1] def safe_divide(a: float, b: float) -> float: """Used when computing time ratios to ensure no exception is raised if either time is 0.""" try: return a / b except ZeroDivisionError: if a == 0: return float("nan") else: return float("inf") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3427024 cocotb-2.0.1/src/cocotb/_vendor/0000755000175100017510000000000015106070715016127 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/README.md0000644000175100017510000000221615106067236017413 0ustar00runnerrunner# Third-party code This directory contains code from various third parties, which is distributed together with cocotb. Note that some code may be licensed differently from cocotb itself; refer to the individual files for details. ## SystemVerilog VPI The headers `vpi/vpi_user.h` and `vpi/sv_vpi_user.sv` are part of the SystemVerilog LRM. ## VHPI The header `vhpi/vhpi_user.h` is part of the VHPI/VHDL standard. ## ModelSim/Questa FLI The header `fli/mti.h` is part of the Siemens EDA Questa distribution and distributed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). The header `fli/acc_user.h` defines the PLI ACC (access) routines. The file is part of the [Verilog 2001 LRM](https://standards.ieee.org/ieee/1364/2052/) (IEEE 1364-2001), Annex E, and is shipped in a version as modified by Siemens EDA. The header `fli/acc_vhdl.h` is a ModelSim/Questa extension to the PLI standard to support VHDL. ## TCL The files in the `tcl` directory are part of the [Tcl 8.6.5 source code](https://www.tcl.tk/software/tcltk/download.html), which is distributed under a BSD license. Refer to `tcl/license.terms` for details. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3437026 cocotb-2.0.1/src/cocotb/_vendor/fli/0000755000175100017510000000000015106070715016701 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/fli/acc_user.h0000644000175100017510000006140515106067236020650 0ustar00runnerrunner/***************************************************************************** * acc_user.h * * IEEE 1364-2001 Verilog HDL Programming Language Interface (PLI). * * This file contains the constant definitions, structure definitions, and * routine declarations for the Verilog Programming Language Interface ACC * access routines. * ****************************************************************************/ /* $Id: //dvt/mti/rel/2021.4/src/vsim/acc_user.h#1 $ */ #ifndef ACC_USER_H #define ACC_USER_H #ifdef __cplusplus extern "C" { #endif /*---------------------------------------------------------------------------*/ /*--------------------------- Portability Help ------------------------------*/ /*---------------------------------------------------------------------------*/ /* Sized variables */ #ifndef PLI_TYPES #define PLI_TYPES typedef int PLI_INT32; typedef unsigned int PLI_UINT32; typedef short PLI_INT16; typedef unsigned short PLI_UINT16; typedef char PLI_BYTE8; typedef unsigned char PLI_UBYTE8; #endif /* import a symbol into dll */ #if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)) #ifndef PLI_DLLISPEC #define PLI_DLLISPEC __declspec(dllimport) #define ACC_USER_DEFINED_DLLISPEC 1 #endif #else #ifndef PLI_DLLISPEC #define PLI_DLLISPEC #endif #endif /* export a symbol from dll */ #if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)) #ifndef PLI_DLLESPEC #define PLI_DLLESPEC __declspec(dllexport) #define ACC_USER_DEFINED_DLLESPEC 1 #endif #else #ifndef PLI_DLLESPEC #define PLI_DLLESPEC #endif #endif /* mark a function as external */ #ifndef PLI_EXTERN #define PLI_EXTERN #endif /* mark a variable as external */ #ifndef PLI_VEXTERN #define PLI_VEXTERN extern #endif #ifndef PLI_PROTOTYPES #define PLI_PROTOTYPES #define PROTO_PARAMS(params) params /* object is imported by the dll */ #define XXTERN PLI_EXTERN PLI_DLLISPEC /* object is exported by the dll */ #define EETERN PLI_EXTERN PLI_DLLESPEC #endif /* * The following group of defines exists purely for backwards compatibility */ #ifndef PLI_EXTRAS #define PLI_EXTRAS /* guard bool/true/false when compiling with C++, C99 or later */ #if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)) #define bool int #define true 1 #define TRUE 1 #define false 0 #define FALSE 0 #endif #define null 0L #define global extern #define local static #define exfunc #endif /*---------------------------------------------------------------------------*/ /*------------------------------- definitions -------------------------------*/ /*---------------------------------------------------------------------------*/ /*----------------------------- general defines -----------------------------*/ typedef void *HANDLE; #ifndef VPI_USER_CDS_H typedef void *handle; #endif #define OPEN_HANDLE_REP ((handle)0x1) #define HANDLE_IS_OPEN(hand) ((hand) == OPEN_HANDLE_REP) /*------------------------------- object types ------------------------------*/ #define accModule 20 #define accScope 21 #define accNet 25 #define accReg 30 #define accRegister accReg #define accPort 35 #define accTerminal 45 #define accInputTerminal 46 #define accOutputTerminal 47 #define accInoutTerminal 48 #define accCombPrim 140 #define accSeqOptPrim 141 #define accSeqPrim 142 #define accAndGate 144 #define accNandGate 146 #define accNorGate 148 #define accOrGate 150 #define accXorGate 152 #define accXnorGate 154 #define accBufGate 156 #define accNotGate 158 #define accBufif0Gate 160 #define accBufif1Gate 162 #define accNotif0Gate 164 #define accNotif1Gate 166 #define accNmosGate 168 #define accPmosGate 170 #define accCmosGate 172 #define accRnmosGate 174 #define accRpmosGate 176 #define accRcmosGate 178 #define accRtranGate 180 #define accRtranif0Gate 182 #define accRtranif1Gate 184 #define accTranGate 186 #define accTranif0Gate 188 #define accTranif1Gate 190 #define accPullupGate 192 #define accPulldownGate 194 #define accIntegerParam 200 #define accIntParam accIntegerParam #define accRealParam 202 #define accStringParam 204 #define accPath 206 #define accTchk 208 #define accPrimitive 210 #define accBit 212 #define accPortBit 214 #define accNetBit 216 #define accRegBit 218 #define accParameter 220 #define accSpecparam 222 #define accSpecParam accSpecparam #define accTopModule 224 #define accModuleInstance 226 #define accCellInstance 228 #define accModPath 230 #define accWirePath 234 #define accInterModPath 236 #define accScalarPort 250 #define accBitSelectPort 252 #define accPartSelectPort 254 #define accVectorPort 256 #define accConcatPort 258 #define accWire 260 #define accWand 261 #define accWor 262 #define accTri 263 #define accTriand 264 #define accTrior 265 #define accTri0 266 #define accTri1 267 #define accTrireg 268 #define accSupply0 269 #define accSupply1 270 #define accNamedEvent 280 #define accEventVar accNamedEvent #define accIntegerVar 281 #define accIntVar 281 #define accRealVar 282 #define accTimeVar 283 #define accScalar 300 #define accVector 302 #define accCollapsedNet 304 #define accExpandedVector 306 #define accUnExpandedVector 307 #define accProtected 308 #define accSetup 366 #define accHold 367 #define accWidth 368 #define accPeriod 369 #define accRecovery 370 #define accSkew 371 #define accTimeSkew 381 #define accFullSkew 382 #define accRemoval 372 #define accRecrem 373 #define accNochange 376 #define accNoChange accNochange #define accSetuphold 377 #define accInput 402 #define accOutput 404 #define accInout 406 #define accMixedIo 407 #define accPositive 408 #define accNegative 410 #define accUnknown 412 #define accPathTerminal 420 #define accPathInput 422 #define accPathOutput 424 #define accDataPath 426 #define accTchkTerminal 428 #define accBitSelect 500 #define accPartSelect 502 #define accTask 504 #define accFunction 506 #define accStatement 508 #define accTaskCall 510 #define accFunctionCall 512 #define accSystemTask 514 #define accSystemFunction 516 #define accSystemRealFunction 518 #define accUserTask 520 #define accUserFunction 522 #define accUserRealFunction 524 #define accNamedBeginStat 560 #define accNamedForkStat 564 #define accNamedForeachStmt 565 #define accConstant 600 #define accConcat 610 #define accOperator 620 #define accMinTypMax 696 #define accModPathHasIfnone 715 #define accSeqOptFastPrim_1 801 #define accSeqOptFastPrim_2 802 #define accSeqOptFastPrim_3 803 #define accSeqOptFastPrim_4 804 #define accSeqOptFastPrim_5 805 #define accSeqOptFastPrim_6 806 #define accSeqOptFastPrim_7 807 #define accSeqOptFastPrim_8 808 #define accModportTask 809 /*------------------ parameter values for acc_configure() -------------------*/ #define accPathDelayCount 1 #define accPathDelimStr 2 #define accDisplayErrors 3 #define accDefaultAttr0 4 #define accToHiZDelay 5 #define accEnableArgs 6 #define accDisplayWarnings 8 #define accDevelopmentVersion 11 #define accMapToMipd 17 #define accMinTypMaxDelays 19 /*------------ edge information used by acc_handle_tchk(), etc. ------------*/ #define accNoedge 0 #define accNoEdge 0 #define accEdge01 1 #define accEdge10 2 #define accEdge0x 4 #define accEdgex1 8 #define accEdge1x 16 #define accEdgex0 32 #define accPosedge 13 #define accPosEdge accPosedge #define accNegedge 50 #define accNegEdge accNegedge /*------------------------------- delay modes -------------------------------*/ #define accDelayModeNone 0 #define accDelayModePath 1 #define accDelayModeDistrib 2 #define accDelayModeUnit 3 #define accDelayModeZero 4 #define accDelayModeMTM 5 #define accDelayModeSUDP 6 /*------------ values for type field in t_setval_delay structure ------------*/ #define accNoDelay 0 #define accInertialDelay 1 #define accTransportDelay 2 #define accPureTransportDelay 3 #define accForceFlag 4 #define accReleaseFlag 5 #define accAssignFlag 6 #define accDeassignFlag 7 /*------------ values for type field in t_setval_value structure ------------*/ #define accBinStrVal 1 #define accOctStrVal 2 #define accDecStrVal 3 #define accHexStrVal 4 #define accScalarVal 5 #define accIntVal 6 #define accRealVal 7 #define accStringVal 8 #define accVectorVal 10 /*------------------------------ scalar values ------------------------------*/ #define acc0 0 #define acc1 1 #define accX 2 #define accZ 3 /*---------------------------- VCL scalar values ----------------------------*/ #define vcl0 acc0 #define vcl1 acc1 #define vclX accX #define vclx vclX #define vclZ accZ #define vclz vclZ /*----------- values for vc_reason field in t_vc_record structure -----------*/ #define logic_value_change 1 #define strength_value_change 2 #define real_value_change 3 #define vector_value_change 4 #define event_value_change 5 #define integer_value_change 6 #define time_value_change 7 #define sregister_value_change 8 #define vregister_value_change 9 #define realtime_value_change 10 /*--------------------------- VCL strength values ---------------------------*/ #define vclSupply 7 #define vclStrong 6 #define vclPull 5 #define vclLarge 4 #define vclWeak 3 #define vclMedium 2 #define vclSmall 1 #define vclHighZ 0 /*----------------------- vcl bit flag definitions -------------------------*/ #define vcl_strength_flag 1 #define vcl_verilog_flag 2 /*----------------------- flags used with acc_vcl_add -----------------------*/ #define vcl_verilog_logic 2 #define VCL_VERILOG_LOGIC vcl_verilog_logic #define vcl_verilog_strength 3 #define VCL_VERILOG_STRENGTH vcl_verilog_strength /*---------------------- flags used with acc_vcl_delete ---------------------*/ #define vcl_verilog vcl_verilog_logic #define VCL_VERILOG vcl_verilog /*---------- values for the type field in the t_acc_time structure --------- */ #define accTime 1 #define accSimTime 2 #define accRealTime 3 /*------------------------------ product types ------------------------------*/ #define accSimulator 1 #define accTimingAnalyzer 2 #define accFaultSimulator 3 #define accOther 4 /*---------------------------------------------------------------------------*/ /*-------------------------- structure definitions --------------------------*/ /*---------------------------------------------------------------------------*/ typedef struct t_vc_record *p_vc_record; typedef PLI_INT32 (*consumer_function)(p_vc_record); /*----------------- data structure used with acc_set_value() ----------------*/ typedef struct t_acc_time { PLI_INT32 type; PLI_INT32 low, high; double real; } s_acc_time, *p_acc_time; /*----------------- data structure used with acc_set_value() ----------------*/ typedef struct t_setval_delay { s_acc_time time; PLI_INT32 model; } s_setval_delay, *p_setval_delay; /*--------------------- data structure of vector values ---------------------*/ typedef struct t_acc_vecval { PLI_INT32 aval; PLI_INT32 bval; } s_acc_vecval, *p_acc_vecval; /*------ data structure used with acc_set_value() and acc_fetch_value() -----*/ typedef struct t_setval_value { PLI_INT32 format; union { PLI_BYTE8 *str; PLI_INT32 scalar; PLI_INT32 integer; double real; p_acc_vecval vector; } value; } s_setval_value, *p_setval_value, s_acc_value, *p_acc_value; /*----------------------- structure for VCL strengths -----------------------*/ typedef struct t_strengths { PLI_UBYTE8 logic_value; PLI_UBYTE8 strength1; PLI_UBYTE8 strength2; } s_strengths, *p_strengths; /*--------------- structure passed to callback routine for VCL --------------*/ typedef struct t_vc_record { PLI_INT32 vc_reason; PLI_INT32 vc_hightime; PLI_INT32 vc_lowtime; PLI_BYTE8 *user_data; union { PLI_UBYTE8 logic_value; double real_value; handle vector_handle; s_strengths strengths_s; } out_value; } s_vc_record; /*------------- structure used with acc_fetch_location() routine ------------*/ typedef struct t_location { PLI_INT32 line_no; PLI_BYTE8 *filename; } s_location, *p_location; /*---------- structure used with acc_fetch_timescale_info() routine ---------*/ typedef struct t_timescale_info { PLI_INT16 unit; PLI_INT16 precision; } s_timescale_info, *p_timescale_info; /*---------------------------------------------------------------------------*/ /*-------------------------- routine declarations ---------------------------*/ /*---------------------------------------------------------------------------*/ XXTERN PLI_INT32 acc_append_delays PROTO_PARAMS((handle object, ...)); XXTERN PLI_INT32 acc_append_pulsere PROTO_PARAMS((handle object, double val1r, double val1x, ...)); XXTERN void acc_close PROTO_PARAMS((void)); XXTERN handle *acc_collect PROTO_PARAMS((handle (*p_next_routine)(handle object_handle, handle obj), handle scope_object, PLI_INT32 *aof_count)); XXTERN PLI_INT32 acc_compare_handles PROTO_PARAMS((handle h1, handle h2)); XXTERN PLI_INT32 acc_configure PROTO_PARAMS((PLI_INT32 item, PLI_BYTE8 *value)); XXTERN PLI_INT32 acc_count PROTO_PARAMS((handle (*next_func)(handle object_handle, handle obj), handle object_handle)); XXTERN char *acc_decompile_exp PROTO_PARAMS((handle condition )); XXTERN PLI_INT32 *acc_error_flag_address PROTO_PARAMS((void)); XXTERN PLI_INT32 acc_fetch_argc PROTO_PARAMS((void)); XXTERN PLI_BYTE8 **acc_fetch_argv PROTO_PARAMS((void)); XXTERN double acc_fetch_attribute PROTO_PARAMS((handle object, PLI_BYTE8 *attribute_string, ...)); XXTERN PLI_INT32 acc_fetch_attribute_int PROTO_PARAMS((handle object, PLI_BYTE8 *attribute_string, ...)); XXTERN PLI_BYTE8 *acc_fetch_attribute_str PROTO_PARAMS((handle object, PLI_BYTE8 *attribute_string, ...)); XXTERN PLI_BYTE8 *acc_fetch_defname PROTO_PARAMS((handle object_handle)); XXTERN PLI_INT32 acc_fetch_delay_mode PROTO_PARAMS((handle object_p)); XXTERN PLI_INT32 acc_fetch_delays PROTO_PARAMS((handle object, ...)); XXTERN PLI_INT32 acc_fetch_direction PROTO_PARAMS((handle object_handle)); XXTERN PLI_INT32 acc_fetch_edge PROTO_PARAMS((handle acc_obj)); XXTERN PLI_BYTE8 *acc_fetch_fullname PROTO_PARAMS((handle object_handle)); XXTERN PLI_INT32 acc_fetch_fulltype PROTO_PARAMS((handle object_h)); XXTERN PLI_INT32 acc_fetch_index PROTO_PARAMS((handle object_handle)); XXTERN double acc_fetch_itfarg PROTO_PARAMS((PLI_INT32 n, handle tfinst)); XXTERN PLI_INT32 acc_fetch_itfarg_int PROTO_PARAMS((PLI_INT32 n, handle tfinst)); XXTERN PLI_BYTE8 *acc_fetch_itfarg_str PROTO_PARAMS((PLI_INT32 n, handle tfinst)); XXTERN PLI_INT32 acc_fetch_location PROTO_PARAMS((p_location location_p, handle object)); XXTERN PLI_BYTE8 *acc_fetch_name PROTO_PARAMS((handle object_handle)); XXTERN PLI_INT32 acc_fetch_paramtype PROTO_PARAMS((handle param_p)); XXTERN double acc_fetch_paramval PROTO_PARAMS((handle param)); XXTERN char *acc_fetch_paramval_str PROTO_PARAMS((handle param)); XXTERN PLI_INT32 acc_fetch_polarity PROTO_PARAMS((handle path)); XXTERN PLI_INT32 acc_fetch_precision PROTO_PARAMS((void)); XXTERN PLI_INT32 acc_fetch_pulsere PROTO_PARAMS((handle path_p, double *val1r, double *val1e, ...)); XXTERN PLI_INT32 acc_fetch_range PROTO_PARAMS((handle node, PLI_INT32 *msb, PLI_INT32 *lsb)); XXTERN PLI_INT32 acc_fetch_size PROTO_PARAMS((handle obj_h)); XXTERN double acc_fetch_tfarg PROTO_PARAMS((PLI_INT32 n)); XXTERN PLI_INT32 acc_fetch_tfarg_int PROTO_PARAMS((PLI_INT32 n)); XXTERN PLI_BYTE8 *acc_fetch_tfarg_str PROTO_PARAMS((PLI_INT32 n)); XXTERN void acc_fetch_timescale_info PROTO_PARAMS((handle obj, p_timescale_info aof_timescale_info)); XXTERN PLI_INT32 acc_fetch_type PROTO_PARAMS((handle object_handle)); XXTERN PLI_BYTE8 *acc_fetch_type_str PROTO_PARAMS((PLI_INT32 type)); XXTERN PLI_BYTE8 *acc_fetch_value PROTO_PARAMS((handle object_handle, PLI_BYTE8 *format_str, p_acc_value acc_value_p)); XXTERN void acc_free PROTO_PARAMS((handle *array_ptr)); XXTERN handle acc_handle_by_name PROTO_PARAMS((PLI_BYTE8 *inst_name, handle scope_p)); XXTERN handle acc_handle_condition PROTO_PARAMS((handle obj)); XXTERN handle acc_handle_conn PROTO_PARAMS((handle term_p)); XXTERN handle acc_handle_datapath PROTO_PARAMS((handle path)); XXTERN handle acc_handle_hiconn PROTO_PARAMS((handle port_ref)); XXTERN handle acc_handle_interactive_scope PROTO_PARAMS((void)); XXTERN handle acc_handle_itfarg PROTO_PARAMS((PLI_INT32 n, handle tfinst)); XXTERN handle acc_handle_loconn PROTO_PARAMS((handle port_ref)); XXTERN handle acc_handle_modpath PROTO_PARAMS((handle mod_p, PLI_BYTE8 *pathin_name, PLI_BYTE8 *pathout_name, ...)); XXTERN handle acc_handle_notifier PROTO_PARAMS((handle tchk)); XXTERN handle acc_handle_object PROTO_PARAMS((PLI_BYTE8 *inst_name)); XXTERN handle acc_handle_parent PROTO_PARAMS((handle object_p)); XXTERN handle acc_handle_path PROTO_PARAMS((handle source, handle destination)); XXTERN handle acc_handle_pathin PROTO_PARAMS((handle path_p)); XXTERN handle acc_handle_pathout PROTO_PARAMS((handle path_p)); XXTERN handle acc_handle_port PROTO_PARAMS((handle mod_handle, PLI_INT32 port_num)); XXTERN handle acc_handle_scope PROTO_PARAMS((handle object)); XXTERN handle acc_handle_simulated_net PROTO_PARAMS((handle net_h)); XXTERN handle acc_handle_tchk PROTO_PARAMS((handle mod_p, PLI_INT32 tchk_type, PLI_BYTE8 *arg1_conn_name, PLI_INT32 arg1_edgetype, ...)); XXTERN handle acc_handle_tchkarg1 PROTO_PARAMS((handle tchk)); XXTERN handle acc_handle_tchkarg2 PROTO_PARAMS((handle tchk)); XXTERN handle acc_handle_terminal PROTO_PARAMS((handle gate_handle, PLI_INT32 terminal_index)); XXTERN handle acc_handle_tfarg PROTO_PARAMS((PLI_INT32 n)); XXTERN handle acc_handle_tfinst PROTO_PARAMS((void)); XXTERN PLI_INT32 acc_initialize PROTO_PARAMS((void)); XXTERN handle acc_next PROTO_PARAMS((PLI_INT32 *type_list, handle h_scope, handle h_object)); XXTERN handle acc_next_bit PROTO_PARAMS ((handle vector, handle bit)); XXTERN handle acc_next_cell PROTO_PARAMS((handle scope, handle cell)); XXTERN handle acc_next_cell_load PROTO_PARAMS((handle net_handle, handle load)); XXTERN handle acc_next_child PROTO_PARAMS((handle mod_handle, handle child)); XXTERN handle acc_next_driver PROTO_PARAMS((handle net, handle driver)); XXTERN handle acc_next_hiconn PROTO_PARAMS((handle port, handle hiconn)); XXTERN handle acc_next_input PROTO_PARAMS((handle path, handle pathin)); XXTERN handle acc_next_load PROTO_PARAMS((handle net, handle load)); XXTERN handle acc_next_loconn PROTO_PARAMS((handle port, handle loconn)); XXTERN handle acc_next_modpath PROTO_PARAMS((handle mod_p, handle path)); XXTERN handle acc_next_net PROTO_PARAMS((handle mod_handle, handle net)); XXTERN handle acc_next_output PROTO_PARAMS((handle path, handle pathout)); XXTERN handle acc_next_parameter PROTO_PARAMS((handle module_p, handle param)); XXTERN handle acc_next_port PROTO_PARAMS((handle ref_obj_p, handle port)); XXTERN handle acc_next_portout PROTO_PARAMS((handle mod_p, handle port)); XXTERN handle acc_next_primitive PROTO_PARAMS((handle mod_handle, handle prim)); XXTERN handle acc_next_scope PROTO_PARAMS((handle ref_scope_p, handle scope)); XXTERN handle acc_next_specparam PROTO_PARAMS((handle module_p, handle sparam)); XXTERN handle acc_next_tchk PROTO_PARAMS((handle mod_p, handle tchk)); XXTERN handle acc_next_terminal PROTO_PARAMS((handle gate_handle, handle term)); XXTERN handle acc_next_topmod PROTO_PARAMS((handle topmod)); XXTERN PLI_INT32 acc_object_in_typelist PROTO_PARAMS((handle object, PLI_INT32 *type_list)); XXTERN PLI_INT32 acc_object_of_type PROTO_PARAMS((handle object, PLI_INT32 type)); XXTERN PLI_INT32 acc_product_type PROTO_PARAMS((void)); XXTERN PLI_BYTE8 *acc_product_version PROTO_PARAMS((void)); XXTERN PLI_INT32 acc_release_object PROTO_PARAMS((handle obj)); XXTERN PLI_INT32 acc_replace_delays PROTO_PARAMS((handle object, ...)); XXTERN PLI_INT32 acc_replace_pulsere PROTO_PARAMS((handle object, double val1r, double val1x, ...)); XXTERN void acc_reset_buffer PROTO_PARAMS((void)); XXTERN PLI_INT32 acc_set_interactive_scope PROTO_PARAMS((handle scope, PLI_INT32 callback_flag)); XXTERN PLI_INT32 acc_set_pulsere PROTO_PARAMS((handle path_p, double val1r, double val1e)); XXTERN PLI_BYTE8 *acc_set_scope PROTO_PARAMS((handle object, ...)); XXTERN PLI_INT32 acc_set_value PROTO_PARAMS((handle obj, p_setval_value setval_p, p_setval_delay delay_p)); XXTERN void acc_vcl_add PROTO_PARAMS((handle object_p, PLI_INT32 (*consumer)(p_vc_record), PLI_BYTE8 *user_data, PLI_INT32 vcl_flags)); XXTERN void acc_vcl_delete PROTO_PARAMS((handle object_p, PLI_INT32 (*consumer)(p_vc_record), PLI_BYTE8 *user_data, PLI_INT32 vcl_flags)); XXTERN PLI_BYTE8 *acc_version PROTO_PARAMS((void)); /*---------------------------------------------------------------------------*/ /*----------------------- global variable definitions -----------------------*/ /*---------------------------------------------------------------------------*/ #if (!defined(VSIM) && !defined(VOPT)) && (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) #define acc_error_flag (*acc_error_flag_address()) #else PLI_VEXTERN PLI_DLLISPEC PLI_INT32 acc_error_flag; #endif /*---------------------------------------------------------------------------*/ /*---------------------------- macro definitions ----------------------------*/ /*---------------------------------------------------------------------------*/ #define acc_handle_calling_mod_m acc_handle_parent((handle)tf_getinstance()) #undef PLI_EXTERN #undef PLI_VEXTERN #ifdef ACC_USER_DEFINED_DLLISPEC #undef ACC_USER_DEFINED_DLLISPEC #undef PLI_DLLISPEC #endif #ifdef ACC_USER_DEFINED_DLLESPEC #undef ACC_USER_DEFINED_DLLESPEC #undef PLI_DLLESPEC #endif #ifdef PLI_PROTOTYPES #undef PLI_PROTOTYPES #undef PROTO_PARAMS #undef XXTERN #undef EETERN #endif #ifdef __cplusplus } #endif #endif /* ACC_USER_H */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/fli/acc_vhdl.h0000644000175100017510000002721215106067236020625 0ustar00runnerrunner /***************************************************************************** * * acc_vhdl.h * * List of all predefined type and fulltype constants for VHDL objects. * * Type Constant Fulltype Constant Description * =========================================================================== * * accAlias accAlias Object is a VHDL object alias. * accAlias accAliasSignal ?? * accAlias accAliasConstant ?? * accAlias accAliasGeneric ?? * accAlias accAliasVariable ?? * --------------------------------------------------------------------------- * accArchitecture accArchitecture Object is a VHDL architecture. * * accEntityVitalLevel0 Object is an architecture * whose entity is decorated with * the attribute VITAL_Level0. * * accArchVitalLevel0 Object is an architecture * that is decorated with the * attribute VITAL_Level0. * * accArchVitalLevel1 Object is an architecture * that is decorated with the * attribute VITAL_Level1. * * accForeignArch Object is an architecture * that is decorated with the * attribute FOREIGN and that * does not contain any VHDL * statements or objects other * than generics and/or ports. * * accForeignArchMixed Object is an architecture * that is decorated with the * attribute FOREIGN and that * contains at least one VHDL * statement and/or object in * addition to any generics * and/or ports. * * accForeignArchContext Object is an architecture * inserted into the context * tree by a 3rd party * that is decorated with the * attribute FOREIGN and that * does not contain any VHDL * statements or objects other * than generics and/or ports. * * accForeignArchContextMixed Object is an architecture * inserted into the context * tree by a 3rd party that * is decorated with the * attribute FOREIGN and that * contains at least one VHDL * statement and/or object in * addition to any generics * and/or ports. * --------------------------------------------------------------------------- * accBlock accBlock Object is a VHDL block. * --------------------------------------------------------------------------- * accConfiguration accConfiguration Object is a VHDL configuration. * --------------------------------------------------------------------------- * accVHDLFile accVHDLFile Object is a FILE (1993 and later) * or a variable of a file type (1987). * --------------------------------------------------------------------------- * accForeign accShadow Object is a region created * with the FLI function * mti_CreateRegion(). * --------------------------------------------------------------------------- * accForeignObject accForeignObject Object is a 3rd party object. * --------------------------------------------------------------------------- * accForeignScope accForeignScope Object is a 3rd party scope. * --------------------------------------------------------------------------- * accForLoop accForLoop Object is a VHDL for loop. * --------------------------------------------------------------------------- * accGenerate accGenerate Object is a VHDL generate * statement. * * accForGenerate FOR generate statement. * * accIfGenerate IF generate statement. * * accElsifGenerate ELSIF generate substatement. * * accElseGenerate ELSE generate substatement. * * accCaseGenerate CASE generate statement. * * accCaseOTHERSGenerate CASE generate (OTHERS choice) * substatement. * --------------------------------------------------------------------------- * accGeneric accGeneric Object is a VHDL generic on an * entity. * * accGenericConstant Same as above except that it * cannot be modified after design * elaboration, presumably because it * affects the structural makeup of * the design. * * accGenericNotEntity Object is a VHDL generic on a * package or a subprogram. * * accGenericNotEntityConstant Same as above, and it can't * be changed for the same * reasons. * * accInterfacePackage Object is an interface package on * an entity. * * accInterfacePackageNotEntity Object is an interface package * on a package or subprogram. * * accInterfaceSubpgm Object is an interface subprogram on * an entity. * * accInterfaceSubpgmNotEntity Object is an interface subprogram on * a package or subprogram. # * accInterfaceType Object is an interface type on an entity. * * accInterfaceTypeNotEntity Object is an interface type on * a package or subprogram. * * --------------------------------------------------------------------------- * accPackage accPackage Object is a VHDL package. * --------------------------------------------------------------------------- * accProcess accProcess Object is a VHDL process. * --------------------------------------------------------------------------- * accSignal accSignal Object is a VHDL signal. * --------------------------------------------------------------------------- * accSubprogram accSubprogram Object is a VHDL subprogram. * --------------------------------------------------------------------------- * accVariable accVariable Object is a VHDL variable. * --------------------------------------------------------------------------- * accVHDLConstant accVHDLConstant Object is a VHDL constant. * --------------------------------------------------------------------------- * accAccessObject accAccessObject Object was created with 'new'. * Exists only in simulator and when * viewing a WLF file. * *****************************************************************************/ /* $Id: //dvt/mti/rel/2021.4/src/vsim/acc_vhdl.h#1 $ */ #ifndef ACC_VHDL_H #define ACC_VHDL_H /* ATTENTION: Do not define values here below 1010 or above 1499. */ #define accArchitecture 1010 #define VHDL_FIRST_ACC_ID accArchitecture #define accEntityVitalLevel0 1011 #define accArchVitalLevel0 1012 #define accArchVitalLevel1 1013 #define accForeignArch 1014 #define accForeignArchMixed 1015 #define accArchArray 1016 #define accEntity 1017 #define accForeignArchContext 1018 #define accForeignArchContextMixed 1019 #define accBlock 1020 #define accCompInst 1021 #define accDirectInst 1022 #define accinlinedBlock 1023 #define accinlinedinnerBlock 1024 #define accGenerate 1030 #define accIfGenerate 1031 #define accElsifGenerate 1032 #define accElseGenerate 1033 #define accForGenerate 1034 #define accCaseGenerate 1035 #define accCaseOTHERSGenerate 1036 #define accPackage 1040 #define accPackageUninstantiated 1041 #define accPackageInstantiated 1042 #define accPackageAmsEntry 1043 #define accConfiguration 1050 #define accSubprogram 1060 #define accProcess 1070 #define accForLoop 1080 #define accForeign 1090 #define accShadow 1091 #define accShadowConv 1092 #define accSignal 1100 #define accSignalBit 1101 #define accSignalSubComposite 1102 #define accVariable 1110 #define accGeneric 1120 #define accGenericConstant 1121 #define accGenericNotEntity 1122 #define accGenericNotEntityConstant 1123 #define accInterfacePackage 1124 #define accInterfacePackageNotEntity 1125 #define accInterfaceSubprogram 1126 #define accInterfaceSubprogramNotEntity 1127 #define accInterfaceType 1128 #define accInterfaceTypeNotEntity 1129 #define accAlias 1130 #define accAliasSignal 1131 #define accAliasConstant 1132 #define accAliasGeneric 1133 #define accAliasVariable 1134 #define accAliasAMSTerminal 1135 #define accAliasLWS 1136 #define accVHDLConstant 1140 #define accVHDLFile 1150 #define accForeignObject 1160 #define accAccessObject 1170 #define VHDL_LAST_ACC_ID accAccessObject #define accForeignScope 1180 #define accAMSArchitecture 1181 #define accAMSTerminal 1182 #define accAMSQuantity 1183 #define accAMSPackage 1184 #define VS_TYPE_IS_VHDL(a) (((a) <= VHDL_LAST_ACC_ID) && (a) >= VHDL_FIRST_ACC_ID) #endif /* ACC_VHDL_H */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/fli/mti.h0000644000175100017510000010025315106067236017650 0ustar00runnerrunner/* Copyright 2022 Siemens Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #ifndef MTI_H #define MTI_H #ifndef DEFINE_UCDBT #define DEFINE_UCDBT typedef void* ucdbT; /* generic handle to a UCDB */ #endif /***************************************************************************** * DEFINES *****************************************************************************/ #ifndef PROTO #if defined(_WIN32) || defined(__STDC__) || defined(__cplusplus) #define PROTO(arg) arg #else #define PROTO(arg) () #endif #endif /* PROTO */ /***************************************************************************** * TYPE DEFINITIONS *****************************************************************************/ /* * Notice - this definition appears in mti.h, ucdb.h and mtiLongT.h */ #if !defined(MTI_LONG_INCLUDED) #define MTI_LONG_INCLUDED /* Sun defines _LP64, HP and Linux define __LP64__, AIX defines __64BIT__ */ #if defined(_LP64) || defined(__LP64__) || defined(_WIN64) # if !defined(__64BIT__) # define __64BIT__ # endif #endif /* Ensure that size-critical types are defined on all OS platforms. */ #if defined (_MSC_VER) typedef unsigned __int64 uint64_t; typedef unsigned __int32 uint32_t; typedef unsigned __int16 uint16_t; typedef unsigned __int8 uint8_t; typedef signed __int64 int64_t; typedef signed __int32 int32_t; typedef signed __int16 int16_t; typedef signed __int8 int8_t; #elif defined(__MINGW32__) # include #elif defined(__linux) # include #else # include #endif /* in L32P64 long is 32 bits and pointers are 64 bits. */ #if defined (_WIN64) typedef __int64 mtiLongT; typedef unsigned __int64 mtiUlongT; #else typedef long mtiLongT; typedef unsigned long mtiUlongT; #endif #endif /* !defined(MTI_LONG_INCLUDED) */ typedef struct mtiDriverIdTag * mtiDriverIdT; /* Handle to a signal drvr */ typedef struct mtiProcessIdTag * mtiProcessIdT; /* Handle to a process */ typedef struct mtiRegionIdTag * mtiRegionIdT; /* Handle to a region */ typedef struct mtiObjIdTag * mtiObjIdT; /* Handle to a p_obj */ typedef struct mtiSignalIdTag * mtiSignalIdT; /* Handle to a signal */ typedef struct mtiTypeIdTag * mtiTypeIdT; /* Handle to a type desc */ typedef struct mtiVariableIdTag * mtiVariableIdT;/* Handle to a variable */ typedef struct mtiValueIdTag * mtiValueIdT; /* Handle to a value desc */ typedef struct mtiCompValueIdTag * mtiCompValueIdT; /* Handle to a composite value desc */ typedef struct mtiAMSTerminalIdTag * mtiAMSTerminalIdT; /* Handle to a AMS Terminal */ typedef struct mtiAMSQuantityIdTag * mtiAMSQuantityIdT; /* Handle to a AMS Quantity */ typedef void * mtiHandleListT; typedef void * mtiHandleListItrT; typedef int mtiInt32T; typedef unsigned int mtiUInt32T; typedef mtiInt32T mtiDelayT; typedef void (*mtiEnvCBFuncPtrT) PROTO((void * param, void * context)); typedef void (*mtiSimStatusCBFuncPtrT) PROTO((void * param, int running)); typedef void (*mtiVoidFuncPtrT) PROTO((void * param)); typedef void (*mtiUCDBSaveFuncPtrT) PROTO((ucdbT ucdb, mtiRegionIdT region, void * param)); typedef void (*mtiNoParamFuncPtrT) PROTO((void)); /* Types */ typedef enum mtiTypeKindEnum_ { MTI_TYPE_SCALAR = 0, /* Integer types */ MTI_TYPE_ARRAY = 1, MTI_TYPE_RECORD = 2, MTI_TYPE_ENUM = 3, MTI_TYPE_INTEGER = 4, /* not used (use MTI_TYPE_SCALAR instead) */ MTI_TYPE_PHYSICAL = 5, MTI_TYPE_REAL = 6, MTI_TYPE_ACCESS = 7, MTI_TYPE_FILE = 8, MTI_TYPE_TIME = 9, MTI_TYPE_REG = 10, MTI_TYPE_NET = 11, MTI_TYPE_MEMELEM = 13, MTI_TYPE_C_REAL = 15, MTI_TYPE_VL_ENUM = 19, MTI_TYPE_WREAL = 46, MTI_TYPE_C_ENUM = 264 } mtiTypeKindT; /* Directions (which are really port/signal modes) */ typedef enum mtiDirectionEnum_ { MTI_INTERNAL, MTI_DIR_IN, MTI_DIR_OUT, MTI_DIR_INOUT } mtiDirectionT; /* Process triggers */ typedef enum mtiProcessTriggerEnum_ { MTI_ACTIVE, MTI_EVENT } mtiProcessTriggerT; /* Driver modes */ typedef enum mtiDriverModeEnum_ { MTI_INERTIAL, MTI_TRANSPORT } mtiDriverModeT; /* Force types */ typedef enum mtiForceTypeEnum_ { MTI_FORCE_DEFAULT, MTI_FORCE_DEPOSIT, MTI_FORCE_DRIVE, MTI_FORCE_FREEZE } mtiForceTypeT; /* SystemC Control/Observe Compatibility mode */ typedef enum mtiCntrlObsrvCompatEnum_ { MTI_SCCO_DEFAULT, /* default behaviour for SignalSpy call */ MTI_SCCO_CONTROL, /* control_foreign_signal compatibility mode */ MTI_SCCO_OBSERVE, /* observe_foreign_signal compatibility mode */ MTI_SCCO_SCV_CONNECT /* scv_connect compatibility mode */ } mtiCntrlObsrvCompatT; /* Process priority */ typedef enum mtiProcessPriorityEnum_ { MTI_PROC_NORMAL = 0, /* Normal processes run (when triggered) */ /* after all immediate processes have run and */ /* settled. They can run once per delta and */ /* can schedule events in zero delay. */ MTI_PROC_IMMEDIATE = 1, /* All immediate processes run immediately */ /* after signal activation (if triggered). If */ /* any immediate process activates any */ /* signals, then the signals are reevaluated */ /* and all immediate processes (if triggered) */ /* are run again in the same delta. This */ /* cycle continues until no more signals are */ /* activated. */ MTI_PROC_POSTPONED = 2, /* Postponed processes run once (when */ /* triggered) at the end of the time step for */ /* which they are scheduled after all */ /* immediate, normal, synchronized, and NBA */ /* processes. They cannot schedule anything */ /* in zero delay. (In Verilog, these types */ /* of processes are also known as read-only */ /* synchronization processes or $monitor() */ /* processes.) */ MTI_PROC_NBA = 3, /* Non-Blocking Assignment processes (when */ /* triggered) run after synchronized */ /* processes, but before postponed processes. */ /* They can run once per delta and can */ /* schedule events in zero delay. */ MTI_PROC_SYNCH = 4 /* Synchronized processes (when triggered) */ /* run after immediate and normal processes, */ /* but before NBA processes. They can run */ /* once per delta and can schedule events in */ /* zero delay. */ } mtiProcessPriorityT; /* Time format conversion */ typedef enum mtiTimeFlagEnum_ { MTI_TIME_BEST_UNITS = 1, /* Determine automatically the units to use */ MTI_TIME_INSERT_COMMAS = 2, /* Insert commas every three digits */ MTI_TIME_NO_DEF_UNIT = 8, /* Do not display default units */ MTI_TIME_FREQUENCY = 16 /* Display time as 1/t in hz */ } mtiTimeFlagT; /* -------------------- Data structure for time values -------------------- */ #if defined(__64BIT__) && !defined(NOINT64) /* 64-bit scalar time type */ typedef mtiLongT mtiTime64T; #define MTI_TIME64_INIT(h,l) ((mtiLongT)(h)<<32 | (unsigned int)(l)) #define MTI_TIME64_HI32(t) ((mtiInt32T)((t)>>32)) #define MTI_TIME64_LO32(t) ((mtiUInt32T)(t)) #define MTI_TIME64_ASGN(t,h,l) {(t) = (mtiLongT)(h)<<32 | (unsigned int)(l);} #elif defined(USE_INTTYPES) /* 64-bit scalar time type */ # include typedef int64 mtiTime64T; #define MTI_TIME64_INIT(h,l) ((int64)(h)<<32 | (unsigned int)(l)) #define MTI_TIME64_HI32(t) ((mtiInt32T)((t)>>32)) #define MTI_TIME64_LO32(t) ((mtiUInt32T)(t)) #define MTI_TIME64_ASGN(t,h,l) {(t) = (int64)(h)<<32 | (unsigned int)(l);} #else /* 64-bit aligned time structure */ struct mtiInt64TimeVal_ { #if defined(_WIN32) || defined(__linux) || (defined(__sun) && !defined(__sparc)) unsigned int lo; /* little-endian, sunos5x86, sunos5x866_64 */ int hi; # define MTI_TIME64_INIT(h,l) {{(l), (h)}} #elif (defined(__sun) && defined(__sparc)) int hi; /* big-endian sunos5v9 */ unsigned int lo; # define MTI_TIME64_INIT(h,l) {{(h), (l)}} #else #error "don't know how to determine endian-ness on this machine!" #endif }; typedef union mtiTime64Union_ { struct mtiInt64TimeVal_ s; # if defined(__64BIT__) mtiLongT v; # elif defined (__GNUC__) && !defined(__STRICT_ANSI__) long long v; # else double d; # endif } mtiTime64T; #define MTI_TIME64_ASGN(t,h,l) {(t).s.hi = (h); (t).s.lo = (l);} #define MTI_TIME64_HI32(t) ((t).s.hi) #define MTI_TIME64_LO32(t) ((t).s.lo) #endif /* Types to handle Real values as return values of foreign functions. */ typedef union { mtiTime64T val64; mtiInt32T val32; mtiLongT val_long; double val_real; char * val_ptr; } mtiUniversalValueT; typedef mtiUniversalValueT mtiRealT; #define MTI_GET_REAL_VALUE(r) ((r).val_real) #define MTI_ASSIGN_TO_REAL(target,source) ((target).val_real = source) /* Data structure for physical type units */ typedef struct mtiPhysicalDataStruct_ mtiPhysicalDataT; struct mtiPhysicalDataStruct_ { mtiPhysicalDataT * next; /* Ptr to next unit; NULL at end */ char * unit_name; /* Name of unit */ mtiInt32T position; /* Multiple of primary unit */ }; /* Data structure for ports and generics */ /***************************************************************************** * NOTE: For generics of type string, generic_array_value is NOT * null-terminated. See the FLI manual for information * on accessing VHDL array values. *****************************************************************************/ union mtiGenericValUnion_{ mtiInt32T generic_value; /* Integer/physical/enum generic */ /* value */ double generic_value_real; /* Real generic value */ mtiTime64T generic_value_time; /* Time generic value */ void * generic_array_value; /* Array generic value */ mtiVariableIdT generic_record_varid; /* Generic record variable */ mtiSignalIdT port; /* Signal ID of port */ #if defined(_POWER) long long _qalign_natural; /** force 8-byte alignment of union **/ #endif /* _POWER (IBM cc) */ }; typedef struct mtiInterfaceListStruct_ mtiInterfaceListT; struct mtiInterfaceListStruct_ { char * name; /* Simple name of generic/port */ mtiTypeIdT type; /* Type of generic/port */ mtiDirectionT port_dir; /* Direction of port */ /* (All generics are INTERNAL) */ union mtiGenericValUnion_ u; mtiInterfaceListT *nxt; /* Next generic/port in list */ }; /***************************************************************************** * FUNCTION PROTOTYPES *****************************************************************************/ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /*********** * Regions * ***********/ extern mtiRegionIdT mti_CreateRegion PROTO((mtiRegionIdT parent, char * name)); extern mtiRegionIdT mti_FindRegion PROTO((char * name)); extern mtiRegionIdT mti_FirstLowerRegion PROTO((mtiRegionIdT reg)); extern mtiRegionIdT mti_GetCallingRegion PROTO((void)); extern mtiRegionIdT mti_GetCurrentRegion PROTO((void)); extern mtiRegionIdT mti_GetTopRegion PROTO((void)); extern mtiRegionIdT mti_HigherRegion PROTO((mtiRegionIdT reg)); extern mtiRegionIdT mti_NextRegion PROTO((mtiRegionIdT reg)); extern char * mti_GetLibraryName PROTO((mtiRegionIdT reg)); extern char * mti_GetPrimaryName PROTO((mtiRegionIdT reg)); extern char * mti_GetRegionFullName PROTO((mtiRegionIdT reg)); extern char * mti_GetRegionName PROTO((mtiRegionIdT reg)); extern char * mti_GetRegionSourceName PROTO((mtiRegionIdT reg)); extern char * mti_GetSecondaryName PROTO((mtiRegionIdT reg)); extern int mti_GetRegionKind PROTO((mtiRegionIdT reg)); extern mtiInterfaceListT * mti_GetGenericList PROTO((mtiRegionIdT reg)); /************* * Processes * *************/ extern mtiProcessIdT mti_CreateProcess PROTO((char * name, mtiVoidFuncPtrT func, void * param)); extern mtiProcessIdT mti_CreateProcessWithPriority PROTO((char * name, mtiVoidFuncPtrT func, void * param, mtiProcessPriorityT priority)); extern mtiProcessIdT mti_FirstProcess PROTO((mtiRegionIdT reg)); extern mtiProcessIdT mti_NextProcess PROTO((void)); extern char * mti_GetProcessName PROTO((mtiProcessIdT proc)); extern mtiRegionIdT mti_GetProcessRegion PROTO((mtiProcessIdT proc)); extern void mti_Desensitize PROTO((mtiProcessIdT proc)); extern void mti_ScheduleWakeup PROTO((mtiProcessIdT proc, mtiDelayT delay)); extern void mti_ScheduleWakeup64 PROTO((mtiProcessIdT proc, mtiTime64T delay)); extern void mti_Sensitize PROTO((mtiProcessIdT proc, mtiSignalIdT sig, mtiProcessTriggerT when)); /*********** * Signals * ***********/ extern mtiSignalIdT mti_CreateSignal PROTO((char * name, mtiRegionIdT reg, mtiTypeIdT type)); extern mtiSignalIdT mti_FindPort PROTO((mtiInterfaceListT * list, char * name)); extern mtiSignalIdT mti_FindSignal PROTO((char * name)); extern mtiSignalIdT mti_FirstSignal PROTO((mtiRegionIdT reg)); extern mtiSignalIdT mti_NextSignal PROTO((void)); extern int mti_ForceSignal PROTO((mtiSignalIdT sigid, char * value_string, mtiDelayT delay, mtiForceTypeT force_type, mtiInt32T cancel_period, mtiInt32T repeat_period )); extern int mti_ReleaseSignal PROTO((mtiSignalIdT sigid)); extern void * mti_GetArraySignalValue PROTO((mtiSignalIdT sig, void * buf)); extern mtiSignalIdT * mti_GetDrivingSignals PROTO((char * name)); extern mtiSignalIdT mti_GetParentSignal PROTO((mtiSignalIdT sig)); extern mtiSignalIdT mti_GetResolvedSignalParent PROTO((mtiSignalIdT sig)); extern mtiSignalIdT mti_GetEquivSignal PROTO((mtiSignalIdT sig)); extern mtiDirectionT mti_GetSignalMode PROTO((mtiSignalIdT sig)); extern char * mti_GetSignalName PROTO((mtiSignalIdT sig)); extern char * mti_GetSignalNameIndirect PROTO((mtiSignalIdT sig, char * buf, int length)); extern mtiRegionIdT mti_GetSignalRegion PROTO((mtiSignalIdT sig)); extern mtiSignalIdT * mti_GetSignalSubelements PROTO((mtiSignalIdT sig, mtiSignalIdT * buf)); extern mtiTypeIdT mti_GetSignalType PROTO((mtiSignalIdT sig)); extern mtiInt32T mti_GetSignalValue PROTO((mtiSignalIdT sig)); extern void * mti_GetSignalValueIndirect PROTO((mtiSignalIdT sig, void * buf)); extern void mti_SetSignalValue PROTO((mtiSignalIdT sig, mtiLongT val)); extern char * mti_SignalImage PROTO((mtiSignalIdT sig)); extern int mti_SignalIsResolved PROTO((mtiSignalIdT sig)); extern void mti_SignalDump PROTO((mtiSignalIdT sig)); /*********** * Drivers * ***********/ extern mtiDriverIdT mti_CreateDriver PROTO((mtiSignalIdT sig)); extern mtiDriverIdT mti_FindDriver PROTO((mtiSignalIdT sig)); extern mtiDriverIdT * mti_GetDriverSubelements PROTO((mtiDriverIdT drv, mtiDriverIdT * buf)); extern char ** mti_GetDriverNames PROTO((mtiSignalIdT sig, mtiInt32T * length)); extern char * mti_GetDriverValues PROTO((mtiSignalIdT sig, mtiInt32T * length)); extern void mti_ScheduleDriver PROTO((mtiDriverIdT drv, mtiLongT value, mtiDelayT delay, mtiDriverModeT mode)); extern void mti_ScheduleDriver64 PROTO((mtiDriverIdT drv, mtiLongT value, mtiTime64T delay, mtiDriverModeT mode)); extern void mti_SetDriverOwner PROTO((mtiDriverIdT drv, mtiProcessIdT proc)); /************************************************** * Variables/Generics/Constants/SystemC Variables * *************************************************/ extern mtiVariableIdT mti_FindVar PROTO((char * name)); extern mtiVariableIdT mti_FirstVar PROTO((mtiProcessIdT proc)); extern mtiVariableIdT mti_FirstVarByRegion PROTO((mtiRegionIdT reg)); extern mtiVariableIdT mti_NextVar PROTO((void)); extern void * mti_GetArrayVarValue PROTO((mtiVariableIdT var, void * buf)); extern void * mti_GetVarAddr PROTO((char * name)); extern char * mti_GetVarImage PROTO((char * name)); extern char * mti_GetVarImageById PROTO((mtiVariableIdT var)); extern char * mti_GetVarName PROTO((mtiVariableIdT var)); extern mtiVariableIdT * mti_GetVarSubelements PROTO((mtiVariableIdT var, mtiVariableIdT * buf)); extern mtiTypeIdT mti_GetVarType PROTO((mtiVariableIdT var)); extern mtiInt32T mti_GetVarValue PROTO((mtiVariableIdT var)); extern void * mti_GetVarValueIndirect PROTO((mtiVariableIdT var, void * buf)); extern int mti_GetVarKind PROTO((mtiVariableIdT var)); extern void mti_SetVarValue PROTO((mtiVariableIdT var, mtiLongT val)); /********* * Types * *********/ extern mtiTypeIdT mti_CreateArrayType PROTO((mtiInt32T left, mtiInt32T right, mtiTypeIdT elem_type)); extern mtiTypeIdT mti_CreateEnumType PROTO((mtiInt32T size, mtiInt32T count, char ** literals)); extern mtiTypeIdT mti_CreateRealType PROTO((void)); extern mtiTypeIdT mti_CreateScalarType PROTO((mtiInt32T left, mtiInt32T right)); extern mtiTypeIdT mti_CreateTimeType PROTO((void)); extern mtiTypeIdT mti_GetArrayElementType PROTO((mtiTypeIdT type)); extern char ** mti_GetEnumValues PROTO((mtiTypeIdT type)); extern mtiPhysicalDataT * mti_GetPhysicalData PROTO((mtiTypeIdT type)); extern mtiTypeKindT mti_GetTypeKind PROTO((mtiTypeIdT type)); extern int mti_IsSystemcType PROTO((mtiTypeIdT type)); extern int mti_IsSystemcSignedType PROTO((mtiTypeIdT type)); extern char * mti_Image PROTO((void * value, mtiTypeIdT type)); extern mtiInt32T mti_TickDir PROTO((mtiTypeIdT type)); extern mtiInt32T mti_TickHigh PROTO((mtiTypeIdT type)); extern mtiInt32T mti_TickLeft PROTO((mtiTypeIdT type)); extern mtiInt32T mti_TickLength PROTO((mtiTypeIdT type)); extern mtiInt32T mti_TickLow PROTO((mtiTypeIdT type)); extern mtiInt32T mti_TickRight PROTO((mtiTypeIdT type)); extern mtiInt32T mti_GetNumRecordElements PROTO((mtiTypeIdT type)); /************* * Callbacks * *************/ extern void mti_AddInputReadyCB PROTO((int file_desc, mtiVoidFuncPtrT func, void * param)); extern void mti_AddOutputReadyCB PROTO((int file_desc, mtiVoidFuncPtrT func, void * param)); extern void mti_AddSocketInputReadyCB PROTO((int socket_desc, mtiVoidFuncPtrT func, void * param)); extern void mti_AddSocketOutputReadyCB PROTO((int socket_desc, mtiVoidFuncPtrT func, void * param)); extern void mti_AddEnvCB PROTO((mtiEnvCBFuncPtrT func,void *param)); extern void mti_AddLoadDoneCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_AddQuitCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_AddRestartCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_AddRestoreCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_AddRestoreDoneCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_AddSaveCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_AddSimStatusCB PROTO((mtiSimStatusCBFuncPtrT func, void *param)); extern void mti_AddUCDBSaveCB PROTO((mtiRegionIdT region, mtiUCDBSaveFuncPtrT func, void*param)); extern void mti_RemoveEnvCB PROTO((mtiEnvCBFuncPtrT func,void *param)); extern void mti_RemoveLoadDoneCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_RemoveQuitCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_RemoveRestartCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_RemoveRestoreCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_RemoveRestoreDoneCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_RemoveSaveCB PROTO((mtiVoidFuncPtrT func, void *param)); extern void mti_RemoveSimStatusCB PROTO((mtiSimStatusCBFuncPtrT func, void *param)); extern void mti_AddDPISaveRestoreCB PROTO((mtiVoidFuncPtrT saveFuncPtr, char* restoreFuncName)); /********************* * Memory Management * *********************/ extern void * mti_Malloc PROTO((mtiUlongT size)); extern void * mti_Realloc PROTO((void * p, mtiUlongT size)); extern void mti_Free PROTO((void * p)); extern void mti_VsimFree PROTO((void * ptr)); /****************** * Save & Restore * ******************/ extern char * mti_GetCheckpointFilename PROTO((void)); extern char * mti_GetCheckpointDirname PROTO((void)); extern char * mti_GetRestoreDirname PROTO((void)); extern int mti_IsRestore PROTO((void)); extern int mti_IsColdRestore PROTO((void)); extern void mti_SaveBlock PROTO((char * p, mtiUlongT size)); extern void mti_SaveChar PROTO((char data)); extern void mti_SaveLong PROTO((mtiLongT data)); extern void mti_SaveShort PROTO((short data)); extern void mti_SaveString PROTO((char * data)); extern void mti_RestoreBlock PROTO((char * p)); extern char mti_RestoreChar PROTO((void)); extern mtiLongT mti_RestoreLong PROTO((void)); extern short mti_RestoreShort PROTO((void)); extern char * mti_RestoreString PROTO((void)); extern void mti_RestoreProcess PROTO((mtiProcessIdT proc, char * name, mtiVoidFuncPtrT func, void * param)); /***************** * Time & Events * *****************/ extern mtiUInt32T mti_Delta PROTO((void)); extern mtiInt32T mti_Now PROTO((void)); extern mtiTime64T * mti_NowIndirect PROTO((mtiTime64T *timep)); extern mtiInt32T mti_NowUpper PROTO((void)); extern char * mti_NowFormatted PROTO((mtiTimeFlagT flags)); extern char * mti_TimeToString PROTO((mtiTime64T *timep, mtiTimeFlagT flags)); extern int mti_GetNextEventTime PROTO((mtiTime64T * timep)); extern int mti_GetNextNextEventTime PROTO((mtiTime64T * timep)); extern int mti_GetResolutionLimit PROTO((void)); extern void mti_GetRunStopTime PROTO((mtiTime64T * timep)); /**************************** * Communication & Commands * ****************************/ extern void mti_AddCommand PROTO((char * cmd_name, mtiVoidFuncPtrT func)); #ifdef _TCL extern void mti_AddTclCommand PROTO((const char * cmd_name, Tcl_CmdProc * func, void * param, mtiVoidFuncPtrT funcDeleteCB)); #endif /* _TCL */ extern void mti_Command PROTO((const char * cmd)); extern int mti_Cmd PROTO((const char * cmd)); extern void * mti_Interp PROTO((void)); extern int mti_AskStdin PROTO((char * buf, char * prompt)); extern void mti_PrintMsg PROTO((int flags, const char * msg)); extern void mti_PrintMessage PROTO((const char * msg)); extern void mti_PrintFormatted PROTO((const char * format, ...)); extern void mti_Break PROTO((void)); extern void mti_FatalError PROTO((void)); extern void mti_Exit PROTO((int exit_status)); extern void mti_Quit PROTO((void)); extern void mti_QuitWithErrorCode PROTO((const char* file_name, int line_number, int error_code)); /***************** * Miscellaneous * *****************/ extern char * mti_GetProductVersion PROTO((void)); extern char * mti_GetWlfFilename PROTO((void)); extern char * mti_FindProjectEntry PROTO((char * section, char * name, int expand)); extern void mti_WriteProjectEntry PROTO((char * key, char * val)); extern int mti_IsFirstInit PROTO((void)); extern void mti_KeepLoaded PROTO((void)); extern int mti_AddAttrToVsimTestrecord PROTO((const char * key, void * value)); extern int mti_GetAttrFromVsimTestrecord PROTO((const char * key, void * value)); extern int mti_GetSimulationStatus PROTO((void)); extern int mti_RemoveAttrFromVsimTestrecord PROTO((const char * key)); extern int mti_CallStack PROTO((void)); extern int mti_IsVoptMode PROTO((void)); extern int mti_IsGBEMode PROTO((void)); extern int mti_NoScHdlParam PROTO((void)); /***************** * VHDL - AMS * *****************/ extern void* ams_debug_FirstAMSObj PROTO((mtiRegionIdT reg, uint32_t acc_type)); extern void* ams_debug_NextAMSObj PROTO((uint32_t acc_type)); extern mtiTypeIdT ams_debug_GetTerminalType PROTO((void* term_obj)); extern mtiTypeIdT ams_debug_GetQuantityType PROTO((void* quant_obj)); extern void* ams_debug_GetPlusTerminal PROTO((void* quant_obj)); extern void* ams_debug_GetMinusTerminal PROTO((void* quant_obj)); extern void* ams_debug_GetImplicitQuantityPrefix PROTO((void* quant_obj)); extern double ams_debug_GetQuantityValue PROTO((void* quant_obj)); extern void ams_debug_SetQuantityValue PROTO((void* quant_obj, double value)); extern int ams_debug_getQuantityTDKind PROTO((void* quant_obj)); extern int ams_debug_getQuantityPortMode PROTO((void* quant_obj)); extern int ams_debug_getArrayQuantityNumChildren PROTO((void* quant_obj)); extern int ams_debug_validateQuantityStructure PROTO((void* quant_obj, int validateSetGet, char* printStr)); extern void* ams_debug_getQuantityPortHiconn PROTO((void* quant_obj)); extern double ams_debug_GetTerminalContribution PROTO((void* term_obj)); extern void ams_debug_SetTerminalContribution PROTO((void* term_obj, double value)); extern double ams_debug_GetTerminalReference PROTO((void* term_obj)); extern void ams_debug_SetTerminalReference PROTO((void* term_obj, double value)); extern int ams_debug_getTerminalTDKind PROTO((void* term_obj)); extern int ams_debug_getTerminalPortMode PROTO((void* term_obj)); extern int ams_debug_getArrayTerminalNumChildren PROTO((void* term_obj)); extern int ams_debug_validateTerminalStructure PROTO((void* term_obj, int validateSetGet, char* printStr)); extern void* ams_debug_getTerminalPortHiconn PROTO((void* term_obj)); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* MTI_H */ /* ***************************** End of Header ***************************** */ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3437026 cocotb-2.0.1/src/cocotb/_vendor/tcl/0000755000175100017510000000000015106070715016711 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/tcl/license.terms0000644000175100017510000000431715106067236021420 0ustar00runnerrunnerThis software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState Corporation and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/tcl/tcl.h0000644000175100017510000027102715106067236017661 0ustar00runnerrunner/* * tcl.h -- * * This header file describes the externally-visible facilities of the * Tcl interpreter. * * Copyright (c) 1987-1994 The Regents of the University of California. * Copyright (c) 1993-1996 Lucent Technologies. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * Copyright (c) 1998-2000 by Scriptics Corporation. * Copyright (c) 2002 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCL #define _TCL /* * For C++ compilers, use extern "C" */ #ifdef __cplusplus extern "C" { #endif /* * The following defines are used to indicate the various release levels. */ #define TCL_ALPHA_RELEASE 0 #define TCL_BETA_RELEASE 1 #define TCL_FINAL_RELEASE 2 /* * When version numbers change here, must also go into the following files and * update the version numbers: * * library/init.tcl (1 LOC patch) * unix/configure.in (2 LOC Major, 2 LOC minor, 1 LOC patch) * win/configure.in (as above) * win/tcl.m4 (not patchlevel) * win/makefile.bc (not patchlevel) 2 LOC * README (sections 0 and 2, with and without separator) * macosx/Tcl.pbproj/project.pbxproj (not patchlevel) 1 LOC * macosx/Tcl.pbproj/default.pbxuser (not patchlevel) 1 LOC * macosx/Tcl.xcode/project.pbxproj (not patchlevel) 2 LOC * macosx/Tcl.xcode/default.pbxuser (not patchlevel) 1 LOC * macosx/Tcl-Common.xcconfig (not patchlevel) 1 LOC * win/README (not patchlevel) (sections 0 and 2) * unix/tcl.spec (1 LOC patch) * tools/tcl.hpj.in (not patchlevel, for windows installer) */ #define TCL_MAJOR_VERSION 8 #define TCL_MINOR_VERSION 6 #define TCL_RELEASE_LEVEL TCL_FINAL_RELEASE #define TCL_RELEASE_SERIAL 5 #define TCL_VERSION "8.6" #define TCL_PATCH_LEVEL "8.6.5" /* *---------------------------------------------------------------------------- * The following definitions set up the proper options for Windows compilers. * We use this method because there is no autoconf equivalent. */ #ifdef _WIN32 # ifndef __WIN32__ # define __WIN32__ # endif # ifndef WIN32 # define WIN32 # endif #endif /* * Utility macros: STRINGIFY takes an argument and wraps it in "" (double * quotation marks), JOIN joins two arguments. */ #ifndef STRINGIFY # define STRINGIFY(x) STRINGIFY1(x) # define STRINGIFY1(x) #x #endif #ifndef JOIN # define JOIN(a,b) JOIN1(a,b) # define JOIN1(a,b) a##b #endif /* * A special definition used to allow this header file to be included from * windows resource files so that they can obtain version information. * RC_INVOKED is defined by default by the windows RC tool. * * Resource compilers don't like all the C stuff, like typedefs and function * declarations, that occur below, so block them out. */ #ifndef RC_INVOKED /* * Special macro to define mutexes, that doesn't do anything if we are not * using threads. */ #ifdef TCL_THREADS #define TCL_DECLARE_MUTEX(name) static Tcl_Mutex name; #else #define TCL_DECLARE_MUTEX(name) #endif /* * Tcl's public routine Tcl_FSSeek() uses the values SEEK_SET, SEEK_CUR, and * SEEK_END, all #define'd by stdio.h . * * Also, many extensions need stdio.h, and they've grown accustomed to tcl.h * providing it for them rather than #include-ing it themselves as they * should, so also for their sake, we keep the #include to be consistent with * prior Tcl releases. */ #include /* *---------------------------------------------------------------------------- * Support for functions with a variable number of arguments. * * The following TCL_VARARGS* macros are to support old extensions * written for older versions of Tcl where the macros permitted * support for the varargs.h system as well as stdarg.h . * * New code should just directly be written to use stdarg.h conventions. */ #include #ifndef TCL_NO_DEPRECATED # define TCL_VARARGS(type, name) (type name, ...) # define TCL_VARARGS_DEF(type, name) (type name, ...) # define TCL_VARARGS_START(type, name, list) (va_start(list, name), name) #endif #if defined(__GNUC__) && (__GNUC__ > 2) # define TCL_FORMAT_PRINTF(a,b) __attribute__ ((__format__ (__printf__, a, b))) # define TCL_NORETURN __attribute__ ((noreturn)) # if defined(BUILD_tcl) || defined(BUILD_tk) # define TCL_NORETURN1 __attribute__ ((noreturn)) # else # define TCL_NORETURN1 /* nothing */ # endif #else # define TCL_FORMAT_PRINTF(a,b) # if defined(_MSC_VER) && (_MSC_VER >= 1310) # define TCL_NORETURN _declspec(noreturn) # else # define TCL_NORETURN /* nothing */ # endif # define TCL_NORETURN1 /* nothing */ #endif /* * Allow a part of Tcl's API to be explicitly marked as deprecated. * * Used to make TIP 330/336 generate moans even if people use the * compatibility macros. Change your code, guys! We won't support you forever. */ #if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1))) # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) # define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__ (msg))) # else # define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__)) # endif #else # define TCL_DEPRECATED_API(msg) /* nothing portable */ #endif /* *---------------------------------------------------------------------------- * Macros used to declare a function to be exported by a DLL. Used by Windows, * maps to no-op declarations on non-Windows systems. The default build on * windows is for a DLL, which causes the DLLIMPORT and DLLEXPORT macros to be * nonempty. To build a static library, the macro STATIC_BUILD should be * defined. * * Note: when building static but linking dynamically to MSVCRT we must still * correctly decorate the C library imported function. Use CRTIMPORT * for this purpose. _DLL is defined by the compiler when linking to * MSVCRT. */ #if (defined(_WIN32) && (defined(_MSC_VER) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x0550)) || defined(__LCC__) || defined(__WATCOMC__) || (defined(__GNUC__) && defined(__declspec)))) # define HAVE_DECLSPEC 1 # ifdef STATIC_BUILD # define DLLIMPORT # define DLLEXPORT # ifdef _DLL # define CRTIMPORT __declspec(dllimport) # else # define CRTIMPORT # endif # else # define DLLIMPORT __declspec(dllimport) # define DLLEXPORT __declspec(dllexport) # define CRTIMPORT __declspec(dllimport) # endif #else # define DLLIMPORT # if defined(__GNUC__) && __GNUC__ > 3 # define DLLEXPORT __attribute__ ((visibility("default"))) # else # define DLLEXPORT # endif # define CRTIMPORT #endif /* * These macros are used to control whether functions are being declared for * import or export. If a function is being declared while it is being built * to be included in a shared library, then it should have the DLLEXPORT * storage class. If is being declared for use by a module that is going to * link against the shared library, then it should have the DLLIMPORT storage * class. If the symbol is beind declared for a static build or for use from a * stub library, then the storage class should be empty. * * The convention is that a macro called BUILD_xxxx, where xxxx is the name of * a library we are building, is set on the compile line for sources that are * to be placed in the library. When this macro is set, the storage class will * be set to DLLEXPORT. At the end of the header file, the storage class will * be reset to DLLIMPORT. */ #undef TCL_STORAGE_CLASS #ifdef BUILD_tcl # define TCL_STORAGE_CLASS DLLEXPORT #else # ifdef USE_TCL_STUBS # define TCL_STORAGE_CLASS # else # define TCL_STORAGE_CLASS DLLIMPORT # endif #endif /* * The following _ANSI_ARGS_ macro is to support old extensions * written for older versions of Tcl where it permitted support * for compilers written in the pre-prototype era of C. * * New code should use prototypes. */ #ifndef TCL_NO_DEPRECATED # undef _ANSI_ARGS_ # define _ANSI_ARGS_(x) x #endif /* * Definitions that allow this header file to be used either with or without * ANSI C features. */ #ifndef INLINE # define INLINE #endif #ifdef NO_CONST # ifndef const # define const # endif #endif #ifndef CONST # define CONST const #endif #ifdef USE_NON_CONST # ifdef USE_COMPAT_CONST # error define at most one of USE_NON_CONST and USE_COMPAT_CONST # endif # define CONST84 # define CONST84_RETURN #else # ifdef USE_COMPAT_CONST # define CONST84 # define CONST84_RETURN const # else # define CONST84 const # define CONST84_RETURN const # endif #endif #ifndef CONST86 # define CONST86 CONST84 #endif /* * Make sure EXTERN isn't defined elsewhere. */ #ifdef EXTERN # undef EXTERN #endif /* EXTERN */ #ifdef __cplusplus # define EXTERN extern "C" TCL_STORAGE_CLASS #else # define EXTERN extern TCL_STORAGE_CLASS #endif /* *---------------------------------------------------------------------------- * The following code is copied from winnt.h. If we don't replicate it here, * then can't be included after tcl.h, since tcl.h also defines * VOID. This block is skipped under Cygwin and Mingw. */ #if defined(_WIN32) && !defined(HAVE_WINNT_IGNORE_VOID) #ifndef VOID #define VOID void typedef char CHAR; typedef short SHORT; typedef long LONG; #endif #endif /* _WIN32 && !HAVE_WINNT_IGNORE_VOID */ /* * Macro to use instead of "void" for arguments that must have type "void *" * in ANSI C; maps them to type "char *" in non-ANSI systems. */ #ifndef __VXWORKS__ # ifndef NO_VOID # define VOID void # else # define VOID char # endif #endif /* * Miscellaneous declarations. */ #ifndef _CLIENTDATA # ifndef NO_VOID typedef void *ClientData; # else typedef int *ClientData; # endif # define _CLIENTDATA #endif /* * Darwin specific configure overrides (to support fat compiles, where * configure runs only once for multiple architectures): */ #ifdef __APPLE__ # ifdef __LP64__ # undef TCL_WIDE_INT_TYPE # define TCL_WIDE_INT_IS_LONG 1 # define TCL_CFG_DO64BIT 1 # else /* !__LP64__ */ # define TCL_WIDE_INT_TYPE long long # undef TCL_WIDE_INT_IS_LONG # undef TCL_CFG_DO64BIT # endif /* __LP64__ */ # undef HAVE_STRUCT_STAT64 #endif /* __APPLE__ */ /* * Define Tcl_WideInt to be a type that is (at least) 64-bits wide, and define * Tcl_WideUInt to be the unsigned variant of that type (assuming that where * we have one, we can have the other.) * * Also defines the following macros: * TCL_WIDE_INT_IS_LONG - if wide ints are really longs (i.e. we're on a real * 64-bit system.) * Tcl_WideAsLong - forgetful converter from wideInt to long. * Tcl_LongAsWide - sign-extending converter from long to wideInt. * Tcl_WideAsDouble - converter from wideInt to double. * Tcl_DoubleAsWide - converter from double to wideInt. * * The following invariant should hold for any long value 'longVal': * longVal == Tcl_WideAsLong(Tcl_LongAsWide(longVal)) * * Note on converting between Tcl_WideInt and strings. This implementation (in * tclObj.c) depends on the function * sprintf(...,"%" TCL_LL_MODIFIER "d",...). */ #if !defined(TCL_WIDE_INT_TYPE)&&!defined(TCL_WIDE_INT_IS_LONG) # if defined(_WIN32) # define TCL_WIDE_INT_TYPE __int64 # ifdef __BORLANDC__ # define TCL_LL_MODIFIER "L" # else /* __BORLANDC__ */ # define TCL_LL_MODIFIER "I64" # endif /* __BORLANDC__ */ # elif defined(__GNUC__) # define TCL_WIDE_INT_TYPE long long # define TCL_LL_MODIFIER "ll" # else /* ! _WIN32 && ! __GNUC__ */ /* * Don't know what platform it is and configure hasn't discovered what is * going on for us. Try to guess... */ # include # if (INT_MAX < LONG_MAX) # define TCL_WIDE_INT_IS_LONG 1 # else # define TCL_WIDE_INT_TYPE long long # endif # endif /* _WIN32 */ #endif /* !TCL_WIDE_INT_TYPE & !TCL_WIDE_INT_IS_LONG */ #ifdef TCL_WIDE_INT_IS_LONG # undef TCL_WIDE_INT_TYPE # define TCL_WIDE_INT_TYPE long #endif /* TCL_WIDE_INT_IS_LONG */ typedef TCL_WIDE_INT_TYPE Tcl_WideInt; typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt; #ifdef TCL_WIDE_INT_IS_LONG # define Tcl_WideAsLong(val) ((long)(val)) # define Tcl_LongAsWide(val) ((long)(val)) # define Tcl_WideAsDouble(val) ((double)((long)(val))) # define Tcl_DoubleAsWide(val) ((long)((double)(val))) # ifndef TCL_LL_MODIFIER # define TCL_LL_MODIFIER "l" # endif /* !TCL_LL_MODIFIER */ #else /* TCL_WIDE_INT_IS_LONG */ /* * The next short section of defines are only done when not running on Windows * or some other strange platform. */ # ifndef TCL_LL_MODIFIER # define TCL_LL_MODIFIER "ll" # endif /* !TCL_LL_MODIFIER */ # define Tcl_WideAsLong(val) ((long)((Tcl_WideInt)(val))) # define Tcl_LongAsWide(val) ((Tcl_WideInt)((long)(val))) # define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val))) # define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val))) #endif /* TCL_WIDE_INT_IS_LONG */ #if defined(_WIN32) # ifdef __BORLANDC__ typedef struct stati64 Tcl_StatBuf; # elif defined(_WIN64) typedef struct __stat64 Tcl_StatBuf; # elif (defined(_MSC_VER) && (_MSC_VER < 1400)) || defined(_USE_32BIT_TIME_T) typedef struct _stati64 Tcl_StatBuf; # else typedef struct _stat32i64 Tcl_StatBuf; # endif /* _MSC_VER < 1400 */ #elif defined(__CYGWIN__) typedef struct { dev_t st_dev; unsigned short st_ino; unsigned short st_mode; short st_nlink; short st_uid; short st_gid; /* Here is a 2-byte gap */ dev_t st_rdev; /* Here is a 4-byte gap */ long long st_size; struct {long tv_sec;} st_atim; struct {long tv_sec;} st_mtim; struct {long tv_sec;} st_ctim; /* Here is a 4-byte gap */ } Tcl_StatBuf; #elif defined(HAVE_STRUCT_STAT64) && !defined(__APPLE__) typedef struct stat64 Tcl_StatBuf; #else typedef struct stat Tcl_StatBuf; #endif /* *---------------------------------------------------------------------------- * Data structures defined opaquely in this module. The definitions below just * provide dummy types. A few fields are made visible in Tcl_Interp * structures, namely those used for returning a string result from commands. * Direct access to the result field is discouraged in Tcl 8.0. The * interpreter result is either an object or a string, and the two values are * kept consistent unless some C code sets interp->result directly. * Programmers should use either the function Tcl_GetObjResult() or * Tcl_GetStringResult() to read the interpreter's result. See the SetResult * man page for details. * * Note: any change to the Tcl_Interp definition below must be mirrored in the * "real" definition in tclInt.h. * * Note: Tcl_ObjCmdProc functions do not directly set result and freeProc. * Instead, they set a Tcl_Obj member in the "real" structure that can be * accessed with Tcl_GetObjResult() and Tcl_SetObjResult(). */ typedef struct Tcl_Interp #ifndef TCL_NO_DEPRECATED { /* TIP #330: Strongly discourage extensions from using the string * result. */ #ifdef USE_INTERP_RESULT char *result TCL_DEPRECATED_API("use Tcl_GetStringResult/Tcl_SetResult"); /* If the last command returned a string * result, this points to it. */ void (*freeProc) (char *blockPtr) TCL_DEPRECATED_API("use Tcl_GetStringResult/Tcl_SetResult"); /* Zero means the string result is statically * allocated. TCL_DYNAMIC means it was * allocated with ckalloc and should be freed * with ckfree. Other values give the address * of function to invoke to free the result. * Tcl_Eval must free it before executing next * command. */ #else char *resultDontUse; /* Don't use in extensions! */ void (*freeProcDontUse) (char *); /* Don't use in extensions! */ #endif #ifdef USE_INTERP_ERRORLINE int errorLine TCL_DEPRECATED_API("use Tcl_GetErrorLine/Tcl_SetErrorLine"); /* When TCL_ERROR is returned, this gives the * line number within the command where the * error occurred (1 if first line). */ #else int errorLineDontUse; /* Don't use in extensions! */ #endif } #endif /* TCL_NO_DEPRECATED */ Tcl_Interp; typedef struct Tcl_AsyncHandler_ *Tcl_AsyncHandler; typedef struct Tcl_Channel_ *Tcl_Channel; typedef struct Tcl_ChannelTypeVersion_ *Tcl_ChannelTypeVersion; typedef struct Tcl_Command_ *Tcl_Command; typedef struct Tcl_Condition_ *Tcl_Condition; typedef struct Tcl_Dict_ *Tcl_Dict; typedef struct Tcl_EncodingState_ *Tcl_EncodingState; typedef struct Tcl_Encoding_ *Tcl_Encoding; typedef struct Tcl_Event Tcl_Event; typedef struct Tcl_InterpState_ *Tcl_InterpState; typedef struct Tcl_LoadHandle_ *Tcl_LoadHandle; typedef struct Tcl_Mutex_ *Tcl_Mutex; typedef struct Tcl_Pid_ *Tcl_Pid; typedef struct Tcl_RegExp_ *Tcl_RegExp; typedef struct Tcl_ThreadDataKey_ *Tcl_ThreadDataKey; typedef struct Tcl_ThreadId_ *Tcl_ThreadId; typedef struct Tcl_TimerToken_ *Tcl_TimerToken; typedef struct Tcl_Trace_ *Tcl_Trace; typedef struct Tcl_Var_ *Tcl_Var; typedef struct Tcl_ZLibStream_ *Tcl_ZlibStream; /* *---------------------------------------------------------------------------- * Definition of the interface to functions implementing threads. A function * following this definition is given to each call of 'Tcl_CreateThread' and * will be called as the main fuction of the new thread created by that call. */ #if defined _WIN32 typedef unsigned (__stdcall Tcl_ThreadCreateProc) (ClientData clientData); #else typedef void (Tcl_ThreadCreateProc) (ClientData clientData); #endif /* * Threading function return types used for abstracting away platform * differences when writing a Tcl_ThreadCreateProc. See the NewThread function * in generic/tclThreadTest.c for it's usage. */ #if defined _WIN32 # define Tcl_ThreadCreateType unsigned __stdcall # define TCL_THREAD_CREATE_RETURN return 0 #else # define Tcl_ThreadCreateType void # define TCL_THREAD_CREATE_RETURN #endif /* * Definition of values for default stacksize and the possible flags to be * given to Tcl_CreateThread. */ #define TCL_THREAD_STACK_DEFAULT (0) /* Use default size for stack. */ #define TCL_THREAD_NOFLAGS (0000) /* Standard flags, default * behaviour. */ #define TCL_THREAD_JOINABLE (0001) /* Mark the thread as joinable. */ /* * Flag values passed to Tcl_StringCaseMatch. */ #define TCL_MATCH_NOCASE (1<<0) /* * Flag values passed to Tcl_GetRegExpFromObj. */ #define TCL_REG_BASIC 000000 /* BREs (convenience). */ #define TCL_REG_EXTENDED 000001 /* EREs. */ #define TCL_REG_ADVF 000002 /* Advanced features in EREs. */ #define TCL_REG_ADVANCED 000003 /* AREs (which are also EREs). */ #define TCL_REG_QUOTE 000004 /* No special characters, none. */ #define TCL_REG_NOCASE 000010 /* Ignore case. */ #define TCL_REG_NOSUB 000020 /* Don't care about subexpressions. */ #define TCL_REG_EXPANDED 000040 /* Expanded format, white space & * comments. */ #define TCL_REG_NLSTOP 000100 /* \n doesn't match . or [^ ] */ #define TCL_REG_NLANCH 000200 /* ^ matches after \n, $ before. */ #define TCL_REG_NEWLINE 000300 /* Newlines are line terminators. */ #define TCL_REG_CANMATCH 001000 /* Report details on partial/limited * matches. */ /* * Flags values passed to Tcl_RegExpExecObj. */ #define TCL_REG_NOTBOL 0001 /* Beginning of string does not match ^. */ #define TCL_REG_NOTEOL 0002 /* End of string does not match $. */ /* * Structures filled in by Tcl_RegExpInfo. Note that all offset values are * relative to the start of the match string, not the beginning of the entire * string. */ typedef struct Tcl_RegExpIndices { long start; /* Character offset of first character in * match. */ long end; /* Character offset of first character after * the match. */ } Tcl_RegExpIndices; typedef struct Tcl_RegExpInfo { int nsubs; /* Number of subexpressions in the compiled * expression. */ Tcl_RegExpIndices *matches; /* Array of nsubs match offset pairs. */ long extendStart; /* The offset at which a subsequent match * might begin. */ long reserved; /* Reserved for later use. */ } Tcl_RegExpInfo; /* * Picky compilers complain if this typdef doesn't appear before the struct's * reference in tclDecls.h. */ typedef Tcl_StatBuf *Tcl_Stat_; typedef struct stat *Tcl_OldStat_; /* *---------------------------------------------------------------------------- * When a TCL command returns, the interpreter contains a result from the * command. Programmers are strongly encouraged to use one of the functions * Tcl_GetObjResult() or Tcl_GetStringResult() to read the interpreter's * result. See the SetResult man page for details. Besides this result, the * command function returns an integer code, which is one of the following: * * TCL_OK Command completed normally; the interpreter's result * contains the command's result. * TCL_ERROR The command couldn't be completed successfully; the * interpreter's result describes what went wrong. * TCL_RETURN The command requests that the current function return; * the interpreter's result contains the function's * return value. * TCL_BREAK The command requests that the innermost loop be * exited; the interpreter's result is meaningless. * TCL_CONTINUE Go on to the next iteration of the current loop; the * interpreter's result is meaningless. */ #define TCL_OK 0 #define TCL_ERROR 1 #define TCL_RETURN 2 #define TCL_BREAK 3 #define TCL_CONTINUE 4 #define TCL_RESULT_SIZE 200 /* *---------------------------------------------------------------------------- * Flags to control what substitutions are performed by Tcl_SubstObj(): */ #define TCL_SUBST_COMMANDS 001 #define TCL_SUBST_VARIABLES 002 #define TCL_SUBST_BACKSLASHES 004 #define TCL_SUBST_ALL 007 /* * Argument descriptors for math function callbacks in expressions: */ typedef enum { TCL_INT, TCL_DOUBLE, TCL_EITHER, TCL_WIDE_INT } Tcl_ValueType; typedef struct Tcl_Value { Tcl_ValueType type; /* Indicates intValue or doubleValue is valid, * or both. */ long intValue; /* Integer value. */ double doubleValue; /* Double-precision floating value. */ Tcl_WideInt wideValue; /* Wide (min. 64-bit) integer value. */ } Tcl_Value; /* * Forward declaration of Tcl_Obj to prevent an error when the forward * reference to Tcl_Obj is encountered in the function types declared below. */ struct Tcl_Obj; /* *---------------------------------------------------------------------------- * Function types defined by Tcl: */ typedef int (Tcl_AppInitProc) (Tcl_Interp *interp); typedef int (Tcl_AsyncProc) (ClientData clientData, Tcl_Interp *interp, int code); typedef void (Tcl_ChannelProc) (ClientData clientData, int mask); typedef void (Tcl_CloseProc) (ClientData data); typedef void (Tcl_CmdDeleteProc) (ClientData clientData); typedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[]); typedef void (Tcl_CmdTraceProc) (ClientData clientData, Tcl_Interp *interp, int level, char *command, Tcl_CmdProc *proc, ClientData cmdClientData, int argc, CONST84 char *argv[]); typedef int (Tcl_CmdObjTraceProc) (ClientData clientData, Tcl_Interp *interp, int level, const char *command, Tcl_Command commandInfo, int objc, struct Tcl_Obj *const *objv); typedef void (Tcl_CmdObjTraceDeleteProc) (ClientData clientData); typedef void (Tcl_DupInternalRepProc) (struct Tcl_Obj *srcPtr, struct Tcl_Obj *dupPtr); typedef int (Tcl_EncodingConvertProc) (ClientData clientData, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); typedef void (Tcl_EncodingFreeProc) (ClientData clientData); typedef int (Tcl_EventProc) (Tcl_Event *evPtr, int flags); typedef void (Tcl_EventCheckProc) (ClientData clientData, int flags); typedef int (Tcl_EventDeleteProc) (Tcl_Event *evPtr, ClientData clientData); typedef void (Tcl_EventSetupProc) (ClientData clientData, int flags); typedef void (Tcl_ExitProc) (ClientData clientData); typedef void (Tcl_FileProc) (ClientData clientData, int mask); typedef void (Tcl_FileFreeProc) (ClientData clientData); typedef void (Tcl_FreeInternalRepProc) (struct Tcl_Obj *objPtr); typedef void (Tcl_FreeProc) (char *blockPtr); typedef void (Tcl_IdleProc) (ClientData clientData); typedef void (Tcl_InterpDeleteProc) (ClientData clientData, Tcl_Interp *interp); typedef int (Tcl_MathProc) (ClientData clientData, Tcl_Interp *interp, Tcl_Value *args, Tcl_Value *resultPtr); typedef void (Tcl_NamespaceDeleteProc) (ClientData clientData); typedef int (Tcl_ObjCmdProc) (ClientData clientData, Tcl_Interp *interp, int objc, struct Tcl_Obj *const *objv); typedef int (Tcl_PackageInitProc) (Tcl_Interp *interp); typedef int (Tcl_PackageUnloadProc) (Tcl_Interp *interp, int flags); typedef void (Tcl_PanicProc) (const char *format, ...); typedef void (Tcl_TcpAcceptProc) (ClientData callbackData, Tcl_Channel chan, char *address, int port); typedef void (Tcl_TimerProc) (ClientData clientData); typedef int (Tcl_SetFromAnyProc) (Tcl_Interp *interp, struct Tcl_Obj *objPtr); typedef void (Tcl_UpdateStringProc) (struct Tcl_Obj *objPtr); typedef char * (Tcl_VarTraceProc) (ClientData clientData, Tcl_Interp *interp, CONST84 char *part1, CONST84 char *part2, int flags); typedef void (Tcl_CommandTraceProc) (ClientData clientData, Tcl_Interp *interp, const char *oldName, const char *newName, int flags); typedef void (Tcl_CreateFileHandlerProc) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); typedef void (Tcl_DeleteFileHandlerProc) (int fd); typedef void (Tcl_AlertNotifierProc) (ClientData clientData); typedef void (Tcl_ServiceModeHookProc) (int mode); typedef ClientData (Tcl_InitNotifierProc) (void); typedef void (Tcl_FinalizeNotifierProc) (ClientData clientData); typedef void (Tcl_MainLoopProc) (void); /* *---------------------------------------------------------------------------- * The following structure represents a type of object, which is a particular * internal representation for an object plus a set of functions that provide * standard operations on objects of that type. */ typedef struct Tcl_ObjType { const char *name; /* Name of the type, e.g. "int". */ Tcl_FreeInternalRepProc *freeIntRepProc; /* Called to free any storage for the type's * internal rep. NULL if the internal rep does * not need freeing. */ Tcl_DupInternalRepProc *dupIntRepProc; /* Called to create a new object as a copy of * an existing object. */ Tcl_UpdateStringProc *updateStringProc; /* Called to update the string rep from the * type's internal representation. */ Tcl_SetFromAnyProc *setFromAnyProc; /* Called to convert the object's internal rep * to this type. Frees the internal rep of the * old type. Returns TCL_ERROR on failure. */ } Tcl_ObjType; /* * One of the following structures exists for each object in the Tcl system. * An object stores a value as either a string, some internal representation, * or both. */ typedef struct Tcl_Obj { int refCount; /* When 0 the object will be freed. */ char *bytes; /* This points to the first byte of the * object's string representation. The array * must be followed by a null byte (i.e., at * offset length) but may also contain * embedded null characters. The array's * storage is allocated by ckalloc. NULL means * the string rep is invalid and must be * regenerated from the internal rep. Clients * should use Tcl_GetStringFromObj or * Tcl_GetString to get a pointer to the byte * array as a readonly value. */ int length; /* The number of bytes at *bytes, not * including the terminating null. */ const Tcl_ObjType *typePtr; /* Denotes the object's type. Always * corresponds to the type of the object's * internal rep. NULL indicates the object has * no internal rep (has no type). */ union { /* The internal representation: */ long longValue; /* - an long integer value. */ double doubleValue; /* - a double-precision floating value. */ void *otherValuePtr; /* - another, type-specific value, not used internally any more. */ Tcl_WideInt wideValue; /* - a long long value. */ struct { /* - internal rep as two pointers. * the main use of which is a bignum's * tightly packed fields, where the alloc, * used and signum flags are packed into * ptr2 with everything else hung off ptr1. */ void *ptr1; void *ptr2; } twoPtrValue; struct { /* - internal rep as a pointer and a long, not used internally any more. */ void *ptr; unsigned long value; } ptrAndLongRep; } internalRep; } Tcl_Obj; /* * Macros to increment and decrement a Tcl_Obj's reference count, and to test * whether an object is shared (i.e. has reference count > 1). Note: clients * should use Tcl_DecrRefCount() when they are finished using an object, and * should never call TclFreeObj() directly. TclFreeObj() is only defined and * made public in tcl.h to support Tcl_DecrRefCount's macro definition. */ void Tcl_IncrRefCount(Tcl_Obj *objPtr); void Tcl_DecrRefCount(Tcl_Obj *objPtr); int Tcl_IsShared(Tcl_Obj *objPtr); /* *---------------------------------------------------------------------------- * The following structure contains the state needed by Tcl_SaveResult. No-one * outside of Tcl should access any of these fields. This structure is * typically allocated on the stack. */ typedef struct Tcl_SavedResult { char *result; Tcl_FreeProc *freeProc; Tcl_Obj *objResultPtr; char *appendResult; int appendAvl; int appendUsed; char resultSpace[TCL_RESULT_SIZE+1]; } Tcl_SavedResult; /* *---------------------------------------------------------------------------- * The following definitions support Tcl's namespace facility. Note: the first * five fields must match exactly the fields in a Namespace structure (see * tclInt.h). */ typedef struct Tcl_Namespace { char *name; /* The namespace's name within its parent * namespace. This contains no ::'s. The name * of the global namespace is "" although "::" * is an synonym. */ char *fullName; /* The namespace's fully qualified name. This * starts with ::. */ ClientData clientData; /* Arbitrary value associated with this * namespace. */ Tcl_NamespaceDeleteProc *deleteProc; /* Function invoked when deleting the * namespace to, e.g., free clientData. */ struct Tcl_Namespace *parentPtr; /* Points to the namespace that contains this * one. NULL if this is the global * namespace. */ } Tcl_Namespace; /* *---------------------------------------------------------------------------- * The following structure represents a call frame, or activation record. A * call frame defines a naming context for a procedure call: its local scope * (for local variables) and its namespace scope (used for non-local * variables; often the global :: namespace). A call frame can also define the * naming context for a namespace eval or namespace inscope command: the * namespace in which the command's code should execute. The Tcl_CallFrame * structures exist only while procedures or namespace eval/inscope's are * being executed, and provide a Tcl call stack. * * A call frame is initialized and pushed using Tcl_PushCallFrame and popped * using Tcl_PopCallFrame. Storage for a Tcl_CallFrame must be provided by the * Tcl_PushCallFrame caller, and callers typically allocate them on the C call * stack for efficiency. For this reason, Tcl_CallFrame is defined as a * structure and not as an opaque token. However, most Tcl_CallFrame fields * are hidden since applications should not access them directly; others are * declared as "dummyX". * * WARNING!! The structure definition must be kept consistent with the * CallFrame structure in tclInt.h. If you change one, change the other. */ typedef struct Tcl_CallFrame { Tcl_Namespace *nsPtr; int dummy1; int dummy2; void *dummy3; void *dummy4; void *dummy5; int dummy6; void *dummy7; void *dummy8; int dummy9; void *dummy10; void *dummy11; void *dummy12; void *dummy13; } Tcl_CallFrame; /* *---------------------------------------------------------------------------- * Information about commands that is returned by Tcl_GetCommandInfo and * passed to Tcl_SetCommandInfo. objProc is an objc/objv object-based command * function while proc is a traditional Tcl argc/argv string-based function. * Tcl_CreateObjCommand and Tcl_CreateCommand ensure that both objProc and * proc are non-NULL and can be called to execute the command. However, it may * be faster to call one instead of the other. The member isNativeObjectProc * is set to 1 if an object-based function was registered by * Tcl_CreateObjCommand, and to 0 if a string-based function was registered by * Tcl_CreateCommand. The other function is typically set to a compatibility * wrapper that does string-to-object or object-to-string argument conversions * then calls the other function. */ typedef struct Tcl_CmdInfo { int isNativeObjectProc; /* 1 if objProc was registered by a call to * Tcl_CreateObjCommand; 0 otherwise. * Tcl_SetCmdInfo does not modify this * field. */ Tcl_ObjCmdProc *objProc; /* Command's object-based function. */ ClientData objClientData; /* ClientData for object proc. */ Tcl_CmdProc *proc; /* Command's string-based function. */ ClientData clientData; /* ClientData for string proc. */ Tcl_CmdDeleteProc *deleteProc; /* Function to call when command is * deleted. */ ClientData deleteData; /* Value to pass to deleteProc (usually the * same as clientData). */ Tcl_Namespace *namespacePtr;/* Points to the namespace that contains this * command. Note that Tcl_SetCmdInfo will not * change a command's namespace; use * TclRenameCommand or Tcl_Eval (of 'rename') * to do that. */ } Tcl_CmdInfo; /* *---------------------------------------------------------------------------- * The structure defined below is used to hold dynamic strings. The only * fields that clients should use are string and length, accessible via the * macros Tcl_DStringValue and Tcl_DStringLength. */ #define TCL_DSTRING_STATIC_SIZE 200 typedef struct Tcl_DString { char *string; /* Points to beginning of string: either * staticSpace below or a malloced array. */ int length; /* Number of non-NULL characters in the * string. */ int spaceAvl; /* Total number of bytes available for the * string and its terminating NULL char. */ char staticSpace[TCL_DSTRING_STATIC_SIZE]; /* Space to use in common case where string is * small. */ } Tcl_DString; #define Tcl_DStringLength(dsPtr) ((dsPtr)->length) #define Tcl_DStringValue(dsPtr) ((dsPtr)->string) #define Tcl_DStringTrunc Tcl_DStringSetLength /* * Definitions for the maximum number of digits of precision that may be * specified in the "tcl_precision" variable, and the number of bytes of * buffer space required by Tcl_PrintDouble. */ #define TCL_MAX_PREC 17 #define TCL_DOUBLE_SPACE (TCL_MAX_PREC+10) /* * Definition for a number of bytes of buffer space sufficient to hold the * string representation of an integer in base 10 (assuming the existence of * 64-bit integers). */ #define TCL_INTEGER_SPACE 24 /* * Flag values passed to Tcl_ConvertElement. * TCL_DONT_USE_BRACES forces it not to enclose the element in braces, but to * use backslash quoting instead. * TCL_DONT_QUOTE_HASH disables the default quoting of the '#' character. It * is safe to leave the hash unquoted when the element is not the first * element of a list, and this flag can be used by the caller to indicate * that condition. */ #define TCL_DONT_USE_BRACES 1 #define TCL_DONT_QUOTE_HASH 8 /* * Flag that may be passed to Tcl_GetIndexFromObj to force it to disallow * abbreviated strings. */ #define TCL_EXACT 1 /* *---------------------------------------------------------------------------- * Flag values passed to Tcl_RecordAndEval, Tcl_EvalObj, Tcl_EvalObjv. * WARNING: these bit choices must not conflict with the bit choices for * evalFlag bits in tclInt.h! * * Meanings: * TCL_NO_EVAL: Just record this command * TCL_EVAL_GLOBAL: Execute script in global namespace * TCL_EVAL_DIRECT: Do not compile this script * TCL_EVAL_INVOKE: Magical Tcl_EvalObjv mode for aliases/ensembles * o Run in iPtr->lookupNsPtr or global namespace * o Cut out of error traces * o Don't reset the flags controlling ensemble * error message rewriting. * TCL_CANCEL_UNWIND: Magical Tcl_CancelEval mode that causes the * stack for the script in progress to be * completely unwound. * TCL_EVAL_NOERR: Do no exception reporting at all, just return * as the caller will report. */ #define TCL_NO_EVAL 0x010000 #define TCL_EVAL_GLOBAL 0x020000 #define TCL_EVAL_DIRECT 0x040000 #define TCL_EVAL_INVOKE 0x080000 #define TCL_CANCEL_UNWIND 0x100000 #define TCL_EVAL_NOERR 0x200000 /* * Special freeProc values that may be passed to Tcl_SetResult (see the man * page for details): */ #define TCL_VOLATILE ((Tcl_FreeProc *) 1) #define TCL_STATIC ((Tcl_FreeProc *) 0) #define TCL_DYNAMIC ((Tcl_FreeProc *) 3) /* * Flag values passed to variable-related functions. * WARNING: these bit choices must not conflict with the bit choice for * TCL_CANCEL_UNWIND, above. */ #define TCL_GLOBAL_ONLY 1 #define TCL_NAMESPACE_ONLY 2 #define TCL_APPEND_VALUE 4 #define TCL_LIST_ELEMENT 8 #define TCL_TRACE_READS 0x10 #define TCL_TRACE_WRITES 0x20 #define TCL_TRACE_UNSETS 0x40 #define TCL_TRACE_DESTROYED 0x80 #define TCL_INTERP_DESTROYED 0x100 #define TCL_LEAVE_ERR_MSG 0x200 #define TCL_TRACE_ARRAY 0x800 #ifndef TCL_REMOVE_OBSOLETE_TRACES /* Required to support old variable/vdelete/vinfo traces. */ #define TCL_TRACE_OLD_STYLE 0x1000 #endif /* Indicate the semantics of the result of a trace. */ #define TCL_TRACE_RESULT_DYNAMIC 0x8000 #define TCL_TRACE_RESULT_OBJECT 0x10000 /* * Flag values for ensemble commands. */ #define TCL_ENSEMBLE_PREFIX 0x02/* Flag value to say whether to allow * unambiguous prefixes of commands or to * require exact matches for command names. */ /* * Flag values passed to command-related functions. */ #define TCL_TRACE_RENAME 0x2000 #define TCL_TRACE_DELETE 0x4000 #define TCL_ALLOW_INLINE_COMPILATION 0x20000 /* * The TCL_PARSE_PART1 flag is deprecated and has no effect. The part1 is now * always parsed whenever the part2 is NULL. (This is to avoid a common error * when converting code to use the new object based APIs and forgetting to * give the flag) */ #ifndef TCL_NO_DEPRECATED # define TCL_PARSE_PART1 0x400 #endif /* * Types for linked variables: */ #define TCL_LINK_INT 1 #define TCL_LINK_DOUBLE 2 #define TCL_LINK_BOOLEAN 3 #define TCL_LINK_STRING 4 #define TCL_LINK_WIDE_INT 5 #define TCL_LINK_CHAR 6 #define TCL_LINK_UCHAR 7 #define TCL_LINK_SHORT 8 #define TCL_LINK_USHORT 9 #define TCL_LINK_UINT 10 #define TCL_LINK_LONG 11 #define TCL_LINK_ULONG 12 #define TCL_LINK_FLOAT 13 #define TCL_LINK_WIDE_UINT 14 #define TCL_LINK_READ_ONLY 0x80 /* *---------------------------------------------------------------------------- * Forward declarations of Tcl_HashTable and related types. */ typedef struct Tcl_HashKeyType Tcl_HashKeyType; typedef struct Tcl_HashTable Tcl_HashTable; typedef struct Tcl_HashEntry Tcl_HashEntry; typedef unsigned (Tcl_HashKeyProc) (Tcl_HashTable *tablePtr, void *keyPtr); typedef int (Tcl_CompareHashKeysProc) (void *keyPtr, Tcl_HashEntry *hPtr); typedef Tcl_HashEntry * (Tcl_AllocHashEntryProc) (Tcl_HashTable *tablePtr, void *keyPtr); typedef void (Tcl_FreeHashEntryProc) (Tcl_HashEntry *hPtr); /* * This flag controls whether the hash table stores the hash of a key, or * recalculates it. There should be no reason for turning this flag off as it * is completely binary and source compatible unless you directly access the * bucketPtr member of the Tcl_HashTableEntry structure. This member has been * removed and the space used to store the hash value. */ #ifndef TCL_HASH_KEY_STORE_HASH # define TCL_HASH_KEY_STORE_HASH 1 #endif /* * Structure definition for an entry in a hash table. No-one outside Tcl * should access any of these fields directly; use the macros defined below. */ struct Tcl_HashEntry { Tcl_HashEntry *nextPtr; /* Pointer to next entry in this hash bucket, * or NULL for end of chain. */ Tcl_HashTable *tablePtr; /* Pointer to table containing entry. */ #if TCL_HASH_KEY_STORE_HASH void *hash; /* Hash value, stored as pointer to ensure * that the offsets of the fields in this * structure are not changed. */ #else Tcl_HashEntry **bucketPtr; /* Pointer to bucket that points to first * entry in this entry's chain: used for * deleting the entry. */ #endif ClientData clientData; /* Application stores something here with * Tcl_SetHashValue. */ union { /* Key has one of these forms: */ char *oneWordValue; /* One-word value for key. */ Tcl_Obj *objPtr; /* Tcl_Obj * key value. */ int words[1]; /* Multiple integer words for key. The actual * size will be as large as necessary for this * table's keys. */ char string[1]; /* String for key. The actual size will be as * large as needed to hold the key. */ } key; /* MUST BE LAST FIELD IN RECORD!! */ }; /* * Flags used in Tcl_HashKeyType. * * TCL_HASH_KEY_RANDOMIZE_HASH - * There are some things, pointers for example * which don't hash well because they do not use * the lower bits. If this flag is set then the * hash table will attempt to rectify this by * randomising the bits and then using the upper * N bits as the index into the table. * TCL_HASH_KEY_SYSTEM_HASH - If this flag is set then all memory internally * allocated for the hash table that is not for an * entry will use the system heap. */ #define TCL_HASH_KEY_RANDOMIZE_HASH 0x1 #define TCL_HASH_KEY_SYSTEM_HASH 0x2 /* * Structure definition for the methods associated with a hash table key type. */ #define TCL_HASH_KEY_TYPE_VERSION 1 struct Tcl_HashKeyType { int version; /* Version of the table. If this structure is * extended in future then the version can be * used to distinguish between different * structures. */ int flags; /* Flags, see above for details. */ Tcl_HashKeyProc *hashKeyProc; /* Calculates a hash value for the key. If * this is NULL then the pointer itself is * used as a hash value. */ Tcl_CompareHashKeysProc *compareKeysProc; /* Compares two keys and returns zero if they * do not match, and non-zero if they do. If * this is NULL then the pointers are * compared. */ Tcl_AllocHashEntryProc *allocEntryProc; /* Called to allocate memory for a new entry, * i.e. if the key is a string then this could * allocate a single block which contains * enough space for both the entry and the * string. Only the key field of the allocated * Tcl_HashEntry structure needs to be filled * in. If something else needs to be done to * the key, i.e. incrementing a reference * count then that should be done by this * function. If this is NULL then Tcl_Alloc is * used to allocate enough space for a * Tcl_HashEntry and the key pointer is * assigned to key.oneWordValue. */ Tcl_FreeHashEntryProc *freeEntryProc; /* Called to free memory associated with an * entry. If something else needs to be done * to the key, i.e. decrementing a reference * count then that should be done by this * function. If this is NULL then Tcl_Free is * used to free the Tcl_HashEntry. */ }; /* * Structure definition for a hash table. Must be in tcl.h so clients can * allocate space for these structures, but clients should never access any * fields in this structure. */ #define TCL_SMALL_HASH_TABLE 4 struct Tcl_HashTable { Tcl_HashEntry **buckets; /* Pointer to bucket array. Each element * points to first entry in bucket's hash * chain, or NULL. */ Tcl_HashEntry *staticBuckets[TCL_SMALL_HASH_TABLE]; /* Bucket array used for small tables (to * avoid mallocs and frees). */ int numBuckets; /* Total number of buckets allocated at * **bucketPtr. */ int numEntries; /* Total number of entries present in * table. */ int rebuildSize; /* Enlarge table when numEntries gets to be * this large. */ int downShift; /* Shift count used in hashing function. * Designed to use high-order bits of * randomized keys. */ int mask; /* Mask value used in hashing function. */ int keyType; /* Type of keys used in this table. It's * either TCL_CUSTOM_KEYS, TCL_STRING_KEYS, * TCL_ONE_WORD_KEYS, or an integer giving the * number of ints that is the size of the * key. */ Tcl_HashEntry *(*findProc) (Tcl_HashTable *tablePtr, const char *key); Tcl_HashEntry *(*createProc) (Tcl_HashTable *tablePtr, const char *key, int *newPtr); const Tcl_HashKeyType *typePtr; /* Type of the keys used in the * Tcl_HashTable. */ }; /* * Structure definition for information used to keep track of searches through * hash tables: */ typedef struct Tcl_HashSearch { Tcl_HashTable *tablePtr; /* Table being searched. */ int nextIndex; /* Index of next bucket to be enumerated after * present one. */ Tcl_HashEntry *nextEntryPtr;/* Next entry to be enumerated in the current * bucket. */ } Tcl_HashSearch; /* * Acceptable key types for hash tables: * * TCL_STRING_KEYS: The keys are strings, they are copied into the * entry. * TCL_ONE_WORD_KEYS: The keys are pointers, the pointer is stored * in the entry. * TCL_CUSTOM_TYPE_KEYS: The keys are arbitrary types which are copied * into the entry. * TCL_CUSTOM_PTR_KEYS: The keys are pointers to arbitrary types, the * pointer is stored in the entry. * * While maintaining binary compatability the above have to be distinct values * as they are used to differentiate between old versions of the hash table * which don't have a typePtr and new ones which do. Once binary compatability * is discarded in favour of making more wide spread changes TCL_STRING_KEYS * can be the same as TCL_CUSTOM_TYPE_KEYS, and TCL_ONE_WORD_KEYS can be the * same as TCL_CUSTOM_PTR_KEYS because they simply determine how the key is * accessed from the entry and not the behaviour. */ #define TCL_STRING_KEYS (0) #define TCL_ONE_WORD_KEYS (1) #define TCL_CUSTOM_TYPE_KEYS (-2) #define TCL_CUSTOM_PTR_KEYS (-1) /* * Structure definition for information used to keep track of searches through * dictionaries. These fields should not be accessed by code outside * tclDictObj.c */ typedef struct { void *next; /* Search position for underlying hash * table. */ int epoch; /* Epoch marker for dictionary being searched, * or -1 if search has terminated. */ Tcl_Dict dictionaryPtr; /* Reference to dictionary being searched. */ } Tcl_DictSearch; /* *---------------------------------------------------------------------------- * Flag values to pass to Tcl_DoOneEvent to disable searches for some kinds of * events: */ #define TCL_DONT_WAIT (1<<1) #define TCL_WINDOW_EVENTS (1<<2) #define TCL_FILE_EVENTS (1<<3) #define TCL_TIMER_EVENTS (1<<4) #define TCL_IDLE_EVENTS (1<<5) /* WAS 0x10 ???? */ #define TCL_ALL_EVENTS (~TCL_DONT_WAIT) /* * The following structure defines a generic event for the Tcl event system. * These are the things that are queued in calls to Tcl_QueueEvent and * serviced later by Tcl_DoOneEvent. There can be many different kinds of * events with different fields, corresponding to window events, timer events, * etc. The structure for a particular event consists of a Tcl_Event header * followed by additional information specific to that event. */ struct Tcl_Event { Tcl_EventProc *proc; /* Function to call to service this event. */ struct Tcl_Event *nextPtr; /* Next in list of pending events, or NULL. */ }; /* * Positions to pass to Tcl_QueueEvent: */ typedef enum { TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK } Tcl_QueuePosition; /* * Values to pass to Tcl_SetServiceMode to specify the behavior of notifier * event routines. */ #define TCL_SERVICE_NONE 0 #define TCL_SERVICE_ALL 1 /* * The following structure keeps is used to hold a time value, either as an * absolute time (the number of seconds from the epoch) or as an elapsed time. * On Unix systems the epoch is Midnight Jan 1, 1970 GMT. */ typedef struct Tcl_Time { long sec; /* Seconds. */ long usec; /* Microseconds. */ } Tcl_Time; typedef void (Tcl_SetTimerProc) (CONST86 Tcl_Time *timePtr); typedef int (Tcl_WaitForEventProc) (CONST86 Tcl_Time *timePtr); /* * TIP #233 (Virtualized Time) */ typedef void (Tcl_GetTimeProc) (Tcl_Time *timebuf, ClientData clientData); typedef void (Tcl_ScaleTimeProc) (Tcl_Time *timebuf, ClientData clientData); /* *---------------------------------------------------------------------------- * Bits to pass to Tcl_CreateFileHandler and Tcl_CreateChannelHandler to * indicate what sorts of events are of interest: */ #define TCL_READABLE (1<<1) #define TCL_WRITABLE (1<<2) #define TCL_EXCEPTION (1<<3) /* * Flag values to pass to Tcl_OpenCommandChannel to indicate the disposition * of the stdio handles. TCL_STDIN, TCL_STDOUT, TCL_STDERR, are also used in * Tcl_GetStdChannel. */ #define TCL_STDIN (1<<1) #define TCL_STDOUT (1<<2) #define TCL_STDERR (1<<3) #define TCL_ENFORCE_MODE (1<<4) /* * Bits passed to Tcl_DriverClose2Proc to indicate which side of a channel * should be closed. */ #define TCL_CLOSE_READ (1<<1) #define TCL_CLOSE_WRITE (1<<2) /* * Value to use as the closeProc for a channel that supports the close2Proc * interface. */ #define TCL_CLOSE2PROC ((Tcl_DriverCloseProc *) 1) /* * Channel version tag. This was introduced in 8.3.2/8.4. */ #define TCL_CHANNEL_VERSION_1 ((Tcl_ChannelTypeVersion) 0x1) #define TCL_CHANNEL_VERSION_2 ((Tcl_ChannelTypeVersion) 0x2) #define TCL_CHANNEL_VERSION_3 ((Tcl_ChannelTypeVersion) 0x3) #define TCL_CHANNEL_VERSION_4 ((Tcl_ChannelTypeVersion) 0x4) #define TCL_CHANNEL_VERSION_5 ((Tcl_ChannelTypeVersion) 0x5) /* * TIP #218: Channel Actions, Ids for Tcl_DriverThreadActionProc. */ #define TCL_CHANNEL_THREAD_INSERT (0) #define TCL_CHANNEL_THREAD_REMOVE (1) /* * Typedefs for the various operations in a channel type: */ typedef int (Tcl_DriverBlockModeProc) (ClientData instanceData, int mode); typedef int (Tcl_DriverCloseProc) (ClientData instanceData, Tcl_Interp *interp); typedef int (Tcl_DriverClose2Proc) (ClientData instanceData, Tcl_Interp *interp, int flags); typedef int (Tcl_DriverInputProc) (ClientData instanceData, char *buf, int toRead, int *errorCodePtr); typedef int (Tcl_DriverOutputProc) (ClientData instanceData, CONST84 char *buf, int toWrite, int *errorCodePtr); typedef int (Tcl_DriverSeekProc) (ClientData instanceData, long offset, int mode, int *errorCodePtr); typedef int (Tcl_DriverSetOptionProc) (ClientData instanceData, Tcl_Interp *interp, const char *optionName, const char *value); typedef int (Tcl_DriverGetOptionProc) (ClientData instanceData, Tcl_Interp *interp, CONST84 char *optionName, Tcl_DString *dsPtr); typedef void (Tcl_DriverWatchProc) (ClientData instanceData, int mask); typedef int (Tcl_DriverGetHandleProc) (ClientData instanceData, int direction, ClientData *handlePtr); typedef int (Tcl_DriverFlushProc) (ClientData instanceData); typedef int (Tcl_DriverHandlerProc) (ClientData instanceData, int interestMask); typedef Tcl_WideInt (Tcl_DriverWideSeekProc) (ClientData instanceData, Tcl_WideInt offset, int mode, int *errorCodePtr); /* * TIP #218, Channel Thread Actions */ typedef void (Tcl_DriverThreadActionProc) (ClientData instanceData, int action); /* * TIP #208, File Truncation (etc.) */ typedef int (Tcl_DriverTruncateProc) (ClientData instanceData, Tcl_WideInt length); /* * struct Tcl_ChannelType: * * One such structure exists for each type (kind) of channel. It collects * together in one place all the functions that are part of the specific * channel type. * * It is recommend that the Tcl_Channel* functions are used to access elements * of this structure, instead of direct accessing. */ typedef struct Tcl_ChannelType { const char *typeName; /* The name of the channel type in Tcl * commands. This storage is owned by channel * type. */ Tcl_ChannelTypeVersion version; /* Version of the channel type. */ Tcl_DriverCloseProc *closeProc; /* Function to call to close the channel, or * TCL_CLOSE2PROC if the close2Proc should be * used instead. */ Tcl_DriverInputProc *inputProc; /* Function to call for input on channel. */ Tcl_DriverOutputProc *outputProc; /* Function to call for output on channel. */ Tcl_DriverSeekProc *seekProc; /* Function to call to seek on the channel. * May be NULL. */ Tcl_DriverSetOptionProc *setOptionProc; /* Set an option on a channel. */ Tcl_DriverGetOptionProc *getOptionProc; /* Get an option from a channel. */ Tcl_DriverWatchProc *watchProc; /* Set up the notifier to watch for events on * this channel. */ Tcl_DriverGetHandleProc *getHandleProc; /* Get an OS handle from the channel or NULL * if not supported. */ Tcl_DriverClose2Proc *close2Proc; /* Function to call to close the channel if * the device supports closing the read & * write sides independently. */ Tcl_DriverBlockModeProc *blockModeProc; /* Set blocking mode for the raw channel. May * be NULL. */ /* * Only valid in TCL_CHANNEL_VERSION_2 channels or later. */ Tcl_DriverFlushProc *flushProc; /* Function to call to flush a channel. May be * NULL. */ Tcl_DriverHandlerProc *handlerProc; /* Function to call to handle a channel event. * This will be passed up the stacked channel * chain. */ /* * Only valid in TCL_CHANNEL_VERSION_3 channels or later. */ Tcl_DriverWideSeekProc *wideSeekProc; /* Function to call to seek on the channel * which can handle 64-bit offsets. May be * NULL, and must be NULL if seekProc is * NULL. */ /* * Only valid in TCL_CHANNEL_VERSION_4 channels or later. * TIP #218, Channel Thread Actions. */ Tcl_DriverThreadActionProc *threadActionProc; /* Function to call to notify the driver of * thread specific activity for a channel. May * be NULL. */ /* * Only valid in TCL_CHANNEL_VERSION_5 channels or later. * TIP #208, File Truncation. */ Tcl_DriverTruncateProc *truncateProc; /* Function to call to truncate the underlying * file to a particular length. May be NULL if * the channel does not support truncation. */ } Tcl_ChannelType; /* * The following flags determine whether the blockModeProc above should set * the channel into blocking or nonblocking mode. They are passed as arguments * to the blockModeProc function in the above structure. */ #define TCL_MODE_BLOCKING 0 /* Put channel into blocking mode. */ #define TCL_MODE_NONBLOCKING 1 /* Put channel into nonblocking * mode. */ /* *---------------------------------------------------------------------------- * Enum for different types of file paths. */ typedef enum Tcl_PathType { TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, TCL_PATH_VOLUME_RELATIVE } Tcl_PathType; /* * The following structure is used to pass glob type data amongst the various * glob routines and Tcl_FSMatchInDirectory. */ typedef struct Tcl_GlobTypeData { int type; /* Corresponds to bcdpfls as in 'find -t'. */ int perm; /* Corresponds to file permissions. */ Tcl_Obj *macType; /* Acceptable Mac type. */ Tcl_Obj *macCreator; /* Acceptable Mac creator. */ } Tcl_GlobTypeData; /* * Type and permission definitions for glob command. */ #define TCL_GLOB_TYPE_BLOCK (1<<0) #define TCL_GLOB_TYPE_CHAR (1<<1) #define TCL_GLOB_TYPE_DIR (1<<2) #define TCL_GLOB_TYPE_PIPE (1<<3) #define TCL_GLOB_TYPE_FILE (1<<4) #define TCL_GLOB_TYPE_LINK (1<<5) #define TCL_GLOB_TYPE_SOCK (1<<6) #define TCL_GLOB_TYPE_MOUNT (1<<7) #define TCL_GLOB_PERM_RONLY (1<<0) #define TCL_GLOB_PERM_HIDDEN (1<<1) #define TCL_GLOB_PERM_R (1<<2) #define TCL_GLOB_PERM_W (1<<3) #define TCL_GLOB_PERM_X (1<<4) /* * Flags for the unload callback function. */ #define TCL_UNLOAD_DETACH_FROM_INTERPRETER (1<<0) #define TCL_UNLOAD_DETACH_FROM_PROCESS (1<<1) /* * Typedefs for the various filesystem operations: */ typedef int (Tcl_FSStatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); typedef int (Tcl_FSAccessProc) (Tcl_Obj *pathPtr, int mode); typedef Tcl_Channel (Tcl_FSOpenFileChannelProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr, int mode, int permissions); typedef int (Tcl_FSMatchInDirectoryProc) (Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); typedef Tcl_Obj * (Tcl_FSGetCwdProc) (Tcl_Interp *interp); typedef int (Tcl_FSChdirProc) (Tcl_Obj *pathPtr); typedef int (Tcl_FSLstatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); typedef int (Tcl_FSCreateDirectoryProc) (Tcl_Obj *pathPtr); typedef int (Tcl_FSDeleteFileProc) (Tcl_Obj *pathPtr); typedef int (Tcl_FSCopyDirectoryProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); typedef int (Tcl_FSCopyFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); typedef int (Tcl_FSRemoveDirectoryProc) (Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr); typedef int (Tcl_FSRenameFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); typedef void (Tcl_FSUnloadFileProc) (Tcl_LoadHandle loadHandle); typedef Tcl_Obj * (Tcl_FSListVolumesProc) (void); /* We have to declare the utime structure here. */ struct utimbuf; typedef int (Tcl_FSUtimeProc) (Tcl_Obj *pathPtr, struct utimbuf *tval); typedef int (Tcl_FSNormalizePathProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr, int nextCheckpoint); typedef int (Tcl_FSFileAttrsGetProc) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); typedef const char *CONST86 * (Tcl_FSFileAttrStringsProc) (Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); typedef int (Tcl_FSFileAttrsSetProc) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr); typedef Tcl_Obj * (Tcl_FSLinkProc) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkType); typedef int (Tcl_FSLoadFileProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); typedef int (Tcl_FSPathInFilesystemProc) (Tcl_Obj *pathPtr, ClientData *clientDataPtr); typedef Tcl_Obj * (Tcl_FSFilesystemPathTypeProc) (Tcl_Obj *pathPtr); typedef Tcl_Obj * (Tcl_FSFilesystemSeparatorProc) (Tcl_Obj *pathPtr); typedef void (Tcl_FSFreeInternalRepProc) (ClientData clientData); typedef ClientData (Tcl_FSDupInternalRepProc) (ClientData clientData); typedef Tcl_Obj * (Tcl_FSInternalToNormalizedProc) (ClientData clientData); typedef ClientData (Tcl_FSCreateInternalRepProc) (Tcl_Obj *pathPtr); typedef struct Tcl_FSVersion_ *Tcl_FSVersion; /* *---------------------------------------------------------------------------- * Data structures related to hooking into the filesystem */ /* * Filesystem version tag. This was introduced in 8.4. */ #define TCL_FILESYSTEM_VERSION_1 ((Tcl_FSVersion) 0x1) /* * struct Tcl_Filesystem: * * One such structure exists for each type (kind) of filesystem. It collects * together in one place all the functions that are part of the specific * filesystem. Tcl always accesses the filesystem through one of these * structures. * * Not all entries need be non-NULL; any which are NULL are simply ignored. * However, a complete filesystem should provide all of these functions. The * explanations in the structure show the importance of each function. */ typedef struct Tcl_Filesystem { const char *typeName; /* The name of the filesystem. */ int structureLength; /* Length of this structure, so future binary * compatibility can be assured. */ Tcl_FSVersion version; /* Version of the filesystem type. */ Tcl_FSPathInFilesystemProc *pathInFilesystemProc; /* Function to check whether a path is in this * filesystem. This is the most important * filesystem function. */ Tcl_FSDupInternalRepProc *dupInternalRepProc; /* Function to duplicate internal fs rep. May * be NULL (but then fs is less efficient). */ Tcl_FSFreeInternalRepProc *freeInternalRepProc; /* Function to free internal fs rep. Must be * implemented if internal representations * need freeing, otherwise it can be NULL. */ Tcl_FSInternalToNormalizedProc *internalToNormalizedProc; /* Function to convert internal representation * to a normalized path. Only required if the * fs creates pure path objects with no * string/path representation. */ Tcl_FSCreateInternalRepProc *createInternalRepProc; /* Function to create a filesystem-specific * internal representation. May be NULL if * paths have no internal representation, or * if the Tcl_FSPathInFilesystemProc for this * filesystem always immediately creates an * internal representation for paths it * accepts. */ Tcl_FSNormalizePathProc *normalizePathProc; /* Function to normalize a path. Should be * implemented for all filesystems which can * have multiple string representations for * the same path object. */ Tcl_FSFilesystemPathTypeProc *filesystemPathTypeProc; /* Function to determine the type of a path in * this filesystem. May be NULL. */ Tcl_FSFilesystemSeparatorProc *filesystemSeparatorProc; /* Function to return the separator * character(s) for this filesystem. Must be * implemented. */ Tcl_FSStatProc *statProc; /* Function to process a 'Tcl_FSStat()' call. * Must be implemented for any reasonable * filesystem. */ Tcl_FSAccessProc *accessProc; /* Function to process a 'Tcl_FSAccess()' * call. Must be implemented for any * reasonable filesystem. */ Tcl_FSOpenFileChannelProc *openFileChannelProc; /* Function to process a * 'Tcl_FSOpenFileChannel()' call. Must be * implemented for any reasonable * filesystem. */ Tcl_FSMatchInDirectoryProc *matchInDirectoryProc; /* Function to process a * 'Tcl_FSMatchInDirectory()'. If not * implemented, then glob and recursive copy * functionality will be lacking in the * filesystem. */ Tcl_FSUtimeProc *utimeProc; /* Function to process a 'Tcl_FSUtime()' call. * Required to allow setting (not reading) of * times with 'file mtime', 'file atime' and * the open-r/open-w/fcopy implementation of * 'file copy'. */ Tcl_FSLinkProc *linkProc; /* Function to process a 'Tcl_FSLink()' call. * Should be implemented only if the * filesystem supports links (reading or * creating). */ Tcl_FSListVolumesProc *listVolumesProc; /* Function to list any filesystem volumes * added by this filesystem. Should be * implemented only if the filesystem adds * volumes at the head of the filesystem. */ Tcl_FSFileAttrStringsProc *fileAttrStringsProc; /* Function to list all attributes strings * which are valid for this filesystem. If not * implemented the filesystem will not support * the 'file attributes' command. This allows * arbitrary additional information to be * attached to files in the filesystem. */ Tcl_FSFileAttrsGetProc *fileAttrsGetProc; /* Function to process a * 'Tcl_FSFileAttrsGet()' call, used by 'file * attributes'. */ Tcl_FSFileAttrsSetProc *fileAttrsSetProc; /* Function to process a * 'Tcl_FSFileAttrsSet()' call, used by 'file * attributes'. */ Tcl_FSCreateDirectoryProc *createDirectoryProc; /* Function to process a * 'Tcl_FSCreateDirectory()' call. Should be * implemented unless the FS is read-only. */ Tcl_FSRemoveDirectoryProc *removeDirectoryProc; /* Function to process a * 'Tcl_FSRemoveDirectory()' call. Should be * implemented unless the FS is read-only. */ Tcl_FSDeleteFileProc *deleteFileProc; /* Function to process a 'Tcl_FSDeleteFile()' * call. Should be implemented unless the FS * is read-only. */ Tcl_FSCopyFileProc *copyFileProc; /* Function to process a 'Tcl_FSCopyFile()' * call. If not implemented Tcl will fall back * on open-r, open-w and fcopy as a copying * mechanism, for copying actions initiated in * Tcl (not C). */ Tcl_FSRenameFileProc *renameFileProc; /* Function to process a 'Tcl_FSRenameFile()' * call. If not implemented, Tcl will fall * back on a copy and delete mechanism, for * rename actions initiated in Tcl (not C). */ Tcl_FSCopyDirectoryProc *copyDirectoryProc; /* Function to process a * 'Tcl_FSCopyDirectory()' call. If not * implemented, Tcl will fall back on a * recursive create-dir, file copy mechanism, * for copying actions initiated in Tcl (not * C). */ Tcl_FSLstatProc *lstatProc; /* Function to process a 'Tcl_FSLstat()' call. * If not implemented, Tcl will attempt to use * the 'statProc' defined above instead. */ Tcl_FSLoadFileProc *loadFileProc; /* Function to process a 'Tcl_FSLoadFile()' * call. If not implemented, Tcl will fall * back on a copy to native-temp followed by a * Tcl_FSLoadFile on that temporary copy. */ Tcl_FSGetCwdProc *getCwdProc; /* Function to process a 'Tcl_FSGetCwd()' * call. Most filesystems need not implement * this. It will usually only be called once, * if 'getcwd' is called before 'chdir'. May * be NULL. */ Tcl_FSChdirProc *chdirProc; /* Function to process a 'Tcl_FSChdir()' call. * If filesystems do not implement this, it * will be emulated by a series of directory * access checks. Otherwise, virtual * filesystems which do implement it need only * respond with a positive return result if * the dirName is a valid directory in their * filesystem. They need not remember the * result, since that will be automatically * remembered for use by GetCwd. Real * filesystems should carry out the correct * action (i.e. call the correct system * 'chdir' api). If not implemented, then 'cd' * and 'pwd' will fail inside the * filesystem. */ } Tcl_Filesystem; /* * The following definitions are used as values for the 'linkAction' flag to * Tcl_FSLink, or the linkProc of any filesystem. Any combination of flags can * be given. For link creation, the linkProc should create a link which * matches any of the types given. * * TCL_CREATE_SYMBOLIC_LINK - Create a symbolic or soft link. * TCL_CREATE_HARD_LINK - Create a hard link. */ #define TCL_CREATE_SYMBOLIC_LINK 0x01 #define TCL_CREATE_HARD_LINK 0x02 /* *---------------------------------------------------------------------------- * The following structure represents the Notifier functions that you can * override with the Tcl_SetNotifier call. */ typedef struct Tcl_NotifierProcs { Tcl_SetTimerProc *setTimerProc; Tcl_WaitForEventProc *waitForEventProc; Tcl_CreateFileHandlerProc *createFileHandlerProc; Tcl_DeleteFileHandlerProc *deleteFileHandlerProc; Tcl_InitNotifierProc *initNotifierProc; Tcl_FinalizeNotifierProc *finalizeNotifierProc; Tcl_AlertNotifierProc *alertNotifierProc; Tcl_ServiceModeHookProc *serviceModeHookProc; } Tcl_NotifierProcs; /* *---------------------------------------------------------------------------- * The following data structures and declarations are for the new Tcl parser. * * For each word of a command, and for each piece of a word such as a variable * reference, one of the following structures is created to describe the * token. */ typedef struct Tcl_Token { int type; /* Type of token, such as TCL_TOKEN_WORD; see * below for valid types. */ const char *start; /* First character in token. */ int size; /* Number of bytes in token. */ int numComponents; /* If this token is composed of other tokens, * this field tells how many of them there are * (including components of components, etc.). * The component tokens immediately follow * this one. */ } Tcl_Token; /* * Type values defined for Tcl_Token structures. These values are defined as * mask bits so that it's easy to check for collections of types. * * TCL_TOKEN_WORD - The token describes one word of a command, * from the first non-blank character of the word * (which may be " or {) up to but not including * the space, semicolon, or bracket that * terminates the word. NumComponents counts the * total number of sub-tokens that make up the * word. This includes, for example, sub-tokens * of TCL_TOKEN_VARIABLE tokens. * TCL_TOKEN_SIMPLE_WORD - This token is just like TCL_TOKEN_WORD except * that the word is guaranteed to consist of a * single TCL_TOKEN_TEXT sub-token. * TCL_TOKEN_TEXT - The token describes a range of literal text * that is part of a word. NumComponents is * always 0. * TCL_TOKEN_BS - The token describes a backslash sequence that * must be collapsed. NumComponents is always 0. * TCL_TOKEN_COMMAND - The token describes a command whose result * must be substituted into the word. The token * includes the enclosing brackets. NumComponents * is always 0. * TCL_TOKEN_VARIABLE - The token describes a variable substitution, * including the dollar sign, variable name, and * array index (if there is one) up through the * right parentheses. NumComponents tells how * many additional tokens follow to represent the * variable name. The first token will be a * TCL_TOKEN_TEXT token that describes the * variable name. If the variable is an array * reference then there will be one or more * additional tokens, of type TCL_TOKEN_TEXT, * TCL_TOKEN_BS, TCL_TOKEN_COMMAND, and * TCL_TOKEN_VARIABLE, that describe the array * index; numComponents counts the total number * of nested tokens that make up the variable * reference, including sub-tokens of * TCL_TOKEN_VARIABLE tokens. * TCL_TOKEN_SUB_EXPR - The token describes one subexpression of an * expression, from the first non-blank character * of the subexpression up to but not including * the space, brace, or bracket that terminates * the subexpression. NumComponents counts the * total number of following subtokens that make * up the subexpression; this includes all * subtokens for any nested TCL_TOKEN_SUB_EXPR * tokens. For example, a numeric value used as a * primitive operand is described by a * TCL_TOKEN_SUB_EXPR token followed by a * TCL_TOKEN_TEXT token. A binary subexpression * is described by a TCL_TOKEN_SUB_EXPR token * followed by the TCL_TOKEN_OPERATOR token for * the operator, then TCL_TOKEN_SUB_EXPR tokens * for the left then the right operands. * TCL_TOKEN_OPERATOR - The token describes one expression operator. * An operator might be the name of a math * function such as "abs". A TCL_TOKEN_OPERATOR * token is always preceeded by one * TCL_TOKEN_SUB_EXPR token for the operator's * subexpression, and is followed by zero or more * TCL_TOKEN_SUB_EXPR tokens for the operator's * operands. NumComponents is always 0. * TCL_TOKEN_EXPAND_WORD - This token is just like TCL_TOKEN_WORD except * that it marks a word that began with the * literal character prefix "{*}". This word is * marked to be expanded - that is, broken into * words after substitution is complete. */ #define TCL_TOKEN_WORD 1 #define TCL_TOKEN_SIMPLE_WORD 2 #define TCL_TOKEN_TEXT 4 #define TCL_TOKEN_BS 8 #define TCL_TOKEN_COMMAND 16 #define TCL_TOKEN_VARIABLE 32 #define TCL_TOKEN_SUB_EXPR 64 #define TCL_TOKEN_OPERATOR 128 #define TCL_TOKEN_EXPAND_WORD 256 /* * Parsing error types. On any parsing error, one of these values will be * stored in the error field of the Tcl_Parse structure defined below. */ #define TCL_PARSE_SUCCESS 0 #define TCL_PARSE_QUOTE_EXTRA 1 #define TCL_PARSE_BRACE_EXTRA 2 #define TCL_PARSE_MISSING_BRACE 3 #define TCL_PARSE_MISSING_BRACKET 4 #define TCL_PARSE_MISSING_PAREN 5 #define TCL_PARSE_MISSING_QUOTE 6 #define TCL_PARSE_MISSING_VAR_BRACE 7 #define TCL_PARSE_SYNTAX 8 #define TCL_PARSE_BAD_NUMBER 9 /* * A structure of the following type is filled in by Tcl_ParseCommand. It * describes a single command parsed from an input string. */ #define NUM_STATIC_TOKENS 20 typedef struct Tcl_Parse { const char *commentStart; /* Pointer to # that begins the first of one * or more comments preceding the command. */ int commentSize; /* Number of bytes in comments (up through * newline character that terminates the last * comment). If there were no comments, this * field is 0. */ const char *commandStart; /* First character in first word of * command. */ int commandSize; /* Number of bytes in command, including first * character of first word, up through the * terminating newline, close bracket, or * semicolon. */ int numWords; /* Total number of words in command. May be * 0. */ Tcl_Token *tokenPtr; /* Pointer to first token representing the * words of the command. Initially points to * staticTokens, but may change to point to * malloc-ed space if command exceeds space in * staticTokens. */ int numTokens; /* Total number of tokens in command. */ int tokensAvailable; /* Total number of tokens available at * *tokenPtr. */ int errorType; /* One of the parsing error types defined * above. */ /* * The fields below are intended only for the private use of the parser. * They should not be used by functions that invoke Tcl_ParseCommand. */ const char *string; /* The original command string passed to * Tcl_ParseCommand. */ const char *end; /* Points to the character just after the last * one in the command string. */ Tcl_Interp *interp; /* Interpreter to use for error reporting, or * NULL. */ const char *term; /* Points to character in string that * terminated most recent token. Filled in by * ParseTokens. If an error occurs, points to * beginning of region where the error * occurred (e.g. the open brace if the close * brace is missing). */ int incomplete; /* This field is set to 1 by Tcl_ParseCommand * if the command appears to be incomplete. * This information is used by * Tcl_CommandComplete. */ Tcl_Token staticTokens[NUM_STATIC_TOKENS]; /* Initial space for tokens for command. This * space should be large enough to accommodate * most commands; dynamic space is allocated * for very large commands that don't fit * here. */ } Tcl_Parse; /* *---------------------------------------------------------------------------- * The following structure represents a user-defined encoding. It collects * together all the functions that are used by the specific encoding. */ typedef struct Tcl_EncodingType { const char *encodingName; /* The name of the encoding, e.g. "euc-jp". * This name is the unique key for this * encoding type. */ Tcl_EncodingConvertProc *toUtfProc; /* Function to convert from external encoding * into UTF-8. */ Tcl_EncodingConvertProc *fromUtfProc; /* Function to convert from UTF-8 into * external encoding. */ Tcl_EncodingFreeProc *freeProc; /* If non-NULL, function to call when this * encoding is deleted. */ ClientData clientData; /* Arbitrary value associated with encoding * type. Passed to conversion functions. */ int nullSize; /* Number of zero bytes that signify * end-of-string in this encoding. This number * is used to determine the source string * length when the srcLen argument is * negative. Must be 1 or 2. */ } Tcl_EncodingType; /* * The following definitions are used as values for the conversion control * flags argument when converting text from one character set to another: * * TCL_ENCODING_START - Signifies that the source buffer is the first * block in a (potentially multi-block) input * stream. Tells the conversion function to reset * to an initial state and perform any * initialization that needs to occur before the * first byte is converted. If the source buffer * contains the entire input stream to be * converted, this flag should be set. * TCL_ENCODING_END - Signifies that the source buffer is the last * block in a (potentially multi-block) input * stream. Tells the conversion routine to * perform any finalization that needs to occur * after the last byte is converted and then to * reset to an initial state. If the source * buffer contains the entire input stream to be * converted, this flag should be set. * TCL_ENCODING_STOPONERROR - If set, then the converter will return * immediately upon encountering an invalid byte * sequence or a source character that has no * mapping in the target encoding. If clear, then * the converter will skip the problem, * substituting one or more "close" characters in * the destination buffer and then continue to * convert the source. * TCL_ENCODING_NO_TERMINATE - If set, Tcl_ExternalToUtf will not append a * terminating NUL byte. Knowing that it will * not need space to do so, it will fill all * dstLen bytes with encoded UTF-8 content, as * other circumstances permit. If clear, the * default behavior is to reserve a byte in * the dst space for NUL termination, and to * append the NUL byte. * TCL_ENCODING_CHAR_LIMIT - If set and dstCharsPtr is not NULL, then * Tcl_ExternalToUtf takes the initial value * of *dstCharsPtr is taken as a limit of the * maximum number of chars to produce in the * encoded UTF-8 content. Otherwise, the * number of chars produced is controlled only * by other limiting factors. */ #define TCL_ENCODING_START 0x01 #define TCL_ENCODING_END 0x02 #define TCL_ENCODING_STOPONERROR 0x04 #define TCL_ENCODING_NO_TERMINATE 0x08 #define TCL_ENCODING_CHAR_LIMIT 0x10 /* * The following definitions are the error codes returned by the conversion * routines: * * TCL_OK - All characters were converted. * TCL_CONVERT_NOSPACE - The output buffer would not have been large * enough for all of the converted data; as many * characters as could fit were converted though. * TCL_CONVERT_MULTIBYTE - The last few bytes in the source string were * the beginning of a multibyte sequence, but * more bytes were needed to complete this * sequence. A subsequent call to the conversion * routine should pass the beginning of this * unconverted sequence plus additional bytes * from the source stream to properly convert the * formerly split-up multibyte sequence. * TCL_CONVERT_SYNTAX - The source stream contained an invalid * character sequence. This may occur if the * input stream has been damaged or if the input * encoding method was misidentified. This error * is reported only if TCL_ENCODING_STOPONERROR * was specified. * TCL_CONVERT_UNKNOWN - The source string contained a character that * could not be represented in the target * encoding. This error is reported only if * TCL_ENCODING_STOPONERROR was specified. */ #define TCL_CONVERT_MULTIBYTE (-1) #define TCL_CONVERT_SYNTAX (-2) #define TCL_CONVERT_UNKNOWN (-3) #define TCL_CONVERT_NOSPACE (-4) /* * The maximum number of bytes that are necessary to represent a single * Unicode character in UTF-8. The valid values should be 3, 4 or 6 * (or perhaps 1 if we want to support a non-unicode enabled core). If 3 or * 4, then Tcl_UniChar must be 2-bytes in size (UCS-2) (the default). If 6, * then Tcl_UniChar must be 4-bytes in size (UCS-4). At this time UCS-2 mode * is the default and recommended mode. UCS-4 is experimental and not * recommended. It works for the core, but most extensions expect UCS-2. */ #ifndef TCL_UTF_MAX #define TCL_UTF_MAX 3 #endif /* * This represents a Unicode character. Any changes to this should also be * reflected in regcustom.h. */ #if TCL_UTF_MAX > 4 /* * unsigned int isn't 100% accurate as it should be a strict 4-byte value * (perhaps wchar_t). 64-bit systems may have troubles. The size of this * value must be reflected correctly in regcustom.h and * in tclEncoding.c. * XXX: Tcl is currently UCS-2 and planning UTF-16 for the Unicode * XXX: string rep that Tcl_UniChar represents. Changing the size * XXX: of Tcl_UniChar is /not/ supported. */ typedef unsigned int Tcl_UniChar; #else typedef unsigned short Tcl_UniChar; #endif /* *---------------------------------------------------------------------------- * TIP #59: The following structure is used in calls 'Tcl_RegisterConfig' to * provide the system with the embedded configuration data. */ typedef struct Tcl_Config { const char *key; /* Configuration key to register. ASCII * encoded, thus UTF-8. */ const char *value; /* The value associated with the key. System * encoding. */ } Tcl_Config; /* *---------------------------------------------------------------------------- * Flags for TIP#143 limits, detailing which limits are active in an * interpreter. Used for Tcl_{Add,Remove}LimitHandler type argument. */ #define TCL_LIMIT_COMMANDS 0x01 #define TCL_LIMIT_TIME 0x02 /* * Structure containing information about a limit handler to be called when a * command- or time-limit is exceeded by an interpreter. */ typedef void (Tcl_LimitHandlerProc) (ClientData clientData, Tcl_Interp *interp); typedef void (Tcl_LimitHandlerDeleteProc) (ClientData clientData); /* *---------------------------------------------------------------------------- * Override definitions for libtommath. */ typedef struct mp_int mp_int; #define MP_INT_DECLARED typedef unsigned int mp_digit; #define MP_DIGIT_DECLARED /* *---------------------------------------------------------------------------- * Definitions needed for Tcl_ParseArgvObj routines. * Based on tkArgv.c. * Modifications from the original are copyright (c) Sam Bromley 2006 */ typedef struct { int type; /* Indicates the option type; see below. */ const char *keyStr; /* The key string that flags the option in the * argv array. */ void *srcPtr; /* Value to be used in setting dst; usage * depends on type.*/ void *dstPtr; /* Address of value to be modified; usage * depends on type.*/ const char *helpStr; /* Documentation message describing this * option. */ ClientData clientData; /* Word to pass to function callbacks. */ } Tcl_ArgvInfo; /* * Legal values for the type field of a Tcl_ArgInfo: see the user * documentation for details. */ #define TCL_ARGV_CONSTANT 15 #define TCL_ARGV_INT 16 #define TCL_ARGV_STRING 17 #define TCL_ARGV_REST 18 #define TCL_ARGV_FLOAT 19 #define TCL_ARGV_FUNC 20 #define TCL_ARGV_GENFUNC 21 #define TCL_ARGV_HELP 22 #define TCL_ARGV_END 23 /* * Types of callback functions for the TCL_ARGV_FUNC and TCL_ARGV_GENFUNC * argument types: */ typedef int (Tcl_ArgvFuncProc)(ClientData clientData, Tcl_Obj *objPtr, void *dstPtr); typedef int (Tcl_ArgvGenFuncProc)(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv, void *dstPtr); /* * Shorthand for commonly used argTable entries. */ #define TCL_ARGV_AUTO_HELP \ {TCL_ARGV_HELP, "-help", NULL, NULL, \ "Print summary of command-line options and abort", NULL} #define TCL_ARGV_AUTO_REST \ {TCL_ARGV_REST, "--", NULL, NULL, \ "Marks the end of the options", NULL} #define TCL_ARGV_TABLE_END \ {TCL_ARGV_END, NULL, NULL, NULL, NULL, NULL} /* *---------------------------------------------------------------------------- * Definitions needed for Tcl_Zlib routines. [TIP #234] * * Constants for the format flags describing what sort of data format is * desired/expected for the Tcl_ZlibDeflate, Tcl_ZlibInflate and * Tcl_ZlibStreamInit functions. */ #define TCL_ZLIB_FORMAT_RAW 1 #define TCL_ZLIB_FORMAT_ZLIB 2 #define TCL_ZLIB_FORMAT_GZIP 4 #define TCL_ZLIB_FORMAT_AUTO 8 /* * Constants that describe whether the stream is to operate in compressing or * decompressing mode. */ #define TCL_ZLIB_STREAM_DEFLATE 16 #define TCL_ZLIB_STREAM_INFLATE 32 /* * Constants giving compression levels. Use of TCL_ZLIB_COMPRESS_DEFAULT is * recommended. */ #define TCL_ZLIB_COMPRESS_NONE 0 #define TCL_ZLIB_COMPRESS_FAST 1 #define TCL_ZLIB_COMPRESS_BEST 9 #define TCL_ZLIB_COMPRESS_DEFAULT (-1) /* * Constants for types of flushing, used with Tcl_ZlibFlush. */ #define TCL_ZLIB_NO_FLUSH 0 #define TCL_ZLIB_FLUSH 2 #define TCL_ZLIB_FULLFLUSH 3 #define TCL_ZLIB_FINALIZE 4 /* *---------------------------------------------------------------------------- * Definitions needed for the Tcl_LoadFile function. [TIP #416] */ #define TCL_LOAD_GLOBAL 1 #define TCL_LOAD_LAZY 2 /* *---------------------------------------------------------------------------- * Single public declaration for NRE. */ typedef int (Tcl_NRPostProc) (ClientData data[], Tcl_Interp *interp, int result); /* *---------------------------------------------------------------------------- * The following constant is used to test for older versions of Tcl in the * stubs tables. * * Jan Nijtman's plus patch uses 0xFCA1BACF, so we need to pick a different * value since the stubs tables don't match. */ #define TCL_STUB_MAGIC ((int) 0xFCA3BACF) /* * The following function is required to be defined in all stubs aware * extensions. The function is actually implemented in the stub library, not * the main Tcl library, although there is a trivial implementation in the * main library in case an extension is statically linked into an application. */ const char * Tcl_InitStubs(Tcl_Interp *interp, const char *version, int exact); const char * TclTomMathInitializeStubs(Tcl_Interp *interp, const char *version, int epoch, int revision); /* * When not using stubs, make it a macro. */ #ifndef USE_TCL_STUBS #define Tcl_InitStubs(interp, version, exact) \ Tcl_PkgInitStubsCheck(interp, version, exact) #endif /* * TODO - tommath stubs export goes here! */ /* * Public functions that are not accessible via the stubs table. * Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171] */ #define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \ ((Tcl_CreateInterp)())) EXTERN void Tcl_MainEx(int argc, char **argv, Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp, const char *version, int exact); EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr); /* *---------------------------------------------------------------------------- * Include the public function declarations that are accessible via the stubs * table. */ #include "tclDecls.h" /* * Include platform specific public function declarations that are accessible * via the stubs table. Make all TclOO symbols MODULE_SCOPE (which only * has effect on building it as a shared library). See ticket [3010352]. */ #if defined(BUILD_tcl) # undef TCLAPI # define TCLAPI MODULE_SCOPE #endif #include "tclPlatDecls.h" /* *---------------------------------------------------------------------------- * The following declarations either map ckalloc and ckfree to malloc and * free, or they map them to functions with all sorts of debugging hooks * defined in tclCkalloc.c. */ #ifdef TCL_MEM_DEBUG # define ckalloc(x) \ ((void *) Tcl_DbCkalloc((unsigned)(x), __FILE__, __LINE__)) # define ckfree(x) \ Tcl_DbCkfree((char *)(x), __FILE__, __LINE__) # define ckrealloc(x,y) \ ((void *) Tcl_DbCkrealloc((char *)(x), (unsigned)(y), __FILE__, __LINE__)) # define attemptckalloc(x) \ ((void *) Tcl_AttemptDbCkalloc((unsigned)(x), __FILE__, __LINE__)) # define attemptckrealloc(x,y) \ ((void *) Tcl_AttemptDbCkrealloc((char *)(x), (unsigned)(y), __FILE__, __LINE__)) #else /* !TCL_MEM_DEBUG */ /* * If we are not using the debugging allocator, we should call the Tcl_Alloc, * et al. routines in order to guarantee that every module is using the same * memory allocator both inside and outside of the Tcl library. */ # define ckalloc(x) \ ((void *) Tcl_Alloc((unsigned)(x))) # define ckfree(x) \ Tcl_Free((char *)(x)) # define ckrealloc(x,y) \ ((void *) Tcl_Realloc((char *)(x), (unsigned)(y))) # define attemptckalloc(x) \ ((void *) Tcl_AttemptAlloc((unsigned)(x))) # define attemptckrealloc(x,y) \ ((void *) Tcl_AttemptRealloc((char *)(x), (unsigned)(y))) # undef Tcl_InitMemory # define Tcl_InitMemory(x) # undef Tcl_DumpActiveMemory # define Tcl_DumpActiveMemory(x) # undef Tcl_ValidateAllMemory # define Tcl_ValidateAllMemory(x,y) #endif /* !TCL_MEM_DEBUG */ #ifdef TCL_MEM_DEBUG # define Tcl_IncrRefCount(objPtr) \ Tcl_DbIncrRefCount(objPtr, __FILE__, __LINE__) # define Tcl_DecrRefCount(objPtr) \ Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__) # define Tcl_IsShared(objPtr) \ Tcl_DbIsShared(objPtr, __FILE__, __LINE__) #else # define Tcl_IncrRefCount(objPtr) \ ++(objPtr)->refCount /* * Use do/while0 idiom for optimum correctness without compiler warnings. * http://c2.com/cgi/wiki?TrivialDoWhileLoop */ # define Tcl_DecrRefCount(objPtr) \ do { \ Tcl_Obj *_objPtr = (objPtr); \ if ((_objPtr)->refCount-- <= 1) { \ TclFreeObj(_objPtr); \ } \ } while(0) # define Tcl_IsShared(objPtr) \ ((objPtr)->refCount > 1) #endif /* * Macros and definitions that help to debug the use of Tcl objects. When * TCL_MEM_DEBUG is defined, the Tcl_New declarations are overridden to call * debugging versions of the object creation functions. */ #ifdef TCL_MEM_DEBUG # undef Tcl_NewBignumObj # define Tcl_NewBignumObj(val) \ Tcl_DbNewBignumObj(val, __FILE__, __LINE__) # undef Tcl_NewBooleanObj # define Tcl_NewBooleanObj(val) \ Tcl_DbNewBooleanObj(val, __FILE__, __LINE__) # undef Tcl_NewByteArrayObj # define Tcl_NewByteArrayObj(bytes, len) \ Tcl_DbNewByteArrayObj(bytes, len, __FILE__, __LINE__) # undef Tcl_NewDoubleObj # define Tcl_NewDoubleObj(val) \ Tcl_DbNewDoubleObj(val, __FILE__, __LINE__) # undef Tcl_NewIntObj # define Tcl_NewIntObj(val) \ Tcl_DbNewLongObj(val, __FILE__, __LINE__) # undef Tcl_NewListObj # define Tcl_NewListObj(objc, objv) \ Tcl_DbNewListObj(objc, objv, __FILE__, __LINE__) # undef Tcl_NewLongObj # define Tcl_NewLongObj(val) \ Tcl_DbNewLongObj(val, __FILE__, __LINE__) # undef Tcl_NewObj # define Tcl_NewObj() \ Tcl_DbNewObj(__FILE__, __LINE__) # undef Tcl_NewStringObj # define Tcl_NewStringObj(bytes, len) \ Tcl_DbNewStringObj(bytes, len, __FILE__, __LINE__) # undef Tcl_NewWideIntObj # define Tcl_NewWideIntObj(val) \ Tcl_DbNewWideIntObj(val, __FILE__, __LINE__) #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------------- * Macros for clients to use to access fields of hash entries: */ #define Tcl_GetHashValue(h) ((h)->clientData) #define Tcl_SetHashValue(h, value) ((h)->clientData = (ClientData) (value)) #define Tcl_GetHashKey(tablePtr, h) \ ((void *) (((tablePtr)->keyType == TCL_ONE_WORD_KEYS || \ (tablePtr)->keyType == TCL_CUSTOM_PTR_KEYS) \ ? (h)->key.oneWordValue \ : (h)->key.string)) /* * Macros to use for clients to use to invoke find and create functions for * hash tables: */ #undef Tcl_FindHashEntry #define Tcl_FindHashEntry(tablePtr, key) \ (*((tablePtr)->findProc))(tablePtr, (const char *)(key)) #undef Tcl_CreateHashEntry #define Tcl_CreateHashEntry(tablePtr, key, newPtr) \ (*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr) /* *---------------------------------------------------------------------------- * Macros that eliminate the overhead of the thread synchronization functions * when compiling without thread support. */ #ifndef TCL_THREADS #undef Tcl_MutexLock #define Tcl_MutexLock(mutexPtr) #undef Tcl_MutexUnlock #define Tcl_MutexUnlock(mutexPtr) #undef Tcl_MutexFinalize #define Tcl_MutexFinalize(mutexPtr) #undef Tcl_ConditionNotify #define Tcl_ConditionNotify(condPtr) #undef Tcl_ConditionWait #define Tcl_ConditionWait(condPtr, mutexPtr, timePtr) #undef Tcl_ConditionFinalize #define Tcl_ConditionFinalize(condPtr) #endif /* TCL_THREADS */ /* *---------------------------------------------------------------------------- * Deprecated Tcl functions: */ #ifndef TCL_NO_DEPRECATED /* * These function have been renamed. The old names are deprecated, but we * define these macros for backwards compatibilty. */ # define Tcl_Ckalloc Tcl_Alloc # define Tcl_Ckfree Tcl_Free # define Tcl_Ckrealloc Tcl_Realloc # define Tcl_Return Tcl_SetResult # define Tcl_TildeSubst Tcl_TranslateFileName # define panic Tcl_Panic # define panicVA Tcl_PanicVA #endif /* !TCL_NO_DEPRECATED */ /* *---------------------------------------------------------------------------- * Convenience declaration of Tcl_AppInit for backwards compatibility. This * function is not *implemented* by the tcl library, so the storage class is * neither DLLEXPORT nor DLLIMPORT. */ extern Tcl_AppInitProc Tcl_AppInit; #endif /* RC_INVOKED */ /* * end block for C++ */ #ifdef __cplusplus } #endif #endif /* _TCL */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/tcl/tclDecls.h0000644000175100017510000051332115106067236020630 0ustar00runnerrunner/* * tclDecls.h -- * * Declarations of functions in the platform independent public Tcl API. * * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLDECLS #define _TCLDECLS #undef TCL_STORAGE_CLASS #ifdef BUILD_tcl # define TCL_STORAGE_CLASS DLLEXPORT #else # ifdef USE_TCL_STUBS # define TCL_STORAGE_CLASS # else # define TCL_STORAGE_CLASS DLLIMPORT # endif #endif /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the generic/tcl.decls script. */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ /* 0 */ EXTERN int Tcl_PkgProvideEx(Tcl_Interp *interp, const char *name, const char *version, const void *clientData); /* 1 */ EXTERN CONST84_RETURN char * Tcl_PkgRequireEx(Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 2 */ EXTERN TCL_NORETURN void Tcl_Panic(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 3 */ EXTERN char * Tcl_Alloc(unsigned int size); /* 4 */ EXTERN void Tcl_Free(char *ptr); /* 5 */ EXTERN char * Tcl_Realloc(char *ptr, unsigned int size); /* 6 */ EXTERN char * Tcl_DbCkalloc(unsigned int size, const char *file, int line); /* 7 */ EXTERN void Tcl_DbCkfree(char *ptr, const char *file, int line); /* 8 */ EXTERN char * Tcl_DbCkrealloc(char *ptr, unsigned int size, const char *file, int line); #if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ /* 9 */ EXTERN void Tcl_CreateFileHandler(int fd, int mask, Tcl_FileProc *proc, ClientData clientData); #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 9 */ EXTERN void Tcl_CreateFileHandler(int fd, int mask, Tcl_FileProc *proc, ClientData clientData); #endif /* MACOSX */ #if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ /* 10 */ EXTERN void Tcl_DeleteFileHandler(int fd); #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 10 */ EXTERN void Tcl_DeleteFileHandler(int fd); #endif /* MACOSX */ /* 11 */ EXTERN void Tcl_SetTimer(const Tcl_Time *timePtr); /* 12 */ EXTERN void Tcl_Sleep(int ms); /* 13 */ EXTERN int Tcl_WaitForEvent(const Tcl_Time *timePtr); /* 14 */ EXTERN int Tcl_AppendAllObjTypes(Tcl_Interp *interp, Tcl_Obj *objPtr); /* 15 */ EXTERN void Tcl_AppendStringsToObj(Tcl_Obj *objPtr, ...); /* 16 */ EXTERN void Tcl_AppendToObj(Tcl_Obj *objPtr, const char *bytes, int length); /* 17 */ EXTERN Tcl_Obj * Tcl_ConcatObj(int objc, Tcl_Obj *const objv[]); /* 18 */ EXTERN int Tcl_ConvertToType(Tcl_Interp *interp, Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 19 */ EXTERN void Tcl_DbDecrRefCount(Tcl_Obj *objPtr, const char *file, int line); /* 20 */ EXTERN void Tcl_DbIncrRefCount(Tcl_Obj *objPtr, const char *file, int line); /* 21 */ EXTERN int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file, int line); /* 22 */ EXTERN Tcl_Obj * Tcl_DbNewBooleanObj(int boolValue, const char *file, int line); /* 23 */ EXTERN Tcl_Obj * Tcl_DbNewByteArrayObj(const unsigned char *bytes, int length, const char *file, int line); /* 24 */ EXTERN Tcl_Obj * Tcl_DbNewDoubleObj(double doubleValue, const char *file, int line); /* 25 */ EXTERN Tcl_Obj * Tcl_DbNewListObj(int objc, Tcl_Obj *const *objv, const char *file, int line); /* 26 */ EXTERN Tcl_Obj * Tcl_DbNewLongObj(long longValue, const char *file, int line); /* 27 */ EXTERN Tcl_Obj * Tcl_DbNewObj(const char *file, int line); /* 28 */ EXTERN Tcl_Obj * Tcl_DbNewStringObj(const char *bytes, int length, const char *file, int line); /* 29 */ EXTERN Tcl_Obj * Tcl_DuplicateObj(Tcl_Obj *objPtr); /* 30 */ EXTERN void TclFreeObj(Tcl_Obj *objPtr); /* 31 */ EXTERN int Tcl_GetBoolean(Tcl_Interp *interp, const char *src, int *boolPtr); /* 32 */ EXTERN int Tcl_GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *boolPtr); /* 33 */ EXTERN unsigned char * Tcl_GetByteArrayFromObj(Tcl_Obj *objPtr, int *lengthPtr); /* 34 */ EXTERN int Tcl_GetDouble(Tcl_Interp *interp, const char *src, double *doublePtr); /* 35 */ EXTERN int Tcl_GetDoubleFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* 36 */ EXTERN int Tcl_GetIndexFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, CONST84 char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 37 */ EXTERN int Tcl_GetInt(Tcl_Interp *interp, const char *src, int *intPtr); /* 38 */ EXTERN int Tcl_GetIntFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 39 */ EXTERN int Tcl_GetLongFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr); /* 40 */ EXTERN CONST86 Tcl_ObjType * Tcl_GetObjType(const char *typeName); /* 41 */ EXTERN char * Tcl_GetStringFromObj(Tcl_Obj *objPtr, int *lengthPtr); /* 42 */ EXTERN void Tcl_InvalidateStringRep(Tcl_Obj *objPtr); /* 43 */ EXTERN int Tcl_ListObjAppendList(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); /* 44 */ EXTERN int Tcl_ListObjAppendElement(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr); /* 45 */ EXTERN int Tcl_ListObjGetElements(Tcl_Interp *interp, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr); /* 46 */ EXTERN int Tcl_ListObjIndex(Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr); /* 47 */ EXTERN int Tcl_ListObjLength(Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr); /* 48 */ EXTERN int Tcl_ListObjReplace(Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *const objv[]); /* 49 */ EXTERN Tcl_Obj * Tcl_NewBooleanObj(int boolValue); /* 50 */ EXTERN Tcl_Obj * Tcl_NewByteArrayObj(const unsigned char *bytes, int length); /* 51 */ EXTERN Tcl_Obj * Tcl_NewDoubleObj(double doubleValue); /* 52 */ EXTERN Tcl_Obj * Tcl_NewIntObj(int intValue); /* 53 */ EXTERN Tcl_Obj * Tcl_NewListObj(int objc, Tcl_Obj *const objv[]); /* 54 */ EXTERN Tcl_Obj * Tcl_NewLongObj(long longValue); /* 55 */ EXTERN Tcl_Obj * Tcl_NewObj(void); /* 56 */ EXTERN Tcl_Obj * Tcl_NewStringObj(const char *bytes, int length); /* 57 */ EXTERN void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue); /* 58 */ EXTERN unsigned char * Tcl_SetByteArrayLength(Tcl_Obj *objPtr, int length); /* 59 */ EXTERN void Tcl_SetByteArrayObj(Tcl_Obj *objPtr, const unsigned char *bytes, int length); /* 60 */ EXTERN void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue); /* 61 */ EXTERN void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue); /* 62 */ EXTERN void Tcl_SetListObj(Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[]); /* 63 */ EXTERN void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue); /* 64 */ EXTERN void Tcl_SetObjLength(Tcl_Obj *objPtr, int length); /* 65 */ EXTERN void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes, int length); /* 66 */ EXTERN void Tcl_AddErrorInfo(Tcl_Interp *interp, const char *message); /* 67 */ EXTERN void Tcl_AddObjErrorInfo(Tcl_Interp *interp, const char *message, int length); /* 68 */ EXTERN void Tcl_AllowExceptions(Tcl_Interp *interp); /* 69 */ EXTERN void Tcl_AppendElement(Tcl_Interp *interp, const char *element); /* 70 */ EXTERN void Tcl_AppendResult(Tcl_Interp *interp, ...); /* 71 */ EXTERN Tcl_AsyncHandler Tcl_AsyncCreate(Tcl_AsyncProc *proc, ClientData clientData); /* 72 */ EXTERN void Tcl_AsyncDelete(Tcl_AsyncHandler async); /* 73 */ EXTERN int Tcl_AsyncInvoke(Tcl_Interp *interp, int code); /* 74 */ EXTERN void Tcl_AsyncMark(Tcl_AsyncHandler async); /* 75 */ EXTERN int Tcl_AsyncReady(void); /* 76 */ EXTERN void Tcl_BackgroundError(Tcl_Interp *interp); /* 77 */ EXTERN char Tcl_Backslash(const char *src, int *readPtr); /* 78 */ EXTERN int Tcl_BadChannelOption(Tcl_Interp *interp, const char *optionName, const char *optionList); /* 79 */ EXTERN void Tcl_CallWhenDeleted(Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 80 */ EXTERN void Tcl_CancelIdleCall(Tcl_IdleProc *idleProc, ClientData clientData); /* 81 */ EXTERN int Tcl_Close(Tcl_Interp *interp, Tcl_Channel chan); /* 82 */ EXTERN int Tcl_CommandComplete(const char *cmd); /* 83 */ EXTERN char * Tcl_Concat(int argc, CONST84 char *const *argv); /* 84 */ EXTERN int Tcl_ConvertElement(const char *src, char *dst, int flags); /* 85 */ EXTERN int Tcl_ConvertCountedElement(const char *src, int length, char *dst, int flags); /* 86 */ EXTERN int Tcl_CreateAlias(Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int argc, CONST84 char *const *argv); /* 87 */ EXTERN int Tcl_CreateAliasObj(Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int objc, Tcl_Obj *const objv[]); /* 88 */ EXTERN Tcl_Channel Tcl_CreateChannel(const Tcl_ChannelType *typePtr, const char *chanName, ClientData instanceData, int mask); /* 89 */ EXTERN void Tcl_CreateChannelHandler(Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, ClientData clientData); /* 90 */ EXTERN void Tcl_CreateCloseHandler(Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 91 */ EXTERN Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 92 */ EXTERN void Tcl_CreateEventSource(Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 93 */ EXTERN void Tcl_CreateExitHandler(Tcl_ExitProc *proc, ClientData clientData); /* 94 */ EXTERN Tcl_Interp * Tcl_CreateInterp(void); /* 95 */ EXTERN void Tcl_CreateMathFunc(Tcl_Interp *interp, const char *name, int numArgs, Tcl_ValueType *argTypes, Tcl_MathProc *proc, ClientData clientData); /* 96 */ EXTERN Tcl_Command Tcl_CreateObjCommand(Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 97 */ EXTERN Tcl_Interp * Tcl_CreateSlave(Tcl_Interp *interp, const char *slaveName, int isSafe); /* 98 */ EXTERN Tcl_TimerToken Tcl_CreateTimerHandler(int milliseconds, Tcl_TimerProc *proc, ClientData clientData); /* 99 */ EXTERN Tcl_Trace Tcl_CreateTrace(Tcl_Interp *interp, int level, Tcl_CmdTraceProc *proc, ClientData clientData); /* 100 */ EXTERN void Tcl_DeleteAssocData(Tcl_Interp *interp, const char *name); /* 101 */ EXTERN void Tcl_DeleteChannelHandler(Tcl_Channel chan, Tcl_ChannelProc *proc, ClientData clientData); /* 102 */ EXTERN void Tcl_DeleteCloseHandler(Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 103 */ EXTERN int Tcl_DeleteCommand(Tcl_Interp *interp, const char *cmdName); /* 104 */ EXTERN int Tcl_DeleteCommandFromToken(Tcl_Interp *interp, Tcl_Command command); /* 105 */ EXTERN void Tcl_DeleteEvents(Tcl_EventDeleteProc *proc, ClientData clientData); /* 106 */ EXTERN void Tcl_DeleteEventSource(Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 107 */ EXTERN void Tcl_DeleteExitHandler(Tcl_ExitProc *proc, ClientData clientData); /* 108 */ EXTERN void Tcl_DeleteHashEntry(Tcl_HashEntry *entryPtr); /* 109 */ EXTERN void Tcl_DeleteHashTable(Tcl_HashTable *tablePtr); /* 110 */ EXTERN void Tcl_DeleteInterp(Tcl_Interp *interp); /* 111 */ EXTERN void Tcl_DetachPids(int numPids, Tcl_Pid *pidPtr); /* 112 */ EXTERN void Tcl_DeleteTimerHandler(Tcl_TimerToken token); /* 113 */ EXTERN void Tcl_DeleteTrace(Tcl_Interp *interp, Tcl_Trace trace); /* 114 */ EXTERN void Tcl_DontCallWhenDeleted(Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 115 */ EXTERN int Tcl_DoOneEvent(int flags); /* 116 */ EXTERN void Tcl_DoWhenIdle(Tcl_IdleProc *proc, ClientData clientData); /* 117 */ EXTERN char * Tcl_DStringAppend(Tcl_DString *dsPtr, const char *bytes, int length); /* 118 */ EXTERN char * Tcl_DStringAppendElement(Tcl_DString *dsPtr, const char *element); /* 119 */ EXTERN void Tcl_DStringEndSublist(Tcl_DString *dsPtr); /* 120 */ EXTERN void Tcl_DStringFree(Tcl_DString *dsPtr); /* 121 */ EXTERN void Tcl_DStringGetResult(Tcl_Interp *interp, Tcl_DString *dsPtr); /* 122 */ EXTERN void Tcl_DStringInit(Tcl_DString *dsPtr); /* 123 */ EXTERN void Tcl_DStringResult(Tcl_Interp *interp, Tcl_DString *dsPtr); /* 124 */ EXTERN void Tcl_DStringSetLength(Tcl_DString *dsPtr, int length); /* 125 */ EXTERN void Tcl_DStringStartSublist(Tcl_DString *dsPtr); /* 126 */ EXTERN int Tcl_Eof(Tcl_Channel chan); /* 127 */ EXTERN CONST84_RETURN char * Tcl_ErrnoId(void); /* 128 */ EXTERN CONST84_RETURN char * Tcl_ErrnoMsg(int err); /* 129 */ EXTERN int Tcl_Eval(Tcl_Interp *interp, const char *script); /* 130 */ EXTERN int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName); /* 131 */ EXTERN int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr); /* 132 */ EXTERN void Tcl_EventuallyFree(ClientData clientData, Tcl_FreeProc *freeProc); /* 133 */ EXTERN TCL_NORETURN void Tcl_Exit(int status); /* 134 */ EXTERN int Tcl_ExposeCommand(Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName); /* 135 */ EXTERN int Tcl_ExprBoolean(Tcl_Interp *interp, const char *expr, int *ptr); /* 136 */ EXTERN int Tcl_ExprBooleanObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr); /* 137 */ EXTERN int Tcl_ExprDouble(Tcl_Interp *interp, const char *expr, double *ptr); /* 138 */ EXTERN int Tcl_ExprDoubleObj(Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr); /* 139 */ EXTERN int Tcl_ExprLong(Tcl_Interp *interp, const char *expr, long *ptr); /* 140 */ EXTERN int Tcl_ExprLongObj(Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr); /* 141 */ EXTERN int Tcl_ExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr); /* 142 */ EXTERN int Tcl_ExprString(Tcl_Interp *interp, const char *expr); /* 143 */ EXTERN void Tcl_Finalize(void); /* 144 */ EXTERN void Tcl_FindExecutable(const char *argv0); /* 145 */ EXTERN Tcl_HashEntry * Tcl_FirstHashEntry(Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr); /* 146 */ EXTERN int Tcl_Flush(Tcl_Channel chan); /* 147 */ EXTERN void Tcl_FreeResult(Tcl_Interp *interp); /* 148 */ EXTERN int Tcl_GetAlias(Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *argcPtr, CONST84 char ***argvPtr); /* 149 */ EXTERN int Tcl_GetAliasObj(Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv); /* 150 */ EXTERN ClientData Tcl_GetAssocData(Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc **procPtr); /* 151 */ EXTERN Tcl_Channel Tcl_GetChannel(Tcl_Interp *interp, const char *chanName, int *modePtr); /* 152 */ EXTERN int Tcl_GetChannelBufferSize(Tcl_Channel chan); /* 153 */ EXTERN int Tcl_GetChannelHandle(Tcl_Channel chan, int direction, ClientData *handlePtr); /* 154 */ EXTERN ClientData Tcl_GetChannelInstanceData(Tcl_Channel chan); /* 155 */ EXTERN int Tcl_GetChannelMode(Tcl_Channel chan); /* 156 */ EXTERN CONST84_RETURN char * Tcl_GetChannelName(Tcl_Channel chan); /* 157 */ EXTERN int Tcl_GetChannelOption(Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, Tcl_DString *dsPtr); /* 158 */ EXTERN CONST86 Tcl_ChannelType * Tcl_GetChannelType(Tcl_Channel chan); /* 159 */ EXTERN int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); /* 160 */ EXTERN CONST84_RETURN char * Tcl_GetCommandName(Tcl_Interp *interp, Tcl_Command command); /* 161 */ EXTERN int Tcl_GetErrno(void); /* 162 */ EXTERN CONST84_RETURN char * Tcl_GetHostName(void); /* 163 */ EXTERN int Tcl_GetInterpPath(Tcl_Interp *askInterp, Tcl_Interp *slaveInterp); /* 164 */ EXTERN Tcl_Interp * Tcl_GetMaster(Tcl_Interp *interp); /* 165 */ EXTERN const char * Tcl_GetNameOfExecutable(void); /* 166 */ EXTERN Tcl_Obj * Tcl_GetObjResult(Tcl_Interp *interp); #if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ /* 167 */ EXTERN int Tcl_GetOpenFile(Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 167 */ EXTERN int Tcl_GetOpenFile(Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); #endif /* MACOSX */ /* 168 */ EXTERN Tcl_PathType Tcl_GetPathType(const char *path); /* 169 */ EXTERN int Tcl_Gets(Tcl_Channel chan, Tcl_DString *dsPtr); /* 170 */ EXTERN int Tcl_GetsObj(Tcl_Channel chan, Tcl_Obj *objPtr); /* 171 */ EXTERN int Tcl_GetServiceMode(void); /* 172 */ EXTERN Tcl_Interp * Tcl_GetSlave(Tcl_Interp *interp, const char *slaveName); /* 173 */ EXTERN Tcl_Channel Tcl_GetStdChannel(int type); /* 174 */ EXTERN CONST84_RETURN char * Tcl_GetStringResult(Tcl_Interp *interp); /* 175 */ EXTERN CONST84_RETURN char * Tcl_GetVar(Tcl_Interp *interp, const char *varName, int flags); /* 176 */ EXTERN CONST84_RETURN char * Tcl_GetVar2(Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 177 */ EXTERN int Tcl_GlobalEval(Tcl_Interp *interp, const char *command); /* 178 */ EXTERN int Tcl_GlobalEvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr); /* 179 */ EXTERN int Tcl_HideCommand(Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken); /* 180 */ EXTERN int Tcl_Init(Tcl_Interp *interp); /* 181 */ EXTERN void Tcl_InitHashTable(Tcl_HashTable *tablePtr, int keyType); /* 182 */ EXTERN int Tcl_InputBlocked(Tcl_Channel chan); /* 183 */ EXTERN int Tcl_InputBuffered(Tcl_Channel chan); /* 184 */ EXTERN int Tcl_InterpDeleted(Tcl_Interp *interp); /* 185 */ EXTERN int Tcl_IsSafe(Tcl_Interp *interp); /* 186 */ EXTERN char * Tcl_JoinPath(int argc, CONST84 char *const *argv, Tcl_DString *resultPtr); /* 187 */ EXTERN int Tcl_LinkVar(Tcl_Interp *interp, const char *varName, char *addr, int type); /* Slot 188 is reserved */ /* 189 */ EXTERN Tcl_Channel Tcl_MakeFileChannel(ClientData handle, int mode); /* 190 */ EXTERN int Tcl_MakeSafe(Tcl_Interp *interp); /* 191 */ EXTERN Tcl_Channel Tcl_MakeTcpClientChannel(ClientData tcpSocket); /* 192 */ EXTERN char * Tcl_Merge(int argc, CONST84 char *const *argv); /* 193 */ EXTERN Tcl_HashEntry * Tcl_NextHashEntry(Tcl_HashSearch *searchPtr); /* 194 */ EXTERN void Tcl_NotifyChannel(Tcl_Channel channel, int mask); /* 195 */ EXTERN Tcl_Obj * Tcl_ObjGetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags); /* 196 */ EXTERN Tcl_Obj * Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); /* 197 */ EXTERN Tcl_Channel Tcl_OpenCommandChannel(Tcl_Interp *interp, int argc, CONST84 char **argv, int flags); /* 198 */ EXTERN Tcl_Channel Tcl_OpenFileChannel(Tcl_Interp *interp, const char *fileName, const char *modeString, int permissions); /* 199 */ EXTERN Tcl_Channel Tcl_OpenTcpClient(Tcl_Interp *interp, int port, const char *address, const char *myaddr, int myport, int async); /* 200 */ EXTERN Tcl_Channel Tcl_OpenTcpServer(Tcl_Interp *interp, int port, const char *host, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 201 */ EXTERN void Tcl_Preserve(ClientData data); /* 202 */ EXTERN void Tcl_PrintDouble(Tcl_Interp *interp, double value, char *dst); /* 203 */ EXTERN int Tcl_PutEnv(const char *assignment); /* 204 */ EXTERN CONST84_RETURN char * Tcl_PosixError(Tcl_Interp *interp); /* 205 */ EXTERN void Tcl_QueueEvent(Tcl_Event *evPtr, Tcl_QueuePosition position); /* 206 */ EXTERN int Tcl_Read(Tcl_Channel chan, char *bufPtr, int toRead); /* 207 */ EXTERN void Tcl_ReapDetachedProcs(void); /* 208 */ EXTERN int Tcl_RecordAndEval(Tcl_Interp *interp, const char *cmd, int flags); /* 209 */ EXTERN int Tcl_RecordAndEvalObj(Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags); /* 210 */ EXTERN void Tcl_RegisterChannel(Tcl_Interp *interp, Tcl_Channel chan); /* 211 */ EXTERN void Tcl_RegisterObjType(const Tcl_ObjType *typePtr); /* 212 */ EXTERN Tcl_RegExp Tcl_RegExpCompile(Tcl_Interp *interp, const char *pattern); /* 213 */ EXTERN int Tcl_RegExpExec(Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start); /* 214 */ EXTERN int Tcl_RegExpMatch(Tcl_Interp *interp, const char *text, const char *pattern); /* 215 */ EXTERN void Tcl_RegExpRange(Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr); /* 216 */ EXTERN void Tcl_Release(ClientData clientData); /* 217 */ EXTERN void Tcl_ResetResult(Tcl_Interp *interp); /* 218 */ EXTERN int Tcl_ScanElement(const char *src, int *flagPtr); /* 219 */ EXTERN int Tcl_ScanCountedElement(const char *src, int length, int *flagPtr); /* 220 */ EXTERN int Tcl_SeekOld(Tcl_Channel chan, int offset, int mode); /* 221 */ EXTERN int Tcl_ServiceAll(void); /* 222 */ EXTERN int Tcl_ServiceEvent(int flags); /* 223 */ EXTERN void Tcl_SetAssocData(Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 224 */ EXTERN void Tcl_SetChannelBufferSize(Tcl_Channel chan, int sz); /* 225 */ EXTERN int Tcl_SetChannelOption(Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue); /* 226 */ EXTERN int Tcl_SetCommandInfo(Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr); /* 227 */ EXTERN void Tcl_SetErrno(int err); /* 228 */ EXTERN void Tcl_SetErrorCode(Tcl_Interp *interp, ...); /* 229 */ EXTERN void Tcl_SetMaxBlockTime(const Tcl_Time *timePtr); /* 230 */ EXTERN void Tcl_SetPanicProc( TCL_NORETURN1 Tcl_PanicProc *panicProc); /* 231 */ EXTERN int Tcl_SetRecursionLimit(Tcl_Interp *interp, int depth); /* 232 */ EXTERN void Tcl_SetResult(Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc); /* 233 */ EXTERN int Tcl_SetServiceMode(int mode); /* 234 */ EXTERN void Tcl_SetObjErrorCode(Tcl_Interp *interp, Tcl_Obj *errorObjPtr); /* 235 */ EXTERN void Tcl_SetObjResult(Tcl_Interp *interp, Tcl_Obj *resultObjPtr); /* 236 */ EXTERN void Tcl_SetStdChannel(Tcl_Channel channel, int type); /* 237 */ EXTERN CONST84_RETURN char * Tcl_SetVar(Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 238 */ EXTERN CONST84_RETURN char * Tcl_SetVar2(Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags); /* 239 */ EXTERN CONST84_RETURN char * Tcl_SignalId(int sig); /* 240 */ EXTERN CONST84_RETURN char * Tcl_SignalMsg(int sig); /* 241 */ EXTERN void Tcl_SourceRCFile(Tcl_Interp *interp); /* 242 */ EXTERN int Tcl_SplitList(Tcl_Interp *interp, const char *listStr, int *argcPtr, CONST84 char ***argvPtr); /* 243 */ EXTERN void Tcl_SplitPath(const char *path, int *argcPtr, CONST84 char ***argvPtr); /* 244 */ EXTERN void Tcl_StaticPackage(Tcl_Interp *interp, const char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc); /* 245 */ EXTERN int Tcl_StringMatch(const char *str, const char *pattern); /* 246 */ EXTERN int Tcl_TellOld(Tcl_Channel chan); /* 247 */ EXTERN int Tcl_TraceVar(Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 248 */ EXTERN int Tcl_TraceVar2(Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 249 */ EXTERN char * Tcl_TranslateFileName(Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr); /* 250 */ EXTERN int Tcl_Ungets(Tcl_Channel chan, const char *str, int len, int atHead); /* 251 */ EXTERN void Tcl_UnlinkVar(Tcl_Interp *interp, const char *varName); /* 252 */ EXTERN int Tcl_UnregisterChannel(Tcl_Interp *interp, Tcl_Channel chan); /* 253 */ EXTERN int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName, int flags); /* 254 */ EXTERN int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 255 */ EXTERN void Tcl_UntraceVar(Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 256 */ EXTERN void Tcl_UntraceVar2(Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 257 */ EXTERN void Tcl_UpdateLinkedVar(Tcl_Interp *interp, const char *varName); /* 258 */ EXTERN int Tcl_UpVar(Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 259 */ EXTERN int Tcl_UpVar2(Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags); /* 260 */ EXTERN int Tcl_VarEval(Tcl_Interp *interp, ...); /* 261 */ EXTERN ClientData Tcl_VarTraceInfo(Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 262 */ EXTERN ClientData Tcl_VarTraceInfo2(Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 263 */ EXTERN int Tcl_Write(Tcl_Channel chan, const char *s, int slen); /* 264 */ EXTERN void Tcl_WrongNumArgs(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *message); /* 265 */ EXTERN int Tcl_DumpActiveMemory(const char *fileName); /* 266 */ EXTERN void Tcl_ValidateAllMemory(const char *file, int line); /* 267 */ EXTERN void Tcl_AppendResultVA(Tcl_Interp *interp, va_list argList); /* 268 */ EXTERN void Tcl_AppendStringsToObjVA(Tcl_Obj *objPtr, va_list argList); /* 269 */ EXTERN char * Tcl_HashStats(Tcl_HashTable *tablePtr); /* 270 */ EXTERN CONST84_RETURN char * Tcl_ParseVar(Tcl_Interp *interp, const char *start, CONST84 char **termPtr); /* 271 */ EXTERN CONST84_RETURN char * Tcl_PkgPresent(Tcl_Interp *interp, const char *name, const char *version, int exact); /* 272 */ EXTERN CONST84_RETURN char * Tcl_PkgPresentEx(Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 273 */ EXTERN int Tcl_PkgProvide(Tcl_Interp *interp, const char *name, const char *version); /* 274 */ EXTERN CONST84_RETURN char * Tcl_PkgRequire(Tcl_Interp *interp, const char *name, const char *version, int exact); /* 275 */ EXTERN void Tcl_SetErrorCodeVA(Tcl_Interp *interp, va_list argList); /* 276 */ EXTERN int Tcl_VarEvalVA(Tcl_Interp *interp, va_list argList); /* 277 */ EXTERN Tcl_Pid Tcl_WaitPid(Tcl_Pid pid, int *statPtr, int options); /* 278 */ EXTERN TCL_NORETURN void Tcl_PanicVA(const char *format, va_list argList); /* 279 */ EXTERN void Tcl_GetVersion(int *major, int *minor, int *patchLevel, int *type); /* 280 */ EXTERN void Tcl_InitMemory(Tcl_Interp *interp); /* 281 */ EXTERN Tcl_Channel Tcl_StackChannel(Tcl_Interp *interp, const Tcl_ChannelType *typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan); /* 282 */ EXTERN int Tcl_UnstackChannel(Tcl_Interp *interp, Tcl_Channel chan); /* 283 */ EXTERN Tcl_Channel Tcl_GetStackedChannel(Tcl_Channel chan); /* 284 */ EXTERN void Tcl_SetMainLoop(Tcl_MainLoopProc *proc); /* Slot 285 is reserved */ /* 286 */ EXTERN void Tcl_AppendObjToObj(Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr); /* 287 */ EXTERN Tcl_Encoding Tcl_CreateEncoding(const Tcl_EncodingType *typePtr); /* 288 */ EXTERN void Tcl_CreateThreadExitHandler(Tcl_ExitProc *proc, ClientData clientData); /* 289 */ EXTERN void Tcl_DeleteThreadExitHandler(Tcl_ExitProc *proc, ClientData clientData); /* 290 */ EXTERN void Tcl_DiscardResult(Tcl_SavedResult *statePtr); /* 291 */ EXTERN int Tcl_EvalEx(Tcl_Interp *interp, const char *script, int numBytes, int flags); /* 292 */ EXTERN int Tcl_EvalObjv(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 293 */ EXTERN int Tcl_EvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 294 */ EXTERN void Tcl_ExitThread(int status); /* 295 */ EXTERN int Tcl_ExternalToUtf(Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 296 */ EXTERN char * Tcl_ExternalToUtfDString(Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 297 */ EXTERN void Tcl_FinalizeThread(void); /* 298 */ EXTERN void Tcl_FinalizeNotifier(ClientData clientData); /* 299 */ EXTERN void Tcl_FreeEncoding(Tcl_Encoding encoding); /* 300 */ EXTERN Tcl_ThreadId Tcl_GetCurrentThread(void); /* 301 */ EXTERN Tcl_Encoding Tcl_GetEncoding(Tcl_Interp *interp, const char *name); /* 302 */ EXTERN CONST84_RETURN char * Tcl_GetEncodingName(Tcl_Encoding encoding); /* 303 */ EXTERN void Tcl_GetEncodingNames(Tcl_Interp *interp); /* 304 */ EXTERN int Tcl_GetIndexFromObjStruct(Tcl_Interp *interp, Tcl_Obj *objPtr, const void *tablePtr, int offset, const char *msg, int flags, int *indexPtr); /* 305 */ EXTERN void * Tcl_GetThreadData(Tcl_ThreadDataKey *keyPtr, int size); /* 306 */ EXTERN Tcl_Obj * Tcl_GetVar2Ex(Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 307 */ EXTERN ClientData Tcl_InitNotifier(void); /* 308 */ EXTERN void Tcl_MutexLock(Tcl_Mutex *mutexPtr); /* 309 */ EXTERN void Tcl_MutexUnlock(Tcl_Mutex *mutexPtr); /* 310 */ EXTERN void Tcl_ConditionNotify(Tcl_Condition *condPtr); /* 311 */ EXTERN void Tcl_ConditionWait(Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); /* 312 */ EXTERN int Tcl_NumUtfChars(const char *src, int length); /* 313 */ EXTERN int Tcl_ReadChars(Tcl_Channel channel, Tcl_Obj *objPtr, int charsToRead, int appendFlag); /* 314 */ EXTERN void Tcl_RestoreResult(Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 315 */ EXTERN void Tcl_SaveResult(Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 316 */ EXTERN int Tcl_SetSystemEncoding(Tcl_Interp *interp, const char *name); /* 317 */ EXTERN Tcl_Obj * Tcl_SetVar2Ex(Tcl_Interp *interp, const char *part1, const char *part2, Tcl_Obj *newValuePtr, int flags); /* 318 */ EXTERN void Tcl_ThreadAlert(Tcl_ThreadId threadId); /* 319 */ EXTERN void Tcl_ThreadQueueEvent(Tcl_ThreadId threadId, Tcl_Event *evPtr, Tcl_QueuePosition position); /* 320 */ EXTERN Tcl_UniChar Tcl_UniCharAtIndex(const char *src, int index); /* 321 */ EXTERN Tcl_UniChar Tcl_UniCharToLower(int ch); /* 322 */ EXTERN Tcl_UniChar Tcl_UniCharToTitle(int ch); /* 323 */ EXTERN Tcl_UniChar Tcl_UniCharToUpper(int ch); /* 324 */ EXTERN int Tcl_UniCharToUtf(int ch, char *buf); /* 325 */ EXTERN CONST84_RETURN char * Tcl_UtfAtIndex(const char *src, int index); /* 326 */ EXTERN int Tcl_UtfCharComplete(const char *src, int length); /* 327 */ EXTERN int Tcl_UtfBackslash(const char *src, int *readPtr, char *dst); /* 328 */ EXTERN CONST84_RETURN char * Tcl_UtfFindFirst(const char *src, int ch); /* 329 */ EXTERN CONST84_RETURN char * Tcl_UtfFindLast(const char *src, int ch); /* 330 */ EXTERN CONST84_RETURN char * Tcl_UtfNext(const char *src); /* 331 */ EXTERN CONST84_RETURN char * Tcl_UtfPrev(const char *src, const char *start); /* 332 */ EXTERN int Tcl_UtfToExternal(Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 333 */ EXTERN char * Tcl_UtfToExternalDString(Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 334 */ EXTERN int Tcl_UtfToLower(char *src); /* 335 */ EXTERN int Tcl_UtfToTitle(char *src); /* 336 */ EXTERN int Tcl_UtfToUniChar(const char *src, Tcl_UniChar *chPtr); /* 337 */ EXTERN int Tcl_UtfToUpper(char *src); /* 338 */ EXTERN int Tcl_WriteChars(Tcl_Channel chan, const char *src, int srcLen); /* 339 */ EXTERN int Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr); /* 340 */ EXTERN char * Tcl_GetString(Tcl_Obj *objPtr); /* 341 */ EXTERN CONST84_RETURN char * Tcl_GetDefaultEncodingDir(void); /* 342 */ EXTERN void Tcl_SetDefaultEncodingDir(const char *path); /* 343 */ EXTERN void Tcl_AlertNotifier(ClientData clientData); /* 344 */ EXTERN void Tcl_ServiceModeHook(int mode); /* 345 */ EXTERN int Tcl_UniCharIsAlnum(int ch); /* 346 */ EXTERN int Tcl_UniCharIsAlpha(int ch); /* 347 */ EXTERN int Tcl_UniCharIsDigit(int ch); /* 348 */ EXTERN int Tcl_UniCharIsLower(int ch); /* 349 */ EXTERN int Tcl_UniCharIsSpace(int ch); /* 350 */ EXTERN int Tcl_UniCharIsUpper(int ch); /* 351 */ EXTERN int Tcl_UniCharIsWordChar(int ch); /* 352 */ EXTERN int Tcl_UniCharLen(const Tcl_UniChar *uniStr); /* 353 */ EXTERN int Tcl_UniCharNcmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 354 */ EXTERN char * Tcl_UniCharToUtfDString(const Tcl_UniChar *uniStr, int uniLength, Tcl_DString *dsPtr); /* 355 */ EXTERN Tcl_UniChar * Tcl_UtfToUniCharDString(const char *src, int length, Tcl_DString *dsPtr); /* 356 */ EXTERN Tcl_RegExp Tcl_GetRegExpFromObj(Tcl_Interp *interp, Tcl_Obj *patObj, int flags); /* 357 */ EXTERN Tcl_Obj * Tcl_EvalTokens(Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 358 */ EXTERN void Tcl_FreeParse(Tcl_Parse *parsePtr); /* 359 */ EXTERN void Tcl_LogCommandInfo(Tcl_Interp *interp, const char *script, const char *command, int length); /* 360 */ EXTERN int Tcl_ParseBraces(Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 361 */ EXTERN int Tcl_ParseCommand(Tcl_Interp *interp, const char *start, int numBytes, int nested, Tcl_Parse *parsePtr); /* 362 */ EXTERN int Tcl_ParseExpr(Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr); /* 363 */ EXTERN int Tcl_ParseQuotedString(Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 364 */ EXTERN int Tcl_ParseVarName(Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append); /* 365 */ EXTERN char * Tcl_GetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr); /* 366 */ EXTERN int Tcl_Chdir(const char *dirName); /* 367 */ EXTERN int Tcl_Access(const char *path, int mode); /* 368 */ EXTERN int Tcl_Stat(const char *path, struct stat *bufPtr); /* 369 */ EXTERN int Tcl_UtfNcmp(const char *s1, const char *s2, unsigned long n); /* 370 */ EXTERN int Tcl_UtfNcasecmp(const char *s1, const char *s2, unsigned long n); /* 371 */ EXTERN int Tcl_StringCaseMatch(const char *str, const char *pattern, int nocase); /* 372 */ EXTERN int Tcl_UniCharIsControl(int ch); /* 373 */ EXTERN int Tcl_UniCharIsGraph(int ch); /* 374 */ EXTERN int Tcl_UniCharIsPrint(int ch); /* 375 */ EXTERN int Tcl_UniCharIsPunct(int ch); /* 376 */ EXTERN int Tcl_RegExpExecObj(Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, int offset, int nmatches, int flags); /* 377 */ EXTERN void Tcl_RegExpGetInfo(Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr); /* 378 */ EXTERN Tcl_Obj * Tcl_NewUnicodeObj(const Tcl_UniChar *unicode, int numChars); /* 379 */ EXTERN void Tcl_SetUnicodeObj(Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int numChars); /* 380 */ EXTERN int Tcl_GetCharLength(Tcl_Obj *objPtr); /* 381 */ EXTERN Tcl_UniChar Tcl_GetUniChar(Tcl_Obj *objPtr, int index); /* 382 */ EXTERN Tcl_UniChar * Tcl_GetUnicode(Tcl_Obj *objPtr); /* 383 */ EXTERN Tcl_Obj * Tcl_GetRange(Tcl_Obj *objPtr, int first, int last); /* 384 */ EXTERN void Tcl_AppendUnicodeToObj(Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int length); /* 385 */ EXTERN int Tcl_RegExpMatchObj(Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj); /* 386 */ EXTERN void Tcl_SetNotifier(Tcl_NotifierProcs *notifierProcPtr); /* 387 */ EXTERN Tcl_Mutex * Tcl_GetAllocMutex(void); /* 388 */ EXTERN int Tcl_GetChannelNames(Tcl_Interp *interp); /* 389 */ EXTERN int Tcl_GetChannelNamesEx(Tcl_Interp *interp, const char *pattern); /* 390 */ EXTERN int Tcl_ProcObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* 391 */ EXTERN void Tcl_ConditionFinalize(Tcl_Condition *condPtr); /* 392 */ EXTERN void Tcl_MutexFinalize(Tcl_Mutex *mutex); /* 393 */ EXTERN int Tcl_CreateThread(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, ClientData clientData, int stackSize, int flags); /* 394 */ EXTERN int Tcl_ReadRaw(Tcl_Channel chan, char *dst, int bytesToRead); /* 395 */ EXTERN int Tcl_WriteRaw(Tcl_Channel chan, const char *src, int srcLen); /* 396 */ EXTERN Tcl_Channel Tcl_GetTopChannel(Tcl_Channel chan); /* 397 */ EXTERN int Tcl_ChannelBuffered(Tcl_Channel chan); /* 398 */ EXTERN CONST84_RETURN char * Tcl_ChannelName( const Tcl_ChannelType *chanTypePtr); /* 399 */ EXTERN Tcl_ChannelTypeVersion Tcl_ChannelVersion( const Tcl_ChannelType *chanTypePtr); /* 400 */ EXTERN Tcl_DriverBlockModeProc * Tcl_ChannelBlockModeProc( const Tcl_ChannelType *chanTypePtr); /* 401 */ EXTERN Tcl_DriverCloseProc * Tcl_ChannelCloseProc( const Tcl_ChannelType *chanTypePtr); /* 402 */ EXTERN Tcl_DriverClose2Proc * Tcl_ChannelClose2Proc( const Tcl_ChannelType *chanTypePtr); /* 403 */ EXTERN Tcl_DriverInputProc * Tcl_ChannelInputProc( const Tcl_ChannelType *chanTypePtr); /* 404 */ EXTERN Tcl_DriverOutputProc * Tcl_ChannelOutputProc( const Tcl_ChannelType *chanTypePtr); /* 405 */ EXTERN Tcl_DriverSeekProc * Tcl_ChannelSeekProc( const Tcl_ChannelType *chanTypePtr); /* 406 */ EXTERN Tcl_DriverSetOptionProc * Tcl_ChannelSetOptionProc( const Tcl_ChannelType *chanTypePtr); /* 407 */ EXTERN Tcl_DriverGetOptionProc * Tcl_ChannelGetOptionProc( const Tcl_ChannelType *chanTypePtr); /* 408 */ EXTERN Tcl_DriverWatchProc * Tcl_ChannelWatchProc( const Tcl_ChannelType *chanTypePtr); /* 409 */ EXTERN Tcl_DriverGetHandleProc * Tcl_ChannelGetHandleProc( const Tcl_ChannelType *chanTypePtr); /* 410 */ EXTERN Tcl_DriverFlushProc * Tcl_ChannelFlushProc( const Tcl_ChannelType *chanTypePtr); /* 411 */ EXTERN Tcl_DriverHandlerProc * Tcl_ChannelHandlerProc( const Tcl_ChannelType *chanTypePtr); /* 412 */ EXTERN int Tcl_JoinThread(Tcl_ThreadId threadId, int *result); /* 413 */ EXTERN int Tcl_IsChannelShared(Tcl_Channel channel); /* 414 */ EXTERN int Tcl_IsChannelRegistered(Tcl_Interp *interp, Tcl_Channel channel); /* 415 */ EXTERN void Tcl_CutChannel(Tcl_Channel channel); /* 416 */ EXTERN void Tcl_SpliceChannel(Tcl_Channel channel); /* 417 */ EXTERN void Tcl_ClearChannelHandlers(Tcl_Channel channel); /* 418 */ EXTERN int Tcl_IsChannelExisting(const char *channelName); /* 419 */ EXTERN int Tcl_UniCharNcasecmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 420 */ EXTERN int Tcl_UniCharCaseMatch(const Tcl_UniChar *uniStr, const Tcl_UniChar *uniPattern, int nocase); /* 421 */ EXTERN Tcl_HashEntry * Tcl_FindHashEntry(Tcl_HashTable *tablePtr, const void *key); /* 422 */ EXTERN Tcl_HashEntry * Tcl_CreateHashEntry(Tcl_HashTable *tablePtr, const void *key, int *newPtr); /* 423 */ EXTERN void Tcl_InitCustomHashTable(Tcl_HashTable *tablePtr, int keyType, const Tcl_HashKeyType *typePtr); /* 424 */ EXTERN void Tcl_InitObjHashTable(Tcl_HashTable *tablePtr); /* 425 */ EXTERN ClientData Tcl_CommandTraceInfo(Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *procPtr, ClientData prevClientData); /* 426 */ EXTERN int Tcl_TraceCommand(Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 427 */ EXTERN void Tcl_UntraceCommand(Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 428 */ EXTERN char * Tcl_AttemptAlloc(unsigned int size); /* 429 */ EXTERN char * Tcl_AttemptDbCkalloc(unsigned int size, const char *file, int line); /* 430 */ EXTERN char * Tcl_AttemptRealloc(char *ptr, unsigned int size); /* 431 */ EXTERN char * Tcl_AttemptDbCkrealloc(char *ptr, unsigned int size, const char *file, int line); /* 432 */ EXTERN int Tcl_AttemptSetObjLength(Tcl_Obj *objPtr, int length); /* 433 */ EXTERN Tcl_ThreadId Tcl_GetChannelThread(Tcl_Channel channel); /* 434 */ EXTERN Tcl_UniChar * Tcl_GetUnicodeFromObj(Tcl_Obj *objPtr, int *lengthPtr); /* 435 */ EXTERN int Tcl_GetMathFuncInfo(Tcl_Interp *interp, const char *name, int *numArgsPtr, Tcl_ValueType **argTypesPtr, Tcl_MathProc **procPtr, ClientData *clientDataPtr); /* 436 */ EXTERN Tcl_Obj * Tcl_ListMathFuncs(Tcl_Interp *interp, const char *pattern); /* 437 */ EXTERN Tcl_Obj * Tcl_SubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 438 */ EXTERN int Tcl_DetachChannel(Tcl_Interp *interp, Tcl_Channel channel); /* 439 */ EXTERN int Tcl_IsStandardChannel(Tcl_Channel channel); /* 440 */ EXTERN int Tcl_FSCopyFile(Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 441 */ EXTERN int Tcl_FSCopyDirectory(Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); /* 442 */ EXTERN int Tcl_FSCreateDirectory(Tcl_Obj *pathPtr); /* 443 */ EXTERN int Tcl_FSDeleteFile(Tcl_Obj *pathPtr); /* 444 */ EXTERN int Tcl_FSLoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *sym1, const char *sym2, Tcl_PackageInitProc **proc1Ptr, Tcl_PackageInitProc **proc2Ptr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); /* 445 */ EXTERN int Tcl_FSMatchInDirectory(Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); /* 446 */ EXTERN Tcl_Obj * Tcl_FSLink(Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction); /* 447 */ EXTERN int Tcl_FSRemoveDirectory(Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr); /* 448 */ EXTERN int Tcl_FSRenameFile(Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 449 */ EXTERN int Tcl_FSLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 450 */ EXTERN int Tcl_FSUtime(Tcl_Obj *pathPtr, struct utimbuf *tval); /* 451 */ EXTERN int Tcl_FSFileAttrsGet(Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 452 */ EXTERN int Tcl_FSFileAttrsSet(Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr); /* 453 */ EXTERN const char *CONST86 * Tcl_FSFileAttrStrings(Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 454 */ EXTERN int Tcl_FSStat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 455 */ EXTERN int Tcl_FSAccess(Tcl_Obj *pathPtr, int mode); /* 456 */ EXTERN Tcl_Channel Tcl_FSOpenFileChannel(Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *modeString, int permissions); /* 457 */ EXTERN Tcl_Obj * Tcl_FSGetCwd(Tcl_Interp *interp); /* 458 */ EXTERN int Tcl_FSChdir(Tcl_Obj *pathPtr); /* 459 */ EXTERN int Tcl_FSConvertToPathType(Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 460 */ EXTERN Tcl_Obj * Tcl_FSJoinPath(Tcl_Obj *listObj, int elements); /* 461 */ EXTERN Tcl_Obj * Tcl_FSSplitPath(Tcl_Obj *pathPtr, int *lenPtr); /* 462 */ EXTERN int Tcl_FSEqualPaths(Tcl_Obj *firstPtr, Tcl_Obj *secondPtr); /* 463 */ EXTERN Tcl_Obj * Tcl_FSGetNormalizedPath(Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 464 */ EXTERN Tcl_Obj * Tcl_FSJoinToPath(Tcl_Obj *pathPtr, int objc, Tcl_Obj *const objv[]); /* 465 */ EXTERN ClientData Tcl_FSGetInternalRep(Tcl_Obj *pathPtr, const Tcl_Filesystem *fsPtr); /* 466 */ EXTERN Tcl_Obj * Tcl_FSGetTranslatedPath(Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 467 */ EXTERN int Tcl_FSEvalFile(Tcl_Interp *interp, Tcl_Obj *fileName); /* 468 */ EXTERN Tcl_Obj * Tcl_FSNewNativePath( const Tcl_Filesystem *fromFilesystem, ClientData clientData); /* 469 */ EXTERN const void * Tcl_FSGetNativePath(Tcl_Obj *pathPtr); /* 470 */ EXTERN Tcl_Obj * Tcl_FSFileSystemInfo(Tcl_Obj *pathPtr); /* 471 */ EXTERN Tcl_Obj * Tcl_FSPathSeparator(Tcl_Obj *pathPtr); /* 472 */ EXTERN Tcl_Obj * Tcl_FSListVolumes(void); /* 473 */ EXTERN int Tcl_FSRegister(ClientData clientData, const Tcl_Filesystem *fsPtr); /* 474 */ EXTERN int Tcl_FSUnregister(const Tcl_Filesystem *fsPtr); /* 475 */ EXTERN ClientData Tcl_FSData(const Tcl_Filesystem *fsPtr); /* 476 */ EXTERN const char * Tcl_FSGetTranslatedStringPath(Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 477 */ EXTERN CONST86 Tcl_Filesystem * Tcl_FSGetFileSystemForPath(Tcl_Obj *pathPtr); /* 478 */ EXTERN Tcl_PathType Tcl_FSGetPathType(Tcl_Obj *pathPtr); /* 479 */ EXTERN int Tcl_OutputBuffered(Tcl_Channel chan); /* 480 */ EXTERN void Tcl_FSMountsChanged(const Tcl_Filesystem *fsPtr); /* 481 */ EXTERN int Tcl_EvalTokensStandard(Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 482 */ EXTERN void Tcl_GetTime(Tcl_Time *timeBuf); /* 483 */ EXTERN Tcl_Trace Tcl_CreateObjTrace(Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc *objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 484 */ EXTERN int Tcl_GetCommandInfoFromToken(Tcl_Command token, Tcl_CmdInfo *infoPtr); /* 485 */ EXTERN int Tcl_SetCommandInfoFromToken(Tcl_Command token, const Tcl_CmdInfo *infoPtr); /* 486 */ EXTERN Tcl_Obj * Tcl_DbNewWideIntObj(Tcl_WideInt wideValue, const char *file, int line); /* 487 */ EXTERN int Tcl_GetWideIntFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr); /* 488 */ EXTERN Tcl_Obj * Tcl_NewWideIntObj(Tcl_WideInt wideValue); /* 489 */ EXTERN void Tcl_SetWideIntObj(Tcl_Obj *objPtr, Tcl_WideInt wideValue); /* 490 */ EXTERN Tcl_StatBuf * Tcl_AllocStatBuf(void); /* 491 */ EXTERN Tcl_WideInt Tcl_Seek(Tcl_Channel chan, Tcl_WideInt offset, int mode); /* 492 */ EXTERN Tcl_WideInt Tcl_Tell(Tcl_Channel chan); /* 493 */ EXTERN Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc( const Tcl_ChannelType *chanTypePtr); /* 494 */ EXTERN int Tcl_DictObjPut(Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); /* 495 */ EXTERN int Tcl_DictObjGet(Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); /* 496 */ EXTERN int Tcl_DictObjRemove(Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); /* 497 */ EXTERN int Tcl_DictObjSize(Tcl_Interp *interp, Tcl_Obj *dictPtr, int *sizePtr); /* 498 */ EXTERN int Tcl_DictObjFirst(Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 499 */ EXTERN void Tcl_DictObjNext(Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 500 */ EXTERN void Tcl_DictObjDone(Tcl_DictSearch *searchPtr); /* 501 */ EXTERN int Tcl_DictObjPutKeyList(Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); /* 502 */ EXTERN int Tcl_DictObjRemoveKeyList(Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv); /* 503 */ EXTERN Tcl_Obj * Tcl_NewDictObj(void); /* 504 */ EXTERN Tcl_Obj * Tcl_DbNewDictObj(const char *file, int line); /* 505 */ EXTERN void Tcl_RegisterConfig(Tcl_Interp *interp, const char *pkgName, const Tcl_Config *configuration, const char *valEncoding); /* 506 */ EXTERN Tcl_Namespace * Tcl_CreateNamespace(Tcl_Interp *interp, const char *name, ClientData clientData, Tcl_NamespaceDeleteProc *deleteProc); /* 507 */ EXTERN void Tcl_DeleteNamespace(Tcl_Namespace *nsPtr); /* 508 */ EXTERN int Tcl_AppendExportList(Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); /* 509 */ EXTERN int Tcl_Export(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int resetListFirst); /* 510 */ EXTERN int Tcl_Import(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int allowOverwrite); /* 511 */ EXTERN int Tcl_ForgetImport(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern); /* 512 */ EXTERN Tcl_Namespace * Tcl_GetCurrentNamespace(Tcl_Interp *interp); /* 513 */ EXTERN Tcl_Namespace * Tcl_GetGlobalNamespace(Tcl_Interp *interp); /* 514 */ EXTERN Tcl_Namespace * Tcl_FindNamespace(Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 515 */ EXTERN Tcl_Command Tcl_FindCommand(Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 516 */ EXTERN Tcl_Command Tcl_GetCommandFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr); /* 517 */ EXTERN void Tcl_GetCommandFullName(Tcl_Interp *interp, Tcl_Command command, Tcl_Obj *objPtr); /* 518 */ EXTERN int Tcl_FSEvalFileEx(Tcl_Interp *interp, Tcl_Obj *fileName, const char *encodingName); /* 519 */ EXTERN Tcl_ExitProc * Tcl_SetExitProc(TCL_NORETURN1 Tcl_ExitProc *proc); /* 520 */ EXTERN void Tcl_LimitAddHandler(Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData, Tcl_LimitHandlerDeleteProc *deleteProc); /* 521 */ EXTERN void Tcl_LimitRemoveHandler(Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData); /* 522 */ EXTERN int Tcl_LimitReady(Tcl_Interp *interp); /* 523 */ EXTERN int Tcl_LimitCheck(Tcl_Interp *interp); /* 524 */ EXTERN int Tcl_LimitExceeded(Tcl_Interp *interp); /* 525 */ EXTERN void Tcl_LimitSetCommands(Tcl_Interp *interp, int commandLimit); /* 526 */ EXTERN void Tcl_LimitSetTime(Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 527 */ EXTERN void Tcl_LimitSetGranularity(Tcl_Interp *interp, int type, int granularity); /* 528 */ EXTERN int Tcl_LimitTypeEnabled(Tcl_Interp *interp, int type); /* 529 */ EXTERN int Tcl_LimitTypeExceeded(Tcl_Interp *interp, int type); /* 530 */ EXTERN void Tcl_LimitTypeSet(Tcl_Interp *interp, int type); /* 531 */ EXTERN void Tcl_LimitTypeReset(Tcl_Interp *interp, int type); /* 532 */ EXTERN int Tcl_LimitGetCommands(Tcl_Interp *interp); /* 533 */ EXTERN void Tcl_LimitGetTime(Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 534 */ EXTERN int Tcl_LimitGetGranularity(Tcl_Interp *interp, int type); /* 535 */ EXTERN Tcl_InterpState Tcl_SaveInterpState(Tcl_Interp *interp, int status); /* 536 */ EXTERN int Tcl_RestoreInterpState(Tcl_Interp *interp, Tcl_InterpState state); /* 537 */ EXTERN void Tcl_DiscardInterpState(Tcl_InterpState state); /* 538 */ EXTERN int Tcl_SetReturnOptions(Tcl_Interp *interp, Tcl_Obj *options); /* 539 */ EXTERN Tcl_Obj * Tcl_GetReturnOptions(Tcl_Interp *interp, int result); /* 540 */ EXTERN int Tcl_IsEnsemble(Tcl_Command token); /* 541 */ EXTERN Tcl_Command Tcl_CreateEnsemble(Tcl_Interp *interp, const char *name, Tcl_Namespace *namespacePtr, int flags); /* 542 */ EXTERN Tcl_Command Tcl_FindEnsemble(Tcl_Interp *interp, Tcl_Obj *cmdNameObj, int flags); /* 543 */ EXTERN int Tcl_SetEnsembleSubcommandList(Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *subcmdList); /* 544 */ EXTERN int Tcl_SetEnsembleMappingDict(Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *mapDict); /* 545 */ EXTERN int Tcl_SetEnsembleUnknownHandler(Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *unknownList); /* 546 */ EXTERN int Tcl_SetEnsembleFlags(Tcl_Interp *interp, Tcl_Command token, int flags); /* 547 */ EXTERN int Tcl_GetEnsembleSubcommandList(Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr); /* 548 */ EXTERN int Tcl_GetEnsembleMappingDict(Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr); /* 549 */ EXTERN int Tcl_GetEnsembleUnknownHandler(Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr); /* 550 */ EXTERN int Tcl_GetEnsembleFlags(Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 551 */ EXTERN int Tcl_GetEnsembleNamespace(Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 552 */ EXTERN void Tcl_SetTimeProc(Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, ClientData clientData); /* 553 */ EXTERN void Tcl_QueryTimeProc(Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, ClientData *clientData); /* 554 */ EXTERN Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc( const Tcl_ChannelType *chanTypePtr); /* 555 */ EXTERN Tcl_Obj * Tcl_NewBignumObj(mp_int *value); /* 556 */ EXTERN Tcl_Obj * Tcl_DbNewBignumObj(mp_int *value, const char *file, int line); /* 557 */ EXTERN void Tcl_SetBignumObj(Tcl_Obj *obj, mp_int *value); /* 558 */ EXTERN int Tcl_GetBignumFromObj(Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 559 */ EXTERN int Tcl_TakeBignumFromObj(Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 560 */ EXTERN int Tcl_TruncateChannel(Tcl_Channel chan, Tcl_WideInt length); /* 561 */ EXTERN Tcl_DriverTruncateProc * Tcl_ChannelTruncateProc( const Tcl_ChannelType *chanTypePtr); /* 562 */ EXTERN void Tcl_SetChannelErrorInterp(Tcl_Interp *interp, Tcl_Obj *msg); /* 563 */ EXTERN void Tcl_GetChannelErrorInterp(Tcl_Interp *interp, Tcl_Obj **msg); /* 564 */ EXTERN void Tcl_SetChannelError(Tcl_Channel chan, Tcl_Obj *msg); /* 565 */ EXTERN void Tcl_GetChannelError(Tcl_Channel chan, Tcl_Obj **msg); /* 566 */ EXTERN int Tcl_InitBignumFromDouble(Tcl_Interp *interp, double initval, mp_int *toInit); /* 567 */ EXTERN Tcl_Obj * Tcl_GetNamespaceUnknownHandler(Tcl_Interp *interp, Tcl_Namespace *nsPtr); /* 568 */ EXTERN int Tcl_SetNamespaceUnknownHandler(Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); /* 569 */ EXTERN int Tcl_GetEncodingFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); /* 570 */ EXTERN Tcl_Obj * Tcl_GetEncodingSearchPath(void); /* 571 */ EXTERN int Tcl_SetEncodingSearchPath(Tcl_Obj *searchPath); /* 572 */ EXTERN const char * Tcl_GetEncodingNameFromEnvironment( Tcl_DString *bufPtr); /* 573 */ EXTERN int Tcl_PkgRequireProc(Tcl_Interp *interp, const char *name, int objc, Tcl_Obj *const objv[], void *clientDataPtr); /* 574 */ EXTERN void Tcl_AppendObjToErrorInfo(Tcl_Interp *interp, Tcl_Obj *objPtr); /* 575 */ EXTERN void Tcl_AppendLimitedToObj(Tcl_Obj *objPtr, const char *bytes, int length, int limit, const char *ellipsis); /* 576 */ EXTERN Tcl_Obj * Tcl_Format(Tcl_Interp *interp, const char *format, int objc, Tcl_Obj *const objv[]); /* 577 */ EXTERN int Tcl_AppendFormatToObj(Tcl_Interp *interp, Tcl_Obj *objPtr, const char *format, int objc, Tcl_Obj *const objv[]); /* 578 */ EXTERN Tcl_Obj * Tcl_ObjPrintf(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 579 */ EXTERN void Tcl_AppendPrintfToObj(Tcl_Obj *objPtr, const char *format, ...) TCL_FORMAT_PRINTF(2, 3); /* 580 */ EXTERN int Tcl_CancelEval(Tcl_Interp *interp, Tcl_Obj *resultObjPtr, ClientData clientData, int flags); /* 581 */ EXTERN int Tcl_Canceled(Tcl_Interp *interp, int flags); /* 582 */ EXTERN int Tcl_CreatePipe(Tcl_Interp *interp, Tcl_Channel *rchan, Tcl_Channel *wchan, int flags); /* 583 */ EXTERN Tcl_Command Tcl_NRCreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 584 */ EXTERN int Tcl_NREvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 585 */ EXTERN int Tcl_NREvalObjv(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 586 */ EXTERN int Tcl_NRCmdSwap(Tcl_Interp *interp, Tcl_Command cmd, int objc, Tcl_Obj *const objv[], int flags); /* 587 */ EXTERN void Tcl_NRAddCallback(Tcl_Interp *interp, Tcl_NRPostProc *postProcPtr, ClientData data0, ClientData data1, ClientData data2, ClientData data3); /* 588 */ EXTERN int Tcl_NRCallObjProc(Tcl_Interp *interp, Tcl_ObjCmdProc *objProc, ClientData clientData, int objc, Tcl_Obj *const objv[]); /* 589 */ EXTERN unsigned Tcl_GetFSDeviceFromStat(const Tcl_StatBuf *statPtr); /* 590 */ EXTERN unsigned Tcl_GetFSInodeFromStat(const Tcl_StatBuf *statPtr); /* 591 */ EXTERN unsigned Tcl_GetModeFromStat(const Tcl_StatBuf *statPtr); /* 592 */ EXTERN int Tcl_GetLinkCountFromStat(const Tcl_StatBuf *statPtr); /* 593 */ EXTERN int Tcl_GetUserIdFromStat(const Tcl_StatBuf *statPtr); /* 594 */ EXTERN int Tcl_GetGroupIdFromStat(const Tcl_StatBuf *statPtr); /* 595 */ EXTERN int Tcl_GetDeviceTypeFromStat(const Tcl_StatBuf *statPtr); /* 596 */ EXTERN Tcl_WideInt Tcl_GetAccessTimeFromStat(const Tcl_StatBuf *statPtr); /* 597 */ EXTERN Tcl_WideInt Tcl_GetModificationTimeFromStat( const Tcl_StatBuf *statPtr); /* 598 */ EXTERN Tcl_WideInt Tcl_GetChangeTimeFromStat(const Tcl_StatBuf *statPtr); /* 599 */ EXTERN Tcl_WideUInt Tcl_GetSizeFromStat(const Tcl_StatBuf *statPtr); /* 600 */ EXTERN Tcl_WideUInt Tcl_GetBlocksFromStat(const Tcl_StatBuf *statPtr); /* 601 */ EXTERN unsigned Tcl_GetBlockSizeFromStat(const Tcl_StatBuf *statPtr); /* 602 */ EXTERN int Tcl_SetEnsembleParameterList(Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *paramList); /* 603 */ EXTERN int Tcl_GetEnsembleParameterList(Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **paramListPtr); /* 604 */ EXTERN int Tcl_ParseArgsObjv(Tcl_Interp *interp, const Tcl_ArgvInfo *argTable, int *objcPtr, Tcl_Obj *const *objv, Tcl_Obj ***remObjv); /* 605 */ EXTERN int Tcl_GetErrorLine(Tcl_Interp *interp); /* 606 */ EXTERN void Tcl_SetErrorLine(Tcl_Interp *interp, int lineNum); /* 607 */ EXTERN void Tcl_TransferResult(Tcl_Interp *sourceInterp, int result, Tcl_Interp *targetInterp); /* 608 */ EXTERN int Tcl_InterpActive(Tcl_Interp *interp); /* 609 */ EXTERN void Tcl_BackgroundException(Tcl_Interp *interp, int code); /* 610 */ EXTERN int Tcl_ZlibDeflate(Tcl_Interp *interp, int format, Tcl_Obj *data, int level, Tcl_Obj *gzipHeaderDictObj); /* 611 */ EXTERN int Tcl_ZlibInflate(Tcl_Interp *interp, int format, Tcl_Obj *data, int buffersize, Tcl_Obj *gzipHeaderDictObj); /* 612 */ EXTERN unsigned int Tcl_ZlibCRC32(unsigned int crc, const unsigned char *buf, int len); /* 613 */ EXTERN unsigned int Tcl_ZlibAdler32(unsigned int adler, const unsigned char *buf, int len); /* 614 */ EXTERN int Tcl_ZlibStreamInit(Tcl_Interp *interp, int mode, int format, int level, Tcl_Obj *dictObj, Tcl_ZlibStream *zshandle); /* 615 */ EXTERN Tcl_Obj * Tcl_ZlibStreamGetCommandName(Tcl_ZlibStream zshandle); /* 616 */ EXTERN int Tcl_ZlibStreamEof(Tcl_ZlibStream zshandle); /* 617 */ EXTERN int Tcl_ZlibStreamChecksum(Tcl_ZlibStream zshandle); /* 618 */ EXTERN int Tcl_ZlibStreamPut(Tcl_ZlibStream zshandle, Tcl_Obj *data, int flush); /* 619 */ EXTERN int Tcl_ZlibStreamGet(Tcl_ZlibStream zshandle, Tcl_Obj *data, int count); /* 620 */ EXTERN int Tcl_ZlibStreamClose(Tcl_ZlibStream zshandle); /* 621 */ EXTERN int Tcl_ZlibStreamReset(Tcl_ZlibStream zshandle); /* 622 */ EXTERN void Tcl_SetStartupScript(Tcl_Obj *path, const char *encoding); /* 623 */ EXTERN Tcl_Obj * Tcl_GetStartupScript(const char **encodingPtr); /* 624 */ EXTERN int Tcl_CloseEx(Tcl_Interp *interp, Tcl_Channel chan, int flags); /* 625 */ EXTERN int Tcl_NRExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *resultPtr); /* 626 */ EXTERN int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 627 */ EXTERN int Tcl_LoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *const symv[], int flags, void *procPtrs, Tcl_LoadHandle *handlePtr); /* 628 */ EXTERN void * Tcl_FindSymbol(Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 629 */ EXTERN int Tcl_FSUnloadFile(Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 630 */ EXTERN void Tcl_ZlibStreamSetCompressionDictionary( Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); typedef struct { const struct TclPlatStubs *tclPlatStubs; const struct TclIntStubs *tclIntStubs; const struct TclIntPlatStubs *tclIntPlatStubs; } TclStubHooks; typedef struct TclStubs { int magic; const TclStubHooks *hooks; int (*tcl_PkgProvideEx) (Tcl_Interp *interp, const char *name, const char *version, const void *clientData); /* 0 */ CONST84_RETURN char * (*tcl_PkgRequireEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 1 */ TCL_NORETURN1 void (*tcl_Panic) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 2 */ char * (*tcl_Alloc) (unsigned int size); /* 3 */ void (*tcl_Free) (char *ptr); /* 4 */ char * (*tcl_Realloc) (char *ptr, unsigned int size); /* 5 */ char * (*tcl_DbCkalloc) (unsigned int size, const char *file, int line); /* 6 */ void (*tcl_DbCkfree) (char *ptr, const char *file, int line); /* 7 */ char * (*tcl_DbCkrealloc) (char *ptr, unsigned int size, const char *file, int line); /* 8 */ #if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */ #endif /* UNIX */ #if defined(_WIN32) /* WIN */ void (*reserved9)(void); #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */ #endif /* MACOSX */ #if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ void (*tcl_DeleteFileHandler) (int fd); /* 10 */ #endif /* UNIX */ #if defined(_WIN32) /* WIN */ void (*reserved10)(void); #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ void (*tcl_DeleteFileHandler) (int fd); /* 10 */ #endif /* MACOSX */ void (*tcl_SetTimer) (const Tcl_Time *timePtr); /* 11 */ void (*tcl_Sleep) (int ms); /* 12 */ int (*tcl_WaitForEvent) (const Tcl_Time *timePtr); /* 13 */ int (*tcl_AppendAllObjTypes) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 14 */ void (*tcl_AppendStringsToObj) (Tcl_Obj *objPtr, ...); /* 15 */ void (*tcl_AppendToObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 16 */ Tcl_Obj * (*tcl_ConcatObj) (int objc, Tcl_Obj *const objv[]); /* 17 */ int (*tcl_ConvertToType) (Tcl_Interp *interp, Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 18 */ void (*tcl_DbDecrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 19 */ void (*tcl_DbIncrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 20 */ int (*tcl_DbIsShared) (Tcl_Obj *objPtr, const char *file, int line); /* 21 */ Tcl_Obj * (*tcl_DbNewBooleanObj) (int boolValue, const char *file, int line); /* 22 */ Tcl_Obj * (*tcl_DbNewByteArrayObj) (const unsigned char *bytes, int length, const char *file, int line); /* 23 */ Tcl_Obj * (*tcl_DbNewDoubleObj) (double doubleValue, const char *file, int line); /* 24 */ Tcl_Obj * (*tcl_DbNewListObj) (int objc, Tcl_Obj *const *objv, const char *file, int line); /* 25 */ Tcl_Obj * (*tcl_DbNewLongObj) (long longValue, const char *file, int line); /* 26 */ Tcl_Obj * (*tcl_DbNewObj) (const char *file, int line); /* 27 */ Tcl_Obj * (*tcl_DbNewStringObj) (const char *bytes, int length, const char *file, int line); /* 28 */ Tcl_Obj * (*tcl_DuplicateObj) (Tcl_Obj *objPtr); /* 29 */ void (*tclFreeObj) (Tcl_Obj *objPtr); /* 30 */ int (*tcl_GetBoolean) (Tcl_Interp *interp, const char *src, int *boolPtr); /* 31 */ int (*tcl_GetBooleanFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *boolPtr); /* 32 */ unsigned char * (*tcl_GetByteArrayFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 33 */ int (*tcl_GetDouble) (Tcl_Interp *interp, const char *src, double *doublePtr); /* 34 */ int (*tcl_GetDoubleFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* 35 */ int (*tcl_GetIndexFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, CONST84 char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 36 */ int (*tcl_GetInt) (Tcl_Interp *interp, const char *src, int *intPtr); /* 37 */ int (*tcl_GetIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 38 */ int (*tcl_GetLongFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr); /* 39 */ CONST86 Tcl_ObjType * (*tcl_GetObjType) (const char *typeName); /* 40 */ char * (*tcl_GetStringFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 41 */ void (*tcl_InvalidateStringRep) (Tcl_Obj *objPtr); /* 42 */ int (*tcl_ListObjAppendList) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); /* 43 */ int (*tcl_ListObjAppendElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr); /* 44 */ int (*tcl_ListObjGetElements) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr); /* 45 */ int (*tcl_ListObjIndex) (Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr); /* 46 */ int (*tcl_ListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr); /* 47 */ int (*tcl_ListObjReplace) (Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *const objv[]); /* 48 */ Tcl_Obj * (*tcl_NewBooleanObj) (int boolValue); /* 49 */ Tcl_Obj * (*tcl_NewByteArrayObj) (const unsigned char *bytes, int length); /* 50 */ Tcl_Obj * (*tcl_NewDoubleObj) (double doubleValue); /* 51 */ Tcl_Obj * (*tcl_NewIntObj) (int intValue); /* 52 */ Tcl_Obj * (*tcl_NewListObj) (int objc, Tcl_Obj *const objv[]); /* 53 */ Tcl_Obj * (*tcl_NewLongObj) (long longValue); /* 54 */ Tcl_Obj * (*tcl_NewObj) (void); /* 55 */ Tcl_Obj * (*tcl_NewStringObj) (const char *bytes, int length); /* 56 */ void (*tcl_SetBooleanObj) (Tcl_Obj *objPtr, int boolValue); /* 57 */ unsigned char * (*tcl_SetByteArrayLength) (Tcl_Obj *objPtr, int length); /* 58 */ void (*tcl_SetByteArrayObj) (Tcl_Obj *objPtr, const unsigned char *bytes, int length); /* 59 */ void (*tcl_SetDoubleObj) (Tcl_Obj *objPtr, double doubleValue); /* 60 */ void (*tcl_SetIntObj) (Tcl_Obj *objPtr, int intValue); /* 61 */ void (*tcl_SetListObj) (Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[]); /* 62 */ void (*tcl_SetLongObj) (Tcl_Obj *objPtr, long longValue); /* 63 */ void (*tcl_SetObjLength) (Tcl_Obj *objPtr, int length); /* 64 */ void (*tcl_SetStringObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 65 */ void (*tcl_AddErrorInfo) (Tcl_Interp *interp, const char *message); /* 66 */ void (*tcl_AddObjErrorInfo) (Tcl_Interp *interp, const char *message, int length); /* 67 */ void (*tcl_AllowExceptions) (Tcl_Interp *interp); /* 68 */ void (*tcl_AppendElement) (Tcl_Interp *interp, const char *element); /* 69 */ void (*tcl_AppendResult) (Tcl_Interp *interp, ...); /* 70 */ Tcl_AsyncHandler (*tcl_AsyncCreate) (Tcl_AsyncProc *proc, ClientData clientData); /* 71 */ void (*tcl_AsyncDelete) (Tcl_AsyncHandler async); /* 72 */ int (*tcl_AsyncInvoke) (Tcl_Interp *interp, int code); /* 73 */ void (*tcl_AsyncMark) (Tcl_AsyncHandler async); /* 74 */ int (*tcl_AsyncReady) (void); /* 75 */ void (*tcl_BackgroundError) (Tcl_Interp *interp); /* 76 */ char (*tcl_Backslash) (const char *src, int *readPtr); /* 77 */ int (*tcl_BadChannelOption) (Tcl_Interp *interp, const char *optionName, const char *optionList); /* 78 */ void (*tcl_CallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 79 */ void (*tcl_CancelIdleCall) (Tcl_IdleProc *idleProc, ClientData clientData); /* 80 */ int (*tcl_Close) (Tcl_Interp *interp, Tcl_Channel chan); /* 81 */ int (*tcl_CommandComplete) (const char *cmd); /* 82 */ char * (*tcl_Concat) (int argc, CONST84 char *const *argv); /* 83 */ int (*tcl_ConvertElement) (const char *src, char *dst, int flags); /* 84 */ int (*tcl_ConvertCountedElement) (const char *src, int length, char *dst, int flags); /* 85 */ int (*tcl_CreateAlias) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int argc, CONST84 char *const *argv); /* 86 */ int (*tcl_CreateAliasObj) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int objc, Tcl_Obj *const objv[]); /* 87 */ Tcl_Channel (*tcl_CreateChannel) (const Tcl_ChannelType *typePtr, const char *chanName, ClientData instanceData, int mask); /* 88 */ void (*tcl_CreateChannelHandler) (Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, ClientData clientData); /* 89 */ void (*tcl_CreateCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 90 */ Tcl_Command (*tcl_CreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 91 */ void (*tcl_CreateEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 92 */ void (*tcl_CreateExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 93 */ Tcl_Interp * (*tcl_CreateInterp) (void); /* 94 */ void (*tcl_CreateMathFunc) (Tcl_Interp *interp, const char *name, int numArgs, Tcl_ValueType *argTypes, Tcl_MathProc *proc, ClientData clientData); /* 95 */ Tcl_Command (*tcl_CreateObjCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 96 */ Tcl_Interp * (*tcl_CreateSlave) (Tcl_Interp *interp, const char *slaveName, int isSafe); /* 97 */ Tcl_TimerToken (*tcl_CreateTimerHandler) (int milliseconds, Tcl_TimerProc *proc, ClientData clientData); /* 98 */ Tcl_Trace (*tcl_CreateTrace) (Tcl_Interp *interp, int level, Tcl_CmdTraceProc *proc, ClientData clientData); /* 99 */ void (*tcl_DeleteAssocData) (Tcl_Interp *interp, const char *name); /* 100 */ void (*tcl_DeleteChannelHandler) (Tcl_Channel chan, Tcl_ChannelProc *proc, ClientData clientData); /* 101 */ void (*tcl_DeleteCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 102 */ int (*tcl_DeleteCommand) (Tcl_Interp *interp, const char *cmdName); /* 103 */ int (*tcl_DeleteCommandFromToken) (Tcl_Interp *interp, Tcl_Command command); /* 104 */ void (*tcl_DeleteEvents) (Tcl_EventDeleteProc *proc, ClientData clientData); /* 105 */ void (*tcl_DeleteEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 106 */ void (*tcl_DeleteExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 107 */ void (*tcl_DeleteHashEntry) (Tcl_HashEntry *entryPtr); /* 108 */ void (*tcl_DeleteHashTable) (Tcl_HashTable *tablePtr); /* 109 */ void (*tcl_DeleteInterp) (Tcl_Interp *interp); /* 110 */ void (*tcl_DetachPids) (int numPids, Tcl_Pid *pidPtr); /* 111 */ void (*tcl_DeleteTimerHandler) (Tcl_TimerToken token); /* 112 */ void (*tcl_DeleteTrace) (Tcl_Interp *interp, Tcl_Trace trace); /* 113 */ void (*tcl_DontCallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 114 */ int (*tcl_DoOneEvent) (int flags); /* 115 */ void (*tcl_DoWhenIdle) (Tcl_IdleProc *proc, ClientData clientData); /* 116 */ char * (*tcl_DStringAppend) (Tcl_DString *dsPtr, const char *bytes, int length); /* 117 */ char * (*tcl_DStringAppendElement) (Tcl_DString *dsPtr, const char *element); /* 118 */ void (*tcl_DStringEndSublist) (Tcl_DString *dsPtr); /* 119 */ void (*tcl_DStringFree) (Tcl_DString *dsPtr); /* 120 */ void (*tcl_DStringGetResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 121 */ void (*tcl_DStringInit) (Tcl_DString *dsPtr); /* 122 */ void (*tcl_DStringResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 123 */ void (*tcl_DStringSetLength) (Tcl_DString *dsPtr, int length); /* 124 */ void (*tcl_DStringStartSublist) (Tcl_DString *dsPtr); /* 125 */ int (*tcl_Eof) (Tcl_Channel chan); /* 126 */ CONST84_RETURN char * (*tcl_ErrnoId) (void); /* 127 */ CONST84_RETURN char * (*tcl_ErrnoMsg) (int err); /* 128 */ int (*tcl_Eval) (Tcl_Interp *interp, const char *script); /* 129 */ int (*tcl_EvalFile) (Tcl_Interp *interp, const char *fileName); /* 130 */ int (*tcl_EvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 131 */ void (*tcl_EventuallyFree) (ClientData clientData, Tcl_FreeProc *freeProc); /* 132 */ TCL_NORETURN1 void (*tcl_Exit) (int status); /* 133 */ int (*tcl_ExposeCommand) (Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName); /* 134 */ int (*tcl_ExprBoolean) (Tcl_Interp *interp, const char *expr, int *ptr); /* 135 */ int (*tcl_ExprBooleanObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr); /* 136 */ int (*tcl_ExprDouble) (Tcl_Interp *interp, const char *expr, double *ptr); /* 137 */ int (*tcl_ExprDoubleObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr); /* 138 */ int (*tcl_ExprLong) (Tcl_Interp *interp, const char *expr, long *ptr); /* 139 */ int (*tcl_ExprLongObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr); /* 140 */ int (*tcl_ExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr); /* 141 */ int (*tcl_ExprString) (Tcl_Interp *interp, const char *expr); /* 142 */ void (*tcl_Finalize) (void); /* 143 */ void (*tcl_FindExecutable) (const char *argv0); /* 144 */ Tcl_HashEntry * (*tcl_FirstHashEntry) (Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr); /* 145 */ int (*tcl_Flush) (Tcl_Channel chan); /* 146 */ void (*tcl_FreeResult) (Tcl_Interp *interp); /* 147 */ int (*tcl_GetAlias) (Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *argcPtr, CONST84 char ***argvPtr); /* 148 */ int (*tcl_GetAliasObj) (Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv); /* 149 */ ClientData (*tcl_GetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc **procPtr); /* 150 */ Tcl_Channel (*tcl_GetChannel) (Tcl_Interp *interp, const char *chanName, int *modePtr); /* 151 */ int (*tcl_GetChannelBufferSize) (Tcl_Channel chan); /* 152 */ int (*tcl_GetChannelHandle) (Tcl_Channel chan, int direction, ClientData *handlePtr); /* 153 */ ClientData (*tcl_GetChannelInstanceData) (Tcl_Channel chan); /* 154 */ int (*tcl_GetChannelMode) (Tcl_Channel chan); /* 155 */ CONST84_RETURN char * (*tcl_GetChannelName) (Tcl_Channel chan); /* 156 */ int (*tcl_GetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, Tcl_DString *dsPtr); /* 157 */ CONST86 Tcl_ChannelType * (*tcl_GetChannelType) (Tcl_Channel chan); /* 158 */ int (*tcl_GetCommandInfo) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); /* 159 */ CONST84_RETURN char * (*tcl_GetCommandName) (Tcl_Interp *interp, Tcl_Command command); /* 160 */ int (*tcl_GetErrno) (void); /* 161 */ CONST84_RETURN char * (*tcl_GetHostName) (void); /* 162 */ int (*tcl_GetInterpPath) (Tcl_Interp *askInterp, Tcl_Interp *slaveInterp); /* 163 */ Tcl_Interp * (*tcl_GetMaster) (Tcl_Interp *interp); /* 164 */ const char * (*tcl_GetNameOfExecutable) (void); /* 165 */ Tcl_Obj * (*tcl_GetObjResult) (Tcl_Interp *interp); /* 166 */ #if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */ #endif /* UNIX */ #if defined(_WIN32) /* WIN */ void (*reserved167)(void); #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */ #endif /* MACOSX */ Tcl_PathType (*tcl_GetPathType) (const char *path); /* 168 */ int (*tcl_Gets) (Tcl_Channel chan, Tcl_DString *dsPtr); /* 169 */ int (*tcl_GetsObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 170 */ int (*tcl_GetServiceMode) (void); /* 171 */ Tcl_Interp * (*tcl_GetSlave) (Tcl_Interp *interp, const char *slaveName); /* 172 */ Tcl_Channel (*tcl_GetStdChannel) (int type); /* 173 */ CONST84_RETURN char * (*tcl_GetStringResult) (Tcl_Interp *interp); /* 174 */ CONST84_RETURN char * (*tcl_GetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 175 */ CONST84_RETURN char * (*tcl_GetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 176 */ int (*tcl_GlobalEval) (Tcl_Interp *interp, const char *command); /* 177 */ int (*tcl_GlobalEvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 178 */ int (*tcl_HideCommand) (Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken); /* 179 */ int (*tcl_Init) (Tcl_Interp *interp); /* 180 */ void (*tcl_InitHashTable) (Tcl_HashTable *tablePtr, int keyType); /* 181 */ int (*tcl_InputBlocked) (Tcl_Channel chan); /* 182 */ int (*tcl_InputBuffered) (Tcl_Channel chan); /* 183 */ int (*tcl_InterpDeleted) (Tcl_Interp *interp); /* 184 */ int (*tcl_IsSafe) (Tcl_Interp *interp); /* 185 */ char * (*tcl_JoinPath) (int argc, CONST84 char *const *argv, Tcl_DString *resultPtr); /* 186 */ int (*tcl_LinkVar) (Tcl_Interp *interp, const char *varName, char *addr, int type); /* 187 */ void (*reserved188)(void); Tcl_Channel (*tcl_MakeFileChannel) (ClientData handle, int mode); /* 189 */ int (*tcl_MakeSafe) (Tcl_Interp *interp); /* 190 */ Tcl_Channel (*tcl_MakeTcpClientChannel) (ClientData tcpSocket); /* 191 */ char * (*tcl_Merge) (int argc, CONST84 char *const *argv); /* 192 */ Tcl_HashEntry * (*tcl_NextHashEntry) (Tcl_HashSearch *searchPtr); /* 193 */ void (*tcl_NotifyChannel) (Tcl_Channel channel, int mask); /* 194 */ Tcl_Obj * (*tcl_ObjGetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags); /* 195 */ Tcl_Obj * (*tcl_ObjSetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); /* 196 */ Tcl_Channel (*tcl_OpenCommandChannel) (Tcl_Interp *interp, int argc, CONST84 char **argv, int flags); /* 197 */ Tcl_Channel (*tcl_OpenFileChannel) (Tcl_Interp *interp, const char *fileName, const char *modeString, int permissions); /* 198 */ Tcl_Channel (*tcl_OpenTcpClient) (Tcl_Interp *interp, int port, const char *address, const char *myaddr, int myport, int async); /* 199 */ Tcl_Channel (*tcl_OpenTcpServer) (Tcl_Interp *interp, int port, const char *host, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 200 */ void (*tcl_Preserve) (ClientData data); /* 201 */ void (*tcl_PrintDouble) (Tcl_Interp *interp, double value, char *dst); /* 202 */ int (*tcl_PutEnv) (const char *assignment); /* 203 */ CONST84_RETURN char * (*tcl_PosixError) (Tcl_Interp *interp); /* 204 */ void (*tcl_QueueEvent) (Tcl_Event *evPtr, Tcl_QueuePosition position); /* 205 */ int (*tcl_Read) (Tcl_Channel chan, char *bufPtr, int toRead); /* 206 */ void (*tcl_ReapDetachedProcs) (void); /* 207 */ int (*tcl_RecordAndEval) (Tcl_Interp *interp, const char *cmd, int flags); /* 208 */ int (*tcl_RecordAndEvalObj) (Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags); /* 209 */ void (*tcl_RegisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 210 */ void (*tcl_RegisterObjType) (const Tcl_ObjType *typePtr); /* 211 */ Tcl_RegExp (*tcl_RegExpCompile) (Tcl_Interp *interp, const char *pattern); /* 212 */ int (*tcl_RegExpExec) (Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start); /* 213 */ int (*tcl_RegExpMatch) (Tcl_Interp *interp, const char *text, const char *pattern); /* 214 */ void (*tcl_RegExpRange) (Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr); /* 215 */ void (*tcl_Release) (ClientData clientData); /* 216 */ void (*tcl_ResetResult) (Tcl_Interp *interp); /* 217 */ int (*tcl_ScanElement) (const char *src, int *flagPtr); /* 218 */ int (*tcl_ScanCountedElement) (const char *src, int length, int *flagPtr); /* 219 */ int (*tcl_SeekOld) (Tcl_Channel chan, int offset, int mode); /* 220 */ int (*tcl_ServiceAll) (void); /* 221 */ int (*tcl_ServiceEvent) (int flags); /* 222 */ void (*tcl_SetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 223 */ void (*tcl_SetChannelBufferSize) (Tcl_Channel chan, int sz); /* 224 */ int (*tcl_SetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue); /* 225 */ int (*tcl_SetCommandInfo) (Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr); /* 226 */ void (*tcl_SetErrno) (int err); /* 227 */ void (*tcl_SetErrorCode) (Tcl_Interp *interp, ...); /* 228 */ void (*tcl_SetMaxBlockTime) (const Tcl_Time *timePtr); /* 229 */ void (*tcl_SetPanicProc) (TCL_NORETURN1 Tcl_PanicProc *panicProc); /* 230 */ int (*tcl_SetRecursionLimit) (Tcl_Interp *interp, int depth); /* 231 */ void (*tcl_SetResult) (Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc); /* 232 */ int (*tcl_SetServiceMode) (int mode); /* 233 */ void (*tcl_SetObjErrorCode) (Tcl_Interp *interp, Tcl_Obj *errorObjPtr); /* 234 */ void (*tcl_SetObjResult) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr); /* 235 */ void (*tcl_SetStdChannel) (Tcl_Channel channel, int type); /* 236 */ CONST84_RETURN char * (*tcl_SetVar) (Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 237 */ CONST84_RETURN char * (*tcl_SetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags); /* 238 */ CONST84_RETURN char * (*tcl_SignalId) (int sig); /* 239 */ CONST84_RETURN char * (*tcl_SignalMsg) (int sig); /* 240 */ void (*tcl_SourceRCFile) (Tcl_Interp *interp); /* 241 */ int (*tcl_SplitList) (Tcl_Interp *interp, const char *listStr, int *argcPtr, CONST84 char ***argvPtr); /* 242 */ void (*tcl_SplitPath) (const char *path, int *argcPtr, CONST84 char ***argvPtr); /* 243 */ void (*tcl_StaticPackage) (Tcl_Interp *interp, const char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc); /* 244 */ int (*tcl_StringMatch) (const char *str, const char *pattern); /* 245 */ int (*tcl_TellOld) (Tcl_Channel chan); /* 246 */ int (*tcl_TraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 247 */ int (*tcl_TraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 248 */ char * (*tcl_TranslateFileName) (Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr); /* 249 */ int (*tcl_Ungets) (Tcl_Channel chan, const char *str, int len, int atHead); /* 250 */ void (*tcl_UnlinkVar) (Tcl_Interp *interp, const char *varName); /* 251 */ int (*tcl_UnregisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 252 */ int (*tcl_UnsetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 253 */ int (*tcl_UnsetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 254 */ void (*tcl_UntraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 255 */ void (*tcl_UntraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 256 */ void (*tcl_UpdateLinkedVar) (Tcl_Interp *interp, const char *varName); /* 257 */ int (*tcl_UpVar) (Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 258 */ int (*tcl_UpVar2) (Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags); /* 259 */ int (*tcl_VarEval) (Tcl_Interp *interp, ...); /* 260 */ ClientData (*tcl_VarTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 261 */ ClientData (*tcl_VarTraceInfo2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 262 */ int (*tcl_Write) (Tcl_Channel chan, const char *s, int slen); /* 263 */ void (*tcl_WrongNumArgs) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *message); /* 264 */ int (*tcl_DumpActiveMemory) (const char *fileName); /* 265 */ void (*tcl_ValidateAllMemory) (const char *file, int line); /* 266 */ void (*tcl_AppendResultVA) (Tcl_Interp *interp, va_list argList); /* 267 */ void (*tcl_AppendStringsToObjVA) (Tcl_Obj *objPtr, va_list argList); /* 268 */ char * (*tcl_HashStats) (Tcl_HashTable *tablePtr); /* 269 */ CONST84_RETURN char * (*tcl_ParseVar) (Tcl_Interp *interp, const char *start, CONST84 char **termPtr); /* 270 */ CONST84_RETURN char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */ CONST84_RETURN char * (*tcl_PkgPresentEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 272 */ int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */ CONST84_RETURN char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */ void (*tcl_SetErrorCodeVA) (Tcl_Interp *interp, va_list argList); /* 275 */ int (*tcl_VarEvalVA) (Tcl_Interp *interp, va_list argList); /* 276 */ Tcl_Pid (*tcl_WaitPid) (Tcl_Pid pid, int *statPtr, int options); /* 277 */ TCL_NORETURN1 void (*tcl_PanicVA) (const char *format, va_list argList); /* 278 */ void (*tcl_GetVersion) (int *major, int *minor, int *patchLevel, int *type); /* 279 */ void (*tcl_InitMemory) (Tcl_Interp *interp); /* 280 */ Tcl_Channel (*tcl_StackChannel) (Tcl_Interp *interp, const Tcl_ChannelType *typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan); /* 281 */ int (*tcl_UnstackChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 282 */ Tcl_Channel (*tcl_GetStackedChannel) (Tcl_Channel chan); /* 283 */ void (*tcl_SetMainLoop) (Tcl_MainLoopProc *proc); /* 284 */ void (*reserved285)(void); void (*tcl_AppendObjToObj) (Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr); /* 286 */ Tcl_Encoding (*tcl_CreateEncoding) (const Tcl_EncodingType *typePtr); /* 287 */ void (*tcl_CreateThreadExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 288 */ void (*tcl_DeleteThreadExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 289 */ void (*tcl_DiscardResult) (Tcl_SavedResult *statePtr); /* 290 */ int (*tcl_EvalEx) (Tcl_Interp *interp, const char *script, int numBytes, int flags); /* 291 */ int (*tcl_EvalObjv) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 292 */ int (*tcl_EvalObjEx) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 293 */ void (*tcl_ExitThread) (int status); /* 294 */ int (*tcl_ExternalToUtf) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 295 */ char * (*tcl_ExternalToUtfDString) (Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 296 */ void (*tcl_FinalizeThread) (void); /* 297 */ void (*tcl_FinalizeNotifier) (ClientData clientData); /* 298 */ void (*tcl_FreeEncoding) (Tcl_Encoding encoding); /* 299 */ Tcl_ThreadId (*tcl_GetCurrentThread) (void); /* 300 */ Tcl_Encoding (*tcl_GetEncoding) (Tcl_Interp *interp, const char *name); /* 301 */ CONST84_RETURN char * (*tcl_GetEncodingName) (Tcl_Encoding encoding); /* 302 */ void (*tcl_GetEncodingNames) (Tcl_Interp *interp); /* 303 */ int (*tcl_GetIndexFromObjStruct) (Tcl_Interp *interp, Tcl_Obj *objPtr, const void *tablePtr, int offset, const char *msg, int flags, int *indexPtr); /* 304 */ void * (*tcl_GetThreadData) (Tcl_ThreadDataKey *keyPtr, int size); /* 305 */ Tcl_Obj * (*tcl_GetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 306 */ ClientData (*tcl_InitNotifier) (void); /* 307 */ void (*tcl_MutexLock) (Tcl_Mutex *mutexPtr); /* 308 */ void (*tcl_MutexUnlock) (Tcl_Mutex *mutexPtr); /* 309 */ void (*tcl_ConditionNotify) (Tcl_Condition *condPtr); /* 310 */ void (*tcl_ConditionWait) (Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); /* 311 */ int (*tcl_NumUtfChars) (const char *src, int length); /* 312 */ int (*tcl_ReadChars) (Tcl_Channel channel, Tcl_Obj *objPtr, int charsToRead, int appendFlag); /* 313 */ void (*tcl_RestoreResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 314 */ void (*tcl_SaveResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 315 */ int (*tcl_SetSystemEncoding) (Tcl_Interp *interp, const char *name); /* 316 */ Tcl_Obj * (*tcl_SetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, Tcl_Obj *newValuePtr, int flags); /* 317 */ void (*tcl_ThreadAlert) (Tcl_ThreadId threadId); /* 318 */ void (*tcl_ThreadQueueEvent) (Tcl_ThreadId threadId, Tcl_Event *evPtr, Tcl_QueuePosition position); /* 319 */ Tcl_UniChar (*tcl_UniCharAtIndex) (const char *src, int index); /* 320 */ Tcl_UniChar (*tcl_UniCharToLower) (int ch); /* 321 */ Tcl_UniChar (*tcl_UniCharToTitle) (int ch); /* 322 */ Tcl_UniChar (*tcl_UniCharToUpper) (int ch); /* 323 */ int (*tcl_UniCharToUtf) (int ch, char *buf); /* 324 */ CONST84_RETURN char * (*tcl_UtfAtIndex) (const char *src, int index); /* 325 */ int (*tcl_UtfCharComplete) (const char *src, int length); /* 326 */ int (*tcl_UtfBackslash) (const char *src, int *readPtr, char *dst); /* 327 */ CONST84_RETURN char * (*tcl_UtfFindFirst) (const char *src, int ch); /* 328 */ CONST84_RETURN char * (*tcl_UtfFindLast) (const char *src, int ch); /* 329 */ CONST84_RETURN char * (*tcl_UtfNext) (const char *src); /* 330 */ CONST84_RETURN char * (*tcl_UtfPrev) (const char *src, const char *start); /* 331 */ int (*tcl_UtfToExternal) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 332 */ char * (*tcl_UtfToExternalDString) (Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 333 */ int (*tcl_UtfToLower) (char *src); /* 334 */ int (*tcl_UtfToTitle) (char *src); /* 335 */ int (*tcl_UtfToUniChar) (const char *src, Tcl_UniChar *chPtr); /* 336 */ int (*tcl_UtfToUpper) (char *src); /* 337 */ int (*tcl_WriteChars) (Tcl_Channel chan, const char *src, int srcLen); /* 338 */ int (*tcl_WriteObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 339 */ char * (*tcl_GetString) (Tcl_Obj *objPtr); /* 340 */ CONST84_RETURN char * (*tcl_GetDefaultEncodingDir) (void); /* 341 */ void (*tcl_SetDefaultEncodingDir) (const char *path); /* 342 */ void (*tcl_AlertNotifier) (ClientData clientData); /* 343 */ void (*tcl_ServiceModeHook) (int mode); /* 344 */ int (*tcl_UniCharIsAlnum) (int ch); /* 345 */ int (*tcl_UniCharIsAlpha) (int ch); /* 346 */ int (*tcl_UniCharIsDigit) (int ch); /* 347 */ int (*tcl_UniCharIsLower) (int ch); /* 348 */ int (*tcl_UniCharIsSpace) (int ch); /* 349 */ int (*tcl_UniCharIsUpper) (int ch); /* 350 */ int (*tcl_UniCharIsWordChar) (int ch); /* 351 */ int (*tcl_UniCharLen) (const Tcl_UniChar *uniStr); /* 352 */ int (*tcl_UniCharNcmp) (const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 353 */ char * (*tcl_UniCharToUtfDString) (const Tcl_UniChar *uniStr, int uniLength, Tcl_DString *dsPtr); /* 354 */ Tcl_UniChar * (*tcl_UtfToUniCharDString) (const char *src, int length, Tcl_DString *dsPtr); /* 355 */ Tcl_RegExp (*tcl_GetRegExpFromObj) (Tcl_Interp *interp, Tcl_Obj *patObj, int flags); /* 356 */ Tcl_Obj * (*tcl_EvalTokens) (Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 357 */ void (*tcl_FreeParse) (Tcl_Parse *parsePtr); /* 358 */ void (*tcl_LogCommandInfo) (Tcl_Interp *interp, const char *script, const char *command, int length); /* 359 */ int (*tcl_ParseBraces) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 360 */ int (*tcl_ParseCommand) (Tcl_Interp *interp, const char *start, int numBytes, int nested, Tcl_Parse *parsePtr); /* 361 */ int (*tcl_ParseExpr) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr); /* 362 */ int (*tcl_ParseQuotedString) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 363 */ int (*tcl_ParseVarName) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append); /* 364 */ char * (*tcl_GetCwd) (Tcl_Interp *interp, Tcl_DString *cwdPtr); /* 365 */ int (*tcl_Chdir) (const char *dirName); /* 366 */ int (*tcl_Access) (const char *path, int mode); /* 367 */ int (*tcl_Stat) (const char *path, struct stat *bufPtr); /* 368 */ int (*tcl_UtfNcmp) (const char *s1, const char *s2, unsigned long n); /* 369 */ int (*tcl_UtfNcasecmp) (const char *s1, const char *s2, unsigned long n); /* 370 */ int (*tcl_StringCaseMatch) (const char *str, const char *pattern, int nocase); /* 371 */ int (*tcl_UniCharIsControl) (int ch); /* 372 */ int (*tcl_UniCharIsGraph) (int ch); /* 373 */ int (*tcl_UniCharIsPrint) (int ch); /* 374 */ int (*tcl_UniCharIsPunct) (int ch); /* 375 */ int (*tcl_RegExpExecObj) (Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, int offset, int nmatches, int flags); /* 376 */ void (*tcl_RegExpGetInfo) (Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr); /* 377 */ Tcl_Obj * (*tcl_NewUnicodeObj) (const Tcl_UniChar *unicode, int numChars); /* 378 */ void (*tcl_SetUnicodeObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int numChars); /* 379 */ int (*tcl_GetCharLength) (Tcl_Obj *objPtr); /* 380 */ Tcl_UniChar (*tcl_GetUniChar) (Tcl_Obj *objPtr, int index); /* 381 */ Tcl_UniChar * (*tcl_GetUnicode) (Tcl_Obj *objPtr); /* 382 */ Tcl_Obj * (*tcl_GetRange) (Tcl_Obj *objPtr, int first, int last); /* 383 */ void (*tcl_AppendUnicodeToObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int length); /* 384 */ int (*tcl_RegExpMatchObj) (Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj); /* 385 */ void (*tcl_SetNotifier) (Tcl_NotifierProcs *notifierProcPtr); /* 386 */ Tcl_Mutex * (*tcl_GetAllocMutex) (void); /* 387 */ int (*tcl_GetChannelNames) (Tcl_Interp *interp); /* 388 */ int (*tcl_GetChannelNamesEx) (Tcl_Interp *interp, const char *pattern); /* 389 */ int (*tcl_ProcObjCmd) (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* 390 */ void (*tcl_ConditionFinalize) (Tcl_Condition *condPtr); /* 391 */ void (*tcl_MutexFinalize) (Tcl_Mutex *mutex); /* 392 */ int (*tcl_CreateThread) (Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, ClientData clientData, int stackSize, int flags); /* 393 */ int (*tcl_ReadRaw) (Tcl_Channel chan, char *dst, int bytesToRead); /* 394 */ int (*tcl_WriteRaw) (Tcl_Channel chan, const char *src, int srcLen); /* 395 */ Tcl_Channel (*tcl_GetTopChannel) (Tcl_Channel chan); /* 396 */ int (*tcl_ChannelBuffered) (Tcl_Channel chan); /* 397 */ CONST84_RETURN char * (*tcl_ChannelName) (const Tcl_ChannelType *chanTypePtr); /* 398 */ Tcl_ChannelTypeVersion (*tcl_ChannelVersion) (const Tcl_ChannelType *chanTypePtr); /* 399 */ Tcl_DriverBlockModeProc * (*tcl_ChannelBlockModeProc) (const Tcl_ChannelType *chanTypePtr); /* 400 */ Tcl_DriverCloseProc * (*tcl_ChannelCloseProc) (const Tcl_ChannelType *chanTypePtr); /* 401 */ Tcl_DriverClose2Proc * (*tcl_ChannelClose2Proc) (const Tcl_ChannelType *chanTypePtr); /* 402 */ Tcl_DriverInputProc * (*tcl_ChannelInputProc) (const Tcl_ChannelType *chanTypePtr); /* 403 */ Tcl_DriverOutputProc * (*tcl_ChannelOutputProc) (const Tcl_ChannelType *chanTypePtr); /* 404 */ Tcl_DriverSeekProc * (*tcl_ChannelSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 405 */ Tcl_DriverSetOptionProc * (*tcl_ChannelSetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 406 */ Tcl_DriverGetOptionProc * (*tcl_ChannelGetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 407 */ Tcl_DriverWatchProc * (*tcl_ChannelWatchProc) (const Tcl_ChannelType *chanTypePtr); /* 408 */ Tcl_DriverGetHandleProc * (*tcl_ChannelGetHandleProc) (const Tcl_ChannelType *chanTypePtr); /* 409 */ Tcl_DriverFlushProc * (*tcl_ChannelFlushProc) (const Tcl_ChannelType *chanTypePtr); /* 410 */ Tcl_DriverHandlerProc * (*tcl_ChannelHandlerProc) (const Tcl_ChannelType *chanTypePtr); /* 411 */ int (*tcl_JoinThread) (Tcl_ThreadId threadId, int *result); /* 412 */ int (*tcl_IsChannelShared) (Tcl_Channel channel); /* 413 */ int (*tcl_IsChannelRegistered) (Tcl_Interp *interp, Tcl_Channel channel); /* 414 */ void (*tcl_CutChannel) (Tcl_Channel channel); /* 415 */ void (*tcl_SpliceChannel) (Tcl_Channel channel); /* 416 */ void (*tcl_ClearChannelHandlers) (Tcl_Channel channel); /* 417 */ int (*tcl_IsChannelExisting) (const char *channelName); /* 418 */ int (*tcl_UniCharNcasecmp) (const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 419 */ int (*tcl_UniCharCaseMatch) (const Tcl_UniChar *uniStr, const Tcl_UniChar *uniPattern, int nocase); /* 420 */ Tcl_HashEntry * (*tcl_FindHashEntry) (Tcl_HashTable *tablePtr, const void *key); /* 421 */ Tcl_HashEntry * (*tcl_CreateHashEntry) (Tcl_HashTable *tablePtr, const void *key, int *newPtr); /* 422 */ void (*tcl_InitCustomHashTable) (Tcl_HashTable *tablePtr, int keyType, const Tcl_HashKeyType *typePtr); /* 423 */ void (*tcl_InitObjHashTable) (Tcl_HashTable *tablePtr); /* 424 */ ClientData (*tcl_CommandTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *procPtr, ClientData prevClientData); /* 425 */ int (*tcl_TraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 426 */ void (*tcl_UntraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 427 */ char * (*tcl_AttemptAlloc) (unsigned int size); /* 428 */ char * (*tcl_AttemptDbCkalloc) (unsigned int size, const char *file, int line); /* 429 */ char * (*tcl_AttemptRealloc) (char *ptr, unsigned int size); /* 430 */ char * (*tcl_AttemptDbCkrealloc) (char *ptr, unsigned int size, const char *file, int line); /* 431 */ int (*tcl_AttemptSetObjLength) (Tcl_Obj *objPtr, int length); /* 432 */ Tcl_ThreadId (*tcl_GetChannelThread) (Tcl_Channel channel); /* 433 */ Tcl_UniChar * (*tcl_GetUnicodeFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 434 */ int (*tcl_GetMathFuncInfo) (Tcl_Interp *interp, const char *name, int *numArgsPtr, Tcl_ValueType **argTypesPtr, Tcl_MathProc **procPtr, ClientData *clientDataPtr); /* 435 */ Tcl_Obj * (*tcl_ListMathFuncs) (Tcl_Interp *interp, const char *pattern); /* 436 */ Tcl_Obj * (*tcl_SubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 437 */ int (*tcl_DetachChannel) (Tcl_Interp *interp, Tcl_Channel channel); /* 438 */ int (*tcl_IsStandardChannel) (Tcl_Channel channel); /* 439 */ int (*tcl_FSCopyFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 440 */ int (*tcl_FSCopyDirectory) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); /* 441 */ int (*tcl_FSCreateDirectory) (Tcl_Obj *pathPtr); /* 442 */ int (*tcl_FSDeleteFile) (Tcl_Obj *pathPtr); /* 443 */ int (*tcl_FSLoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *sym1, const char *sym2, Tcl_PackageInitProc **proc1Ptr, Tcl_PackageInitProc **proc2Ptr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); /* 444 */ int (*tcl_FSMatchInDirectory) (Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); /* 445 */ Tcl_Obj * (*tcl_FSLink) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction); /* 446 */ int (*tcl_FSRemoveDirectory) (Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr); /* 447 */ int (*tcl_FSRenameFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 448 */ int (*tcl_FSLstat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 449 */ int (*tcl_FSUtime) (Tcl_Obj *pathPtr, struct utimbuf *tval); /* 450 */ int (*tcl_FSFileAttrsGet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 451 */ int (*tcl_FSFileAttrsSet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr); /* 452 */ const char *CONST86 * (*tcl_FSFileAttrStrings) (Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 453 */ int (*tcl_FSStat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 454 */ int (*tcl_FSAccess) (Tcl_Obj *pathPtr, int mode); /* 455 */ Tcl_Channel (*tcl_FSOpenFileChannel) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *modeString, int permissions); /* 456 */ Tcl_Obj * (*tcl_FSGetCwd) (Tcl_Interp *interp); /* 457 */ int (*tcl_FSChdir) (Tcl_Obj *pathPtr); /* 458 */ int (*tcl_FSConvertToPathType) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 459 */ Tcl_Obj * (*tcl_FSJoinPath) (Tcl_Obj *listObj, int elements); /* 460 */ Tcl_Obj * (*tcl_FSSplitPath) (Tcl_Obj *pathPtr, int *lenPtr); /* 461 */ int (*tcl_FSEqualPaths) (Tcl_Obj *firstPtr, Tcl_Obj *secondPtr); /* 462 */ Tcl_Obj * (*tcl_FSGetNormalizedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 463 */ Tcl_Obj * (*tcl_FSJoinToPath) (Tcl_Obj *pathPtr, int objc, Tcl_Obj *const objv[]); /* 464 */ ClientData (*tcl_FSGetInternalRep) (Tcl_Obj *pathPtr, const Tcl_Filesystem *fsPtr); /* 465 */ Tcl_Obj * (*tcl_FSGetTranslatedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 466 */ int (*tcl_FSEvalFile) (Tcl_Interp *interp, Tcl_Obj *fileName); /* 467 */ Tcl_Obj * (*tcl_FSNewNativePath) (const Tcl_Filesystem *fromFilesystem, ClientData clientData); /* 468 */ const void * (*tcl_FSGetNativePath) (Tcl_Obj *pathPtr); /* 469 */ Tcl_Obj * (*tcl_FSFileSystemInfo) (Tcl_Obj *pathPtr); /* 470 */ Tcl_Obj * (*tcl_FSPathSeparator) (Tcl_Obj *pathPtr); /* 471 */ Tcl_Obj * (*tcl_FSListVolumes) (void); /* 472 */ int (*tcl_FSRegister) (ClientData clientData, const Tcl_Filesystem *fsPtr); /* 473 */ int (*tcl_FSUnregister) (const Tcl_Filesystem *fsPtr); /* 474 */ ClientData (*tcl_FSData) (const Tcl_Filesystem *fsPtr); /* 475 */ const char * (*tcl_FSGetTranslatedStringPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 476 */ CONST86 Tcl_Filesystem * (*tcl_FSGetFileSystemForPath) (Tcl_Obj *pathPtr); /* 477 */ Tcl_PathType (*tcl_FSGetPathType) (Tcl_Obj *pathPtr); /* 478 */ int (*tcl_OutputBuffered) (Tcl_Channel chan); /* 479 */ void (*tcl_FSMountsChanged) (const Tcl_Filesystem *fsPtr); /* 480 */ int (*tcl_EvalTokensStandard) (Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 481 */ void (*tcl_GetTime) (Tcl_Time *timeBuf); /* 482 */ Tcl_Trace (*tcl_CreateObjTrace) (Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc *objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 483 */ int (*tcl_GetCommandInfoFromToken) (Tcl_Command token, Tcl_CmdInfo *infoPtr); /* 484 */ int (*tcl_SetCommandInfoFromToken) (Tcl_Command token, const Tcl_CmdInfo *infoPtr); /* 485 */ Tcl_Obj * (*tcl_DbNewWideIntObj) (Tcl_WideInt wideValue, const char *file, int line); /* 486 */ int (*tcl_GetWideIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr); /* 487 */ Tcl_Obj * (*tcl_NewWideIntObj) (Tcl_WideInt wideValue); /* 488 */ void (*tcl_SetWideIntObj) (Tcl_Obj *objPtr, Tcl_WideInt wideValue); /* 489 */ Tcl_StatBuf * (*tcl_AllocStatBuf) (void); /* 490 */ Tcl_WideInt (*tcl_Seek) (Tcl_Channel chan, Tcl_WideInt offset, int mode); /* 491 */ Tcl_WideInt (*tcl_Tell) (Tcl_Channel chan); /* 492 */ Tcl_DriverWideSeekProc * (*tcl_ChannelWideSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 493 */ int (*tcl_DictObjPut) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); /* 494 */ int (*tcl_DictObjGet) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); /* 495 */ int (*tcl_DictObjRemove) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); /* 496 */ int (*tcl_DictObjSize) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int *sizePtr); /* 497 */ int (*tcl_DictObjFirst) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 498 */ void (*tcl_DictObjNext) (Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 499 */ void (*tcl_DictObjDone) (Tcl_DictSearch *searchPtr); /* 500 */ int (*tcl_DictObjPutKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); /* 501 */ int (*tcl_DictObjRemoveKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv); /* 502 */ Tcl_Obj * (*tcl_NewDictObj) (void); /* 503 */ Tcl_Obj * (*tcl_DbNewDictObj) (const char *file, int line); /* 504 */ void (*tcl_RegisterConfig) (Tcl_Interp *interp, const char *pkgName, const Tcl_Config *configuration, const char *valEncoding); /* 505 */ Tcl_Namespace * (*tcl_CreateNamespace) (Tcl_Interp *interp, const char *name, ClientData clientData, Tcl_NamespaceDeleteProc *deleteProc); /* 506 */ void (*tcl_DeleteNamespace) (Tcl_Namespace *nsPtr); /* 507 */ int (*tcl_AppendExportList) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); /* 508 */ int (*tcl_Export) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int resetListFirst); /* 509 */ int (*tcl_Import) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int allowOverwrite); /* 510 */ int (*tcl_ForgetImport) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern); /* 511 */ Tcl_Namespace * (*tcl_GetCurrentNamespace) (Tcl_Interp *interp); /* 512 */ Tcl_Namespace * (*tcl_GetGlobalNamespace) (Tcl_Interp *interp); /* 513 */ Tcl_Namespace * (*tcl_FindNamespace) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 514 */ Tcl_Command (*tcl_FindCommand) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 515 */ Tcl_Command (*tcl_GetCommandFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 516 */ void (*tcl_GetCommandFullName) (Tcl_Interp *interp, Tcl_Command command, Tcl_Obj *objPtr); /* 517 */ int (*tcl_FSEvalFileEx) (Tcl_Interp *interp, Tcl_Obj *fileName, const char *encodingName); /* 518 */ Tcl_ExitProc * (*tcl_SetExitProc) (TCL_NORETURN1 Tcl_ExitProc *proc); /* 519 */ void (*tcl_LimitAddHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData, Tcl_LimitHandlerDeleteProc *deleteProc); /* 520 */ void (*tcl_LimitRemoveHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData); /* 521 */ int (*tcl_LimitReady) (Tcl_Interp *interp); /* 522 */ int (*tcl_LimitCheck) (Tcl_Interp *interp); /* 523 */ int (*tcl_LimitExceeded) (Tcl_Interp *interp); /* 524 */ void (*tcl_LimitSetCommands) (Tcl_Interp *interp, int commandLimit); /* 525 */ void (*tcl_LimitSetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 526 */ void (*tcl_LimitSetGranularity) (Tcl_Interp *interp, int type, int granularity); /* 527 */ int (*tcl_LimitTypeEnabled) (Tcl_Interp *interp, int type); /* 528 */ int (*tcl_LimitTypeExceeded) (Tcl_Interp *interp, int type); /* 529 */ void (*tcl_LimitTypeSet) (Tcl_Interp *interp, int type); /* 530 */ void (*tcl_LimitTypeReset) (Tcl_Interp *interp, int type); /* 531 */ int (*tcl_LimitGetCommands) (Tcl_Interp *interp); /* 532 */ void (*tcl_LimitGetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 533 */ int (*tcl_LimitGetGranularity) (Tcl_Interp *interp, int type); /* 534 */ Tcl_InterpState (*tcl_SaveInterpState) (Tcl_Interp *interp, int status); /* 535 */ int (*tcl_RestoreInterpState) (Tcl_Interp *interp, Tcl_InterpState state); /* 536 */ void (*tcl_DiscardInterpState) (Tcl_InterpState state); /* 537 */ int (*tcl_SetReturnOptions) (Tcl_Interp *interp, Tcl_Obj *options); /* 538 */ Tcl_Obj * (*tcl_GetReturnOptions) (Tcl_Interp *interp, int result); /* 539 */ int (*tcl_IsEnsemble) (Tcl_Command token); /* 540 */ Tcl_Command (*tcl_CreateEnsemble) (Tcl_Interp *interp, const char *name, Tcl_Namespace *namespacePtr, int flags); /* 541 */ Tcl_Command (*tcl_FindEnsemble) (Tcl_Interp *interp, Tcl_Obj *cmdNameObj, int flags); /* 542 */ int (*tcl_SetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *subcmdList); /* 543 */ int (*tcl_SetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *mapDict); /* 544 */ int (*tcl_SetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *unknownList); /* 545 */ int (*tcl_SetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int flags); /* 546 */ int (*tcl_GetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr); /* 547 */ int (*tcl_GetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr); /* 548 */ int (*tcl_GetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr); /* 549 */ int (*tcl_GetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 550 */ int (*tcl_GetEnsembleNamespace) (Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 551 */ void (*tcl_SetTimeProc) (Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, ClientData clientData); /* 552 */ void (*tcl_QueryTimeProc) (Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, ClientData *clientData); /* 553 */ Tcl_DriverThreadActionProc * (*tcl_ChannelThreadActionProc) (const Tcl_ChannelType *chanTypePtr); /* 554 */ Tcl_Obj * (*tcl_NewBignumObj) (mp_int *value); /* 555 */ Tcl_Obj * (*tcl_DbNewBignumObj) (mp_int *value, const char *file, int line); /* 556 */ void (*tcl_SetBignumObj) (Tcl_Obj *obj, mp_int *value); /* 557 */ int (*tcl_GetBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 558 */ int (*tcl_TakeBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 559 */ int (*tcl_TruncateChannel) (Tcl_Channel chan, Tcl_WideInt length); /* 560 */ Tcl_DriverTruncateProc * (*tcl_ChannelTruncateProc) (const Tcl_ChannelType *chanTypePtr); /* 561 */ void (*tcl_SetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj *msg); /* 562 */ void (*tcl_GetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj **msg); /* 563 */ void (*tcl_SetChannelError) (Tcl_Channel chan, Tcl_Obj *msg); /* 564 */ void (*tcl_GetChannelError) (Tcl_Channel chan, Tcl_Obj **msg); /* 565 */ int (*tcl_InitBignumFromDouble) (Tcl_Interp *interp, double initval, mp_int *toInit); /* 566 */ Tcl_Obj * (*tcl_GetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr); /* 567 */ int (*tcl_SetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); /* 568 */ int (*tcl_GetEncodingFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); /* 569 */ Tcl_Obj * (*tcl_GetEncodingSearchPath) (void); /* 570 */ int (*tcl_SetEncodingSearchPath) (Tcl_Obj *searchPath); /* 571 */ const char * (*tcl_GetEncodingNameFromEnvironment) (Tcl_DString *bufPtr); /* 572 */ int (*tcl_PkgRequireProc) (Tcl_Interp *interp, const char *name, int objc, Tcl_Obj *const objv[], void *clientDataPtr); /* 573 */ void (*tcl_AppendObjToErrorInfo) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 574 */ void (*tcl_AppendLimitedToObj) (Tcl_Obj *objPtr, const char *bytes, int length, int limit, const char *ellipsis); /* 575 */ Tcl_Obj * (*tcl_Format) (Tcl_Interp *interp, const char *format, int objc, Tcl_Obj *const objv[]); /* 576 */ int (*tcl_AppendFormatToObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *format, int objc, Tcl_Obj *const objv[]); /* 577 */ Tcl_Obj * (*tcl_ObjPrintf) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 578 */ void (*tcl_AppendPrintfToObj) (Tcl_Obj *objPtr, const char *format, ...) TCL_FORMAT_PRINTF(2, 3); /* 579 */ int (*tcl_CancelEval) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr, ClientData clientData, int flags); /* 580 */ int (*tcl_Canceled) (Tcl_Interp *interp, int flags); /* 581 */ int (*tcl_CreatePipe) (Tcl_Interp *interp, Tcl_Channel *rchan, Tcl_Channel *wchan, int flags); /* 582 */ Tcl_Command (*tcl_NRCreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 583 */ int (*tcl_NREvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 584 */ int (*tcl_NREvalObjv) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 585 */ int (*tcl_NRCmdSwap) (Tcl_Interp *interp, Tcl_Command cmd, int objc, Tcl_Obj *const objv[], int flags); /* 586 */ void (*tcl_NRAddCallback) (Tcl_Interp *interp, Tcl_NRPostProc *postProcPtr, ClientData data0, ClientData data1, ClientData data2, ClientData data3); /* 587 */ int (*tcl_NRCallObjProc) (Tcl_Interp *interp, Tcl_ObjCmdProc *objProc, ClientData clientData, int objc, Tcl_Obj *const objv[]); /* 588 */ unsigned (*tcl_GetFSDeviceFromStat) (const Tcl_StatBuf *statPtr); /* 589 */ unsigned (*tcl_GetFSInodeFromStat) (const Tcl_StatBuf *statPtr); /* 590 */ unsigned (*tcl_GetModeFromStat) (const Tcl_StatBuf *statPtr); /* 591 */ int (*tcl_GetLinkCountFromStat) (const Tcl_StatBuf *statPtr); /* 592 */ int (*tcl_GetUserIdFromStat) (const Tcl_StatBuf *statPtr); /* 593 */ int (*tcl_GetGroupIdFromStat) (const Tcl_StatBuf *statPtr); /* 594 */ int (*tcl_GetDeviceTypeFromStat) (const Tcl_StatBuf *statPtr); /* 595 */ Tcl_WideInt (*tcl_GetAccessTimeFromStat) (const Tcl_StatBuf *statPtr); /* 596 */ Tcl_WideInt (*tcl_GetModificationTimeFromStat) (const Tcl_StatBuf *statPtr); /* 597 */ Tcl_WideInt (*tcl_GetChangeTimeFromStat) (const Tcl_StatBuf *statPtr); /* 598 */ Tcl_WideUInt (*tcl_GetSizeFromStat) (const Tcl_StatBuf *statPtr); /* 599 */ Tcl_WideUInt (*tcl_GetBlocksFromStat) (const Tcl_StatBuf *statPtr); /* 600 */ unsigned (*tcl_GetBlockSizeFromStat) (const Tcl_StatBuf *statPtr); /* 601 */ int (*tcl_SetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *paramList); /* 602 */ int (*tcl_GetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **paramListPtr); /* 603 */ int (*tcl_ParseArgsObjv) (Tcl_Interp *interp, const Tcl_ArgvInfo *argTable, int *objcPtr, Tcl_Obj *const *objv, Tcl_Obj ***remObjv); /* 604 */ int (*tcl_GetErrorLine) (Tcl_Interp *interp); /* 605 */ void (*tcl_SetErrorLine) (Tcl_Interp *interp, int lineNum); /* 606 */ void (*tcl_TransferResult) (Tcl_Interp *sourceInterp, int result, Tcl_Interp *targetInterp); /* 607 */ int (*tcl_InterpActive) (Tcl_Interp *interp); /* 608 */ void (*tcl_BackgroundException) (Tcl_Interp *interp, int code); /* 609 */ int (*tcl_ZlibDeflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int level, Tcl_Obj *gzipHeaderDictObj); /* 610 */ int (*tcl_ZlibInflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int buffersize, Tcl_Obj *gzipHeaderDictObj); /* 611 */ unsigned int (*tcl_ZlibCRC32) (unsigned int crc, const unsigned char *buf, int len); /* 612 */ unsigned int (*tcl_ZlibAdler32) (unsigned int adler, const unsigned char *buf, int len); /* 613 */ int (*tcl_ZlibStreamInit) (Tcl_Interp *interp, int mode, int format, int level, Tcl_Obj *dictObj, Tcl_ZlibStream *zshandle); /* 614 */ Tcl_Obj * (*tcl_ZlibStreamGetCommandName) (Tcl_ZlibStream zshandle); /* 615 */ int (*tcl_ZlibStreamEof) (Tcl_ZlibStream zshandle); /* 616 */ int (*tcl_ZlibStreamChecksum) (Tcl_ZlibStream zshandle); /* 617 */ int (*tcl_ZlibStreamPut) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int flush); /* 618 */ int (*tcl_ZlibStreamGet) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int count); /* 619 */ int (*tcl_ZlibStreamClose) (Tcl_ZlibStream zshandle); /* 620 */ int (*tcl_ZlibStreamReset) (Tcl_ZlibStream zshandle); /* 621 */ void (*tcl_SetStartupScript) (Tcl_Obj *path, const char *encoding); /* 622 */ Tcl_Obj * (*tcl_GetStartupScript) (const char **encodingPtr); /* 623 */ int (*tcl_CloseEx) (Tcl_Interp *interp, Tcl_Channel chan, int flags); /* 624 */ int (*tcl_NRExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *resultPtr); /* 625 */ int (*tcl_NRSubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 626 */ int (*tcl_LoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *const symv[], int flags, void *procPtrs, Tcl_LoadHandle *handlePtr); /* 627 */ void * (*tcl_FindSymbol) (Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 628 */ int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */ void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */ } TclStubs; extern const TclStubs *tclStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_TCL_STUBS) /* * Inline function declarations: */ #define Tcl_PkgProvideEx \ (tclStubsPtr->tcl_PkgProvideEx) /* 0 */ #define Tcl_PkgRequireEx \ (tclStubsPtr->tcl_PkgRequireEx) /* 1 */ #define Tcl_Panic \ (tclStubsPtr->tcl_Panic) /* 2 */ #define Tcl_Alloc \ (tclStubsPtr->tcl_Alloc) /* 3 */ #define Tcl_Free \ (tclStubsPtr->tcl_Free) /* 4 */ #define Tcl_Realloc \ (tclStubsPtr->tcl_Realloc) /* 5 */ #define Tcl_DbCkalloc \ (tclStubsPtr->tcl_DbCkalloc) /* 6 */ #define Tcl_DbCkfree \ (tclStubsPtr->tcl_DbCkfree) /* 7 */ #define Tcl_DbCkrealloc \ (tclStubsPtr->tcl_DbCkrealloc) /* 8 */ #if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ #define Tcl_CreateFileHandler \ (tclStubsPtr->tcl_CreateFileHandler) /* 9 */ #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ #define Tcl_CreateFileHandler \ (tclStubsPtr->tcl_CreateFileHandler) /* 9 */ #endif /* MACOSX */ #if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ #define Tcl_DeleteFileHandler \ (tclStubsPtr->tcl_DeleteFileHandler) /* 10 */ #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ #define Tcl_DeleteFileHandler \ (tclStubsPtr->tcl_DeleteFileHandler) /* 10 */ #endif /* MACOSX */ #define Tcl_SetTimer \ (tclStubsPtr->tcl_SetTimer) /* 11 */ #define Tcl_Sleep \ (tclStubsPtr->tcl_Sleep) /* 12 */ #define Tcl_WaitForEvent \ (tclStubsPtr->tcl_WaitForEvent) /* 13 */ #define Tcl_AppendAllObjTypes \ (tclStubsPtr->tcl_AppendAllObjTypes) /* 14 */ #define Tcl_AppendStringsToObj \ (tclStubsPtr->tcl_AppendStringsToObj) /* 15 */ #define Tcl_AppendToObj \ (tclStubsPtr->tcl_AppendToObj) /* 16 */ #define Tcl_ConcatObj \ (tclStubsPtr->tcl_ConcatObj) /* 17 */ #define Tcl_ConvertToType \ (tclStubsPtr->tcl_ConvertToType) /* 18 */ #define Tcl_DbDecrRefCount \ (tclStubsPtr->tcl_DbDecrRefCount) /* 19 */ #define Tcl_DbIncrRefCount \ (tclStubsPtr->tcl_DbIncrRefCount) /* 20 */ #define Tcl_DbIsShared \ (tclStubsPtr->tcl_DbIsShared) /* 21 */ #define Tcl_DbNewBooleanObj \ (tclStubsPtr->tcl_DbNewBooleanObj) /* 22 */ #define Tcl_DbNewByteArrayObj \ (tclStubsPtr->tcl_DbNewByteArrayObj) /* 23 */ #define Tcl_DbNewDoubleObj \ (tclStubsPtr->tcl_DbNewDoubleObj) /* 24 */ #define Tcl_DbNewListObj \ (tclStubsPtr->tcl_DbNewListObj) /* 25 */ #define Tcl_DbNewLongObj \ (tclStubsPtr->tcl_DbNewLongObj) /* 26 */ #define Tcl_DbNewObj \ (tclStubsPtr->tcl_DbNewObj) /* 27 */ #define Tcl_DbNewStringObj \ (tclStubsPtr->tcl_DbNewStringObj) /* 28 */ #define Tcl_DuplicateObj \ (tclStubsPtr->tcl_DuplicateObj) /* 29 */ #define TclFreeObj \ (tclStubsPtr->tclFreeObj) /* 30 */ #define Tcl_GetBoolean \ (tclStubsPtr->tcl_GetBoolean) /* 31 */ #define Tcl_GetBooleanFromObj \ (tclStubsPtr->tcl_GetBooleanFromObj) /* 32 */ #define Tcl_GetByteArrayFromObj \ (tclStubsPtr->tcl_GetByteArrayFromObj) /* 33 */ #define Tcl_GetDouble \ (tclStubsPtr->tcl_GetDouble) /* 34 */ #define Tcl_GetDoubleFromObj \ (tclStubsPtr->tcl_GetDoubleFromObj) /* 35 */ #define Tcl_GetIndexFromObj \ (tclStubsPtr->tcl_GetIndexFromObj) /* 36 */ #define Tcl_GetInt \ (tclStubsPtr->tcl_GetInt) /* 37 */ #define Tcl_GetIntFromObj \ (tclStubsPtr->tcl_GetIntFromObj) /* 38 */ #define Tcl_GetLongFromObj \ (tclStubsPtr->tcl_GetLongFromObj) /* 39 */ #define Tcl_GetObjType \ (tclStubsPtr->tcl_GetObjType) /* 40 */ #define Tcl_GetStringFromObj \ (tclStubsPtr->tcl_GetStringFromObj) /* 41 */ #define Tcl_InvalidateStringRep \ (tclStubsPtr->tcl_InvalidateStringRep) /* 42 */ #define Tcl_ListObjAppendList \ (tclStubsPtr->tcl_ListObjAppendList) /* 43 */ #define Tcl_ListObjAppendElement \ (tclStubsPtr->tcl_ListObjAppendElement) /* 44 */ #define Tcl_ListObjGetElements \ (tclStubsPtr->tcl_ListObjGetElements) /* 45 */ #define Tcl_ListObjIndex \ (tclStubsPtr->tcl_ListObjIndex) /* 46 */ #define Tcl_ListObjLength \ (tclStubsPtr->tcl_ListObjLength) /* 47 */ #define Tcl_ListObjReplace \ (tclStubsPtr->tcl_ListObjReplace) /* 48 */ #define Tcl_NewBooleanObj \ (tclStubsPtr->tcl_NewBooleanObj) /* 49 */ #define Tcl_NewByteArrayObj \ (tclStubsPtr->tcl_NewByteArrayObj) /* 50 */ #define Tcl_NewDoubleObj \ (tclStubsPtr->tcl_NewDoubleObj) /* 51 */ #define Tcl_NewIntObj \ (tclStubsPtr->tcl_NewIntObj) /* 52 */ #define Tcl_NewListObj \ (tclStubsPtr->tcl_NewListObj) /* 53 */ #define Tcl_NewLongObj \ (tclStubsPtr->tcl_NewLongObj) /* 54 */ #define Tcl_NewObj \ (tclStubsPtr->tcl_NewObj) /* 55 */ #define Tcl_NewStringObj \ (tclStubsPtr->tcl_NewStringObj) /* 56 */ #define Tcl_SetBooleanObj \ (tclStubsPtr->tcl_SetBooleanObj) /* 57 */ #define Tcl_SetByteArrayLength \ (tclStubsPtr->tcl_SetByteArrayLength) /* 58 */ #define Tcl_SetByteArrayObj \ (tclStubsPtr->tcl_SetByteArrayObj) /* 59 */ #define Tcl_SetDoubleObj \ (tclStubsPtr->tcl_SetDoubleObj) /* 60 */ #define Tcl_SetIntObj \ (tclStubsPtr->tcl_SetIntObj) /* 61 */ #define Tcl_SetListObj \ (tclStubsPtr->tcl_SetListObj) /* 62 */ #define Tcl_SetLongObj \ (tclStubsPtr->tcl_SetLongObj) /* 63 */ #define Tcl_SetObjLength \ (tclStubsPtr->tcl_SetObjLength) /* 64 */ #define Tcl_SetStringObj \ (tclStubsPtr->tcl_SetStringObj) /* 65 */ #define Tcl_AddErrorInfo \ (tclStubsPtr->tcl_AddErrorInfo) /* 66 */ #define Tcl_AddObjErrorInfo \ (tclStubsPtr->tcl_AddObjErrorInfo) /* 67 */ #define Tcl_AllowExceptions \ (tclStubsPtr->tcl_AllowExceptions) /* 68 */ #define Tcl_AppendElement \ (tclStubsPtr->tcl_AppendElement) /* 69 */ #define Tcl_AppendResult \ (tclStubsPtr->tcl_AppendResult) /* 70 */ #define Tcl_AsyncCreate \ (tclStubsPtr->tcl_AsyncCreate) /* 71 */ #define Tcl_AsyncDelete \ (tclStubsPtr->tcl_AsyncDelete) /* 72 */ #define Tcl_AsyncInvoke \ (tclStubsPtr->tcl_AsyncInvoke) /* 73 */ #define Tcl_AsyncMark \ (tclStubsPtr->tcl_AsyncMark) /* 74 */ #define Tcl_AsyncReady \ (tclStubsPtr->tcl_AsyncReady) /* 75 */ #define Tcl_BackgroundError \ (tclStubsPtr->tcl_BackgroundError) /* 76 */ #define Tcl_Backslash \ (tclStubsPtr->tcl_Backslash) /* 77 */ #define Tcl_BadChannelOption \ (tclStubsPtr->tcl_BadChannelOption) /* 78 */ #define Tcl_CallWhenDeleted \ (tclStubsPtr->tcl_CallWhenDeleted) /* 79 */ #define Tcl_CancelIdleCall \ (tclStubsPtr->tcl_CancelIdleCall) /* 80 */ #define Tcl_Close \ (tclStubsPtr->tcl_Close) /* 81 */ #define Tcl_CommandComplete \ (tclStubsPtr->tcl_CommandComplete) /* 82 */ #define Tcl_Concat \ (tclStubsPtr->tcl_Concat) /* 83 */ #define Tcl_ConvertElement \ (tclStubsPtr->tcl_ConvertElement) /* 84 */ #define Tcl_ConvertCountedElement \ (tclStubsPtr->tcl_ConvertCountedElement) /* 85 */ #define Tcl_CreateAlias \ (tclStubsPtr->tcl_CreateAlias) /* 86 */ #define Tcl_CreateAliasObj \ (tclStubsPtr->tcl_CreateAliasObj) /* 87 */ #define Tcl_CreateChannel \ (tclStubsPtr->tcl_CreateChannel) /* 88 */ #define Tcl_CreateChannelHandler \ (tclStubsPtr->tcl_CreateChannelHandler) /* 89 */ #define Tcl_CreateCloseHandler \ (tclStubsPtr->tcl_CreateCloseHandler) /* 90 */ #define Tcl_CreateCommand \ (tclStubsPtr->tcl_CreateCommand) /* 91 */ #define Tcl_CreateEventSource \ (tclStubsPtr->tcl_CreateEventSource) /* 92 */ #define Tcl_CreateExitHandler \ (tclStubsPtr->tcl_CreateExitHandler) /* 93 */ #define Tcl_CreateInterp \ (tclStubsPtr->tcl_CreateInterp) /* 94 */ #define Tcl_CreateMathFunc \ (tclStubsPtr->tcl_CreateMathFunc) /* 95 */ #define Tcl_CreateObjCommand \ (tclStubsPtr->tcl_CreateObjCommand) /* 96 */ #define Tcl_CreateSlave \ (tclStubsPtr->tcl_CreateSlave) /* 97 */ #define Tcl_CreateTimerHandler \ (tclStubsPtr->tcl_CreateTimerHandler) /* 98 */ #define Tcl_CreateTrace \ (tclStubsPtr->tcl_CreateTrace) /* 99 */ #define Tcl_DeleteAssocData \ (tclStubsPtr->tcl_DeleteAssocData) /* 100 */ #define Tcl_DeleteChannelHandler \ (tclStubsPtr->tcl_DeleteChannelHandler) /* 101 */ #define Tcl_DeleteCloseHandler \ (tclStubsPtr->tcl_DeleteCloseHandler) /* 102 */ #define Tcl_DeleteCommand \ (tclStubsPtr->tcl_DeleteCommand) /* 103 */ #define Tcl_DeleteCommandFromToken \ (tclStubsPtr->tcl_DeleteCommandFromToken) /* 104 */ #define Tcl_DeleteEvents \ (tclStubsPtr->tcl_DeleteEvents) /* 105 */ #define Tcl_DeleteEventSource \ (tclStubsPtr->tcl_DeleteEventSource) /* 106 */ #define Tcl_DeleteExitHandler \ (tclStubsPtr->tcl_DeleteExitHandler) /* 107 */ #define Tcl_DeleteHashEntry \ (tclStubsPtr->tcl_DeleteHashEntry) /* 108 */ #define Tcl_DeleteHashTable \ (tclStubsPtr->tcl_DeleteHashTable) /* 109 */ #define Tcl_DeleteInterp \ (tclStubsPtr->tcl_DeleteInterp) /* 110 */ #define Tcl_DetachPids \ (tclStubsPtr->tcl_DetachPids) /* 111 */ #define Tcl_DeleteTimerHandler \ (tclStubsPtr->tcl_DeleteTimerHandler) /* 112 */ #define Tcl_DeleteTrace \ (tclStubsPtr->tcl_DeleteTrace) /* 113 */ #define Tcl_DontCallWhenDeleted \ (tclStubsPtr->tcl_DontCallWhenDeleted) /* 114 */ #define Tcl_DoOneEvent \ (tclStubsPtr->tcl_DoOneEvent) /* 115 */ #define Tcl_DoWhenIdle \ (tclStubsPtr->tcl_DoWhenIdle) /* 116 */ #define Tcl_DStringAppend \ (tclStubsPtr->tcl_DStringAppend) /* 117 */ #define Tcl_DStringAppendElement \ (tclStubsPtr->tcl_DStringAppendElement) /* 118 */ #define Tcl_DStringEndSublist \ (tclStubsPtr->tcl_DStringEndSublist) /* 119 */ #define Tcl_DStringFree \ (tclStubsPtr->tcl_DStringFree) /* 120 */ #define Tcl_DStringGetResult \ (tclStubsPtr->tcl_DStringGetResult) /* 121 */ #define Tcl_DStringInit \ (tclStubsPtr->tcl_DStringInit) /* 122 */ #define Tcl_DStringResult \ (tclStubsPtr->tcl_DStringResult) /* 123 */ #define Tcl_DStringSetLength \ (tclStubsPtr->tcl_DStringSetLength) /* 124 */ #define Tcl_DStringStartSublist \ (tclStubsPtr->tcl_DStringStartSublist) /* 125 */ #define Tcl_Eof \ (tclStubsPtr->tcl_Eof) /* 126 */ #define Tcl_ErrnoId \ (tclStubsPtr->tcl_ErrnoId) /* 127 */ #define Tcl_ErrnoMsg \ (tclStubsPtr->tcl_ErrnoMsg) /* 128 */ #define Tcl_Eval \ (tclStubsPtr->tcl_Eval) /* 129 */ #define Tcl_EvalFile \ (tclStubsPtr->tcl_EvalFile) /* 130 */ #define Tcl_EvalObj \ (tclStubsPtr->tcl_EvalObj) /* 131 */ #define Tcl_EventuallyFree \ (tclStubsPtr->tcl_EventuallyFree) /* 132 */ #define Tcl_Exit \ (tclStubsPtr->tcl_Exit) /* 133 */ #define Tcl_ExposeCommand \ (tclStubsPtr->tcl_ExposeCommand) /* 134 */ #define Tcl_ExprBoolean \ (tclStubsPtr->tcl_ExprBoolean) /* 135 */ #define Tcl_ExprBooleanObj \ (tclStubsPtr->tcl_ExprBooleanObj) /* 136 */ #define Tcl_ExprDouble \ (tclStubsPtr->tcl_ExprDouble) /* 137 */ #define Tcl_ExprDoubleObj \ (tclStubsPtr->tcl_ExprDoubleObj) /* 138 */ #define Tcl_ExprLong \ (tclStubsPtr->tcl_ExprLong) /* 139 */ #define Tcl_ExprLongObj \ (tclStubsPtr->tcl_ExprLongObj) /* 140 */ #define Tcl_ExprObj \ (tclStubsPtr->tcl_ExprObj) /* 141 */ #define Tcl_ExprString \ (tclStubsPtr->tcl_ExprString) /* 142 */ #define Tcl_Finalize \ (tclStubsPtr->tcl_Finalize) /* 143 */ #define Tcl_FindExecutable \ (tclStubsPtr->tcl_FindExecutable) /* 144 */ #define Tcl_FirstHashEntry \ (tclStubsPtr->tcl_FirstHashEntry) /* 145 */ #define Tcl_Flush \ (tclStubsPtr->tcl_Flush) /* 146 */ #define Tcl_FreeResult \ (tclStubsPtr->tcl_FreeResult) /* 147 */ #define Tcl_GetAlias \ (tclStubsPtr->tcl_GetAlias) /* 148 */ #define Tcl_GetAliasObj \ (tclStubsPtr->tcl_GetAliasObj) /* 149 */ #define Tcl_GetAssocData \ (tclStubsPtr->tcl_GetAssocData) /* 150 */ #define Tcl_GetChannel \ (tclStubsPtr->tcl_GetChannel) /* 151 */ #define Tcl_GetChannelBufferSize \ (tclStubsPtr->tcl_GetChannelBufferSize) /* 152 */ #define Tcl_GetChannelHandle \ (tclStubsPtr->tcl_GetChannelHandle) /* 153 */ #define Tcl_GetChannelInstanceData \ (tclStubsPtr->tcl_GetChannelInstanceData) /* 154 */ #define Tcl_GetChannelMode \ (tclStubsPtr->tcl_GetChannelMode) /* 155 */ #define Tcl_GetChannelName \ (tclStubsPtr->tcl_GetChannelName) /* 156 */ #define Tcl_GetChannelOption \ (tclStubsPtr->tcl_GetChannelOption) /* 157 */ #define Tcl_GetChannelType \ (tclStubsPtr->tcl_GetChannelType) /* 158 */ #define Tcl_GetCommandInfo \ (tclStubsPtr->tcl_GetCommandInfo) /* 159 */ #define Tcl_GetCommandName \ (tclStubsPtr->tcl_GetCommandName) /* 160 */ #define Tcl_GetErrno \ (tclStubsPtr->tcl_GetErrno) /* 161 */ #define Tcl_GetHostName \ (tclStubsPtr->tcl_GetHostName) /* 162 */ #define Tcl_GetInterpPath \ (tclStubsPtr->tcl_GetInterpPath) /* 163 */ #define Tcl_GetMaster \ (tclStubsPtr->tcl_GetMaster) /* 164 */ #define Tcl_GetNameOfExecutable \ (tclStubsPtr->tcl_GetNameOfExecutable) /* 165 */ #define Tcl_GetObjResult \ (tclStubsPtr->tcl_GetObjResult) /* 166 */ #if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */ #define Tcl_GetOpenFile \ (tclStubsPtr->tcl_GetOpenFile) /* 167 */ #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ #define Tcl_GetOpenFile \ (tclStubsPtr->tcl_GetOpenFile) /* 167 */ #endif /* MACOSX */ #define Tcl_GetPathType \ (tclStubsPtr->tcl_GetPathType) /* 168 */ #define Tcl_Gets \ (tclStubsPtr->tcl_Gets) /* 169 */ #define Tcl_GetsObj \ (tclStubsPtr->tcl_GetsObj) /* 170 */ #define Tcl_GetServiceMode \ (tclStubsPtr->tcl_GetServiceMode) /* 171 */ #define Tcl_GetSlave \ (tclStubsPtr->tcl_GetSlave) /* 172 */ #define Tcl_GetStdChannel \ (tclStubsPtr->tcl_GetStdChannel) /* 173 */ #define Tcl_GetStringResult \ (tclStubsPtr->tcl_GetStringResult) /* 174 */ #define Tcl_GetVar \ (tclStubsPtr->tcl_GetVar) /* 175 */ #define Tcl_GetVar2 \ (tclStubsPtr->tcl_GetVar2) /* 176 */ #define Tcl_GlobalEval \ (tclStubsPtr->tcl_GlobalEval) /* 177 */ #define Tcl_GlobalEvalObj \ (tclStubsPtr->tcl_GlobalEvalObj) /* 178 */ #define Tcl_HideCommand \ (tclStubsPtr->tcl_HideCommand) /* 179 */ #define Tcl_Init \ (tclStubsPtr->tcl_Init) /* 180 */ #define Tcl_InitHashTable \ (tclStubsPtr->tcl_InitHashTable) /* 181 */ #define Tcl_InputBlocked \ (tclStubsPtr->tcl_InputBlocked) /* 182 */ #define Tcl_InputBuffered \ (tclStubsPtr->tcl_InputBuffered) /* 183 */ #define Tcl_InterpDeleted \ (tclStubsPtr->tcl_InterpDeleted) /* 184 */ #define Tcl_IsSafe \ (tclStubsPtr->tcl_IsSafe) /* 185 */ #define Tcl_JoinPath \ (tclStubsPtr->tcl_JoinPath) /* 186 */ #define Tcl_LinkVar \ (tclStubsPtr->tcl_LinkVar) /* 187 */ /* Slot 188 is reserved */ #define Tcl_MakeFileChannel \ (tclStubsPtr->tcl_MakeFileChannel) /* 189 */ #define Tcl_MakeSafe \ (tclStubsPtr->tcl_MakeSafe) /* 190 */ #define Tcl_MakeTcpClientChannel \ (tclStubsPtr->tcl_MakeTcpClientChannel) /* 191 */ #define Tcl_Merge \ (tclStubsPtr->tcl_Merge) /* 192 */ #define Tcl_NextHashEntry \ (tclStubsPtr->tcl_NextHashEntry) /* 193 */ #define Tcl_NotifyChannel \ (tclStubsPtr->tcl_NotifyChannel) /* 194 */ #define Tcl_ObjGetVar2 \ (tclStubsPtr->tcl_ObjGetVar2) /* 195 */ #define Tcl_ObjSetVar2 \ (tclStubsPtr->tcl_ObjSetVar2) /* 196 */ #define Tcl_OpenCommandChannel \ (tclStubsPtr->tcl_OpenCommandChannel) /* 197 */ #define Tcl_OpenFileChannel \ (tclStubsPtr->tcl_OpenFileChannel) /* 198 */ #define Tcl_OpenTcpClient \ (tclStubsPtr->tcl_OpenTcpClient) /* 199 */ #define Tcl_OpenTcpServer \ (tclStubsPtr->tcl_OpenTcpServer) /* 200 */ #define Tcl_Preserve \ (tclStubsPtr->tcl_Preserve) /* 201 */ #define Tcl_PrintDouble \ (tclStubsPtr->tcl_PrintDouble) /* 202 */ #define Tcl_PutEnv \ (tclStubsPtr->tcl_PutEnv) /* 203 */ #define Tcl_PosixError \ (tclStubsPtr->tcl_PosixError) /* 204 */ #define Tcl_QueueEvent \ (tclStubsPtr->tcl_QueueEvent) /* 205 */ #define Tcl_Read \ (tclStubsPtr->tcl_Read) /* 206 */ #define Tcl_ReapDetachedProcs \ (tclStubsPtr->tcl_ReapDetachedProcs) /* 207 */ #define Tcl_RecordAndEval \ (tclStubsPtr->tcl_RecordAndEval) /* 208 */ #define Tcl_RecordAndEvalObj \ (tclStubsPtr->tcl_RecordAndEvalObj) /* 209 */ #define Tcl_RegisterChannel \ (tclStubsPtr->tcl_RegisterChannel) /* 210 */ #define Tcl_RegisterObjType \ (tclStubsPtr->tcl_RegisterObjType) /* 211 */ #define Tcl_RegExpCompile \ (tclStubsPtr->tcl_RegExpCompile) /* 212 */ #define Tcl_RegExpExec \ (tclStubsPtr->tcl_RegExpExec) /* 213 */ #define Tcl_RegExpMatch \ (tclStubsPtr->tcl_RegExpMatch) /* 214 */ #define Tcl_RegExpRange \ (tclStubsPtr->tcl_RegExpRange) /* 215 */ #define Tcl_Release \ (tclStubsPtr->tcl_Release) /* 216 */ #define Tcl_ResetResult \ (tclStubsPtr->tcl_ResetResult) /* 217 */ #define Tcl_ScanElement \ (tclStubsPtr->tcl_ScanElement) /* 218 */ #define Tcl_ScanCountedElement \ (tclStubsPtr->tcl_ScanCountedElement) /* 219 */ #define Tcl_SeekOld \ (tclStubsPtr->tcl_SeekOld) /* 220 */ #define Tcl_ServiceAll \ (tclStubsPtr->tcl_ServiceAll) /* 221 */ #define Tcl_ServiceEvent \ (tclStubsPtr->tcl_ServiceEvent) /* 222 */ #define Tcl_SetAssocData \ (tclStubsPtr->tcl_SetAssocData) /* 223 */ #define Tcl_SetChannelBufferSize \ (tclStubsPtr->tcl_SetChannelBufferSize) /* 224 */ #define Tcl_SetChannelOption \ (tclStubsPtr->tcl_SetChannelOption) /* 225 */ #define Tcl_SetCommandInfo \ (tclStubsPtr->tcl_SetCommandInfo) /* 226 */ #define Tcl_SetErrno \ (tclStubsPtr->tcl_SetErrno) /* 227 */ #define Tcl_SetErrorCode \ (tclStubsPtr->tcl_SetErrorCode) /* 228 */ #define Tcl_SetMaxBlockTime \ (tclStubsPtr->tcl_SetMaxBlockTime) /* 229 */ #define Tcl_SetPanicProc \ (tclStubsPtr->tcl_SetPanicProc) /* 230 */ #define Tcl_SetRecursionLimit \ (tclStubsPtr->tcl_SetRecursionLimit) /* 231 */ #define Tcl_SetResult \ (tclStubsPtr->tcl_SetResult) /* 232 */ #define Tcl_SetServiceMode \ (tclStubsPtr->tcl_SetServiceMode) /* 233 */ #define Tcl_SetObjErrorCode \ (tclStubsPtr->tcl_SetObjErrorCode) /* 234 */ #define Tcl_SetObjResult \ (tclStubsPtr->tcl_SetObjResult) /* 235 */ #define Tcl_SetStdChannel \ (tclStubsPtr->tcl_SetStdChannel) /* 236 */ #define Tcl_SetVar \ (tclStubsPtr->tcl_SetVar) /* 237 */ #define Tcl_SetVar2 \ (tclStubsPtr->tcl_SetVar2) /* 238 */ #define Tcl_SignalId \ (tclStubsPtr->tcl_SignalId) /* 239 */ #define Tcl_SignalMsg \ (tclStubsPtr->tcl_SignalMsg) /* 240 */ #define Tcl_SourceRCFile \ (tclStubsPtr->tcl_SourceRCFile) /* 241 */ #define Tcl_SplitList \ (tclStubsPtr->tcl_SplitList) /* 242 */ #define Tcl_SplitPath \ (tclStubsPtr->tcl_SplitPath) /* 243 */ #define Tcl_StaticPackage \ (tclStubsPtr->tcl_StaticPackage) /* 244 */ #define Tcl_StringMatch \ (tclStubsPtr->tcl_StringMatch) /* 245 */ #define Tcl_TellOld \ (tclStubsPtr->tcl_TellOld) /* 246 */ #define Tcl_TraceVar \ (tclStubsPtr->tcl_TraceVar) /* 247 */ #define Tcl_TraceVar2 \ (tclStubsPtr->tcl_TraceVar2) /* 248 */ #define Tcl_TranslateFileName \ (tclStubsPtr->tcl_TranslateFileName) /* 249 */ #define Tcl_Ungets \ (tclStubsPtr->tcl_Ungets) /* 250 */ #define Tcl_UnlinkVar \ (tclStubsPtr->tcl_UnlinkVar) /* 251 */ #define Tcl_UnregisterChannel \ (tclStubsPtr->tcl_UnregisterChannel) /* 252 */ #define Tcl_UnsetVar \ (tclStubsPtr->tcl_UnsetVar) /* 253 */ #define Tcl_UnsetVar2 \ (tclStubsPtr->tcl_UnsetVar2) /* 254 */ #define Tcl_UntraceVar \ (tclStubsPtr->tcl_UntraceVar) /* 255 */ #define Tcl_UntraceVar2 \ (tclStubsPtr->tcl_UntraceVar2) /* 256 */ #define Tcl_UpdateLinkedVar \ (tclStubsPtr->tcl_UpdateLinkedVar) /* 257 */ #define Tcl_UpVar \ (tclStubsPtr->tcl_UpVar) /* 258 */ #define Tcl_UpVar2 \ (tclStubsPtr->tcl_UpVar2) /* 259 */ #define Tcl_VarEval \ (tclStubsPtr->tcl_VarEval) /* 260 */ #define Tcl_VarTraceInfo \ (tclStubsPtr->tcl_VarTraceInfo) /* 261 */ #define Tcl_VarTraceInfo2 \ (tclStubsPtr->tcl_VarTraceInfo2) /* 262 */ #define Tcl_Write \ (tclStubsPtr->tcl_Write) /* 263 */ #define Tcl_WrongNumArgs \ (tclStubsPtr->tcl_WrongNumArgs) /* 264 */ #define Tcl_DumpActiveMemory \ (tclStubsPtr->tcl_DumpActiveMemory) /* 265 */ #define Tcl_ValidateAllMemory \ (tclStubsPtr->tcl_ValidateAllMemory) /* 266 */ #define Tcl_AppendResultVA \ (tclStubsPtr->tcl_AppendResultVA) /* 267 */ #define Tcl_AppendStringsToObjVA \ (tclStubsPtr->tcl_AppendStringsToObjVA) /* 268 */ #define Tcl_HashStats \ (tclStubsPtr->tcl_HashStats) /* 269 */ #define Tcl_ParseVar \ (tclStubsPtr->tcl_ParseVar) /* 270 */ #define Tcl_PkgPresent \ (tclStubsPtr->tcl_PkgPresent) /* 271 */ #define Tcl_PkgPresentEx \ (tclStubsPtr->tcl_PkgPresentEx) /* 272 */ #define Tcl_PkgProvide \ (tclStubsPtr->tcl_PkgProvide) /* 273 */ #define Tcl_PkgRequire \ (tclStubsPtr->tcl_PkgRequire) /* 274 */ #define Tcl_SetErrorCodeVA \ (tclStubsPtr->tcl_SetErrorCodeVA) /* 275 */ #define Tcl_VarEvalVA \ (tclStubsPtr->tcl_VarEvalVA) /* 276 */ #define Tcl_WaitPid \ (tclStubsPtr->tcl_WaitPid) /* 277 */ #define Tcl_PanicVA \ (tclStubsPtr->tcl_PanicVA) /* 278 */ #define Tcl_GetVersion \ (tclStubsPtr->tcl_GetVersion) /* 279 */ #define Tcl_InitMemory \ (tclStubsPtr->tcl_InitMemory) /* 280 */ #define Tcl_StackChannel \ (tclStubsPtr->tcl_StackChannel) /* 281 */ #define Tcl_UnstackChannel \ (tclStubsPtr->tcl_UnstackChannel) /* 282 */ #define Tcl_GetStackedChannel \ (tclStubsPtr->tcl_GetStackedChannel) /* 283 */ #define Tcl_SetMainLoop \ (tclStubsPtr->tcl_SetMainLoop) /* 284 */ /* Slot 285 is reserved */ #define Tcl_AppendObjToObj \ (tclStubsPtr->tcl_AppendObjToObj) /* 286 */ #define Tcl_CreateEncoding \ (tclStubsPtr->tcl_CreateEncoding) /* 287 */ #define Tcl_CreateThreadExitHandler \ (tclStubsPtr->tcl_CreateThreadExitHandler) /* 288 */ #define Tcl_DeleteThreadExitHandler \ (tclStubsPtr->tcl_DeleteThreadExitHandler) /* 289 */ #define Tcl_DiscardResult \ (tclStubsPtr->tcl_DiscardResult) /* 290 */ #define Tcl_EvalEx \ (tclStubsPtr->tcl_EvalEx) /* 291 */ #define Tcl_EvalObjv \ (tclStubsPtr->tcl_EvalObjv) /* 292 */ #define Tcl_EvalObjEx \ (tclStubsPtr->tcl_EvalObjEx) /* 293 */ #define Tcl_ExitThread \ (tclStubsPtr->tcl_ExitThread) /* 294 */ #define Tcl_ExternalToUtf \ (tclStubsPtr->tcl_ExternalToUtf) /* 295 */ #define Tcl_ExternalToUtfDString \ (tclStubsPtr->tcl_ExternalToUtfDString) /* 296 */ #define Tcl_FinalizeThread \ (tclStubsPtr->tcl_FinalizeThread) /* 297 */ #define Tcl_FinalizeNotifier \ (tclStubsPtr->tcl_FinalizeNotifier) /* 298 */ #define Tcl_FreeEncoding \ (tclStubsPtr->tcl_FreeEncoding) /* 299 */ #define Tcl_GetCurrentThread \ (tclStubsPtr->tcl_GetCurrentThread) /* 300 */ #define Tcl_GetEncoding \ (tclStubsPtr->tcl_GetEncoding) /* 301 */ #define Tcl_GetEncodingName \ (tclStubsPtr->tcl_GetEncodingName) /* 302 */ #define Tcl_GetEncodingNames \ (tclStubsPtr->tcl_GetEncodingNames) /* 303 */ #define Tcl_GetIndexFromObjStruct \ (tclStubsPtr->tcl_GetIndexFromObjStruct) /* 304 */ #define Tcl_GetThreadData \ (tclStubsPtr->tcl_GetThreadData) /* 305 */ #define Tcl_GetVar2Ex \ (tclStubsPtr->tcl_GetVar2Ex) /* 306 */ #define Tcl_InitNotifier \ (tclStubsPtr->tcl_InitNotifier) /* 307 */ #define Tcl_MutexLock \ (tclStubsPtr->tcl_MutexLock) /* 308 */ #define Tcl_MutexUnlock \ (tclStubsPtr->tcl_MutexUnlock) /* 309 */ #define Tcl_ConditionNotify \ (tclStubsPtr->tcl_ConditionNotify) /* 310 */ #define Tcl_ConditionWait \ (tclStubsPtr->tcl_ConditionWait) /* 311 */ #define Tcl_NumUtfChars \ (tclStubsPtr->tcl_NumUtfChars) /* 312 */ #define Tcl_ReadChars \ (tclStubsPtr->tcl_ReadChars) /* 313 */ #define Tcl_RestoreResult \ (tclStubsPtr->tcl_RestoreResult) /* 314 */ #define Tcl_SaveResult \ (tclStubsPtr->tcl_SaveResult) /* 315 */ #define Tcl_SetSystemEncoding \ (tclStubsPtr->tcl_SetSystemEncoding) /* 316 */ #define Tcl_SetVar2Ex \ (tclStubsPtr->tcl_SetVar2Ex) /* 317 */ #define Tcl_ThreadAlert \ (tclStubsPtr->tcl_ThreadAlert) /* 318 */ #define Tcl_ThreadQueueEvent \ (tclStubsPtr->tcl_ThreadQueueEvent) /* 319 */ #define Tcl_UniCharAtIndex \ (tclStubsPtr->tcl_UniCharAtIndex) /* 320 */ #define Tcl_UniCharToLower \ (tclStubsPtr->tcl_UniCharToLower) /* 321 */ #define Tcl_UniCharToTitle \ (tclStubsPtr->tcl_UniCharToTitle) /* 322 */ #define Tcl_UniCharToUpper \ (tclStubsPtr->tcl_UniCharToUpper) /* 323 */ #define Tcl_UniCharToUtf \ (tclStubsPtr->tcl_UniCharToUtf) /* 324 */ #define Tcl_UtfAtIndex \ (tclStubsPtr->tcl_UtfAtIndex) /* 325 */ #define Tcl_UtfCharComplete \ (tclStubsPtr->tcl_UtfCharComplete) /* 326 */ #define Tcl_UtfBackslash \ (tclStubsPtr->tcl_UtfBackslash) /* 327 */ #define Tcl_UtfFindFirst \ (tclStubsPtr->tcl_UtfFindFirst) /* 328 */ #define Tcl_UtfFindLast \ (tclStubsPtr->tcl_UtfFindLast) /* 329 */ #define Tcl_UtfNext \ (tclStubsPtr->tcl_UtfNext) /* 330 */ #define Tcl_UtfPrev \ (tclStubsPtr->tcl_UtfPrev) /* 331 */ #define Tcl_UtfToExternal \ (tclStubsPtr->tcl_UtfToExternal) /* 332 */ #define Tcl_UtfToExternalDString \ (tclStubsPtr->tcl_UtfToExternalDString) /* 333 */ #define Tcl_UtfToLower \ (tclStubsPtr->tcl_UtfToLower) /* 334 */ #define Tcl_UtfToTitle \ (tclStubsPtr->tcl_UtfToTitle) /* 335 */ #define Tcl_UtfToUniChar \ (tclStubsPtr->tcl_UtfToUniChar) /* 336 */ #define Tcl_UtfToUpper \ (tclStubsPtr->tcl_UtfToUpper) /* 337 */ #define Tcl_WriteChars \ (tclStubsPtr->tcl_WriteChars) /* 338 */ #define Tcl_WriteObj \ (tclStubsPtr->tcl_WriteObj) /* 339 */ #define Tcl_GetString \ (tclStubsPtr->tcl_GetString) /* 340 */ #define Tcl_GetDefaultEncodingDir \ (tclStubsPtr->tcl_GetDefaultEncodingDir) /* 341 */ #define Tcl_SetDefaultEncodingDir \ (tclStubsPtr->tcl_SetDefaultEncodingDir) /* 342 */ #define Tcl_AlertNotifier \ (tclStubsPtr->tcl_AlertNotifier) /* 343 */ #define Tcl_ServiceModeHook \ (tclStubsPtr->tcl_ServiceModeHook) /* 344 */ #define Tcl_UniCharIsAlnum \ (tclStubsPtr->tcl_UniCharIsAlnum) /* 345 */ #define Tcl_UniCharIsAlpha \ (tclStubsPtr->tcl_UniCharIsAlpha) /* 346 */ #define Tcl_UniCharIsDigit \ (tclStubsPtr->tcl_UniCharIsDigit) /* 347 */ #define Tcl_UniCharIsLower \ (tclStubsPtr->tcl_UniCharIsLower) /* 348 */ #define Tcl_UniCharIsSpace \ (tclStubsPtr->tcl_UniCharIsSpace) /* 349 */ #define Tcl_UniCharIsUpper \ (tclStubsPtr->tcl_UniCharIsUpper) /* 350 */ #define Tcl_UniCharIsWordChar \ (tclStubsPtr->tcl_UniCharIsWordChar) /* 351 */ #define Tcl_UniCharLen \ (tclStubsPtr->tcl_UniCharLen) /* 352 */ #define Tcl_UniCharNcmp \ (tclStubsPtr->tcl_UniCharNcmp) /* 353 */ #define Tcl_UniCharToUtfDString \ (tclStubsPtr->tcl_UniCharToUtfDString) /* 354 */ #define Tcl_UtfToUniCharDString \ (tclStubsPtr->tcl_UtfToUniCharDString) /* 355 */ #define Tcl_GetRegExpFromObj \ (tclStubsPtr->tcl_GetRegExpFromObj) /* 356 */ #define Tcl_EvalTokens \ (tclStubsPtr->tcl_EvalTokens) /* 357 */ #define Tcl_FreeParse \ (tclStubsPtr->tcl_FreeParse) /* 358 */ #define Tcl_LogCommandInfo \ (tclStubsPtr->tcl_LogCommandInfo) /* 359 */ #define Tcl_ParseBraces \ (tclStubsPtr->tcl_ParseBraces) /* 360 */ #define Tcl_ParseCommand \ (tclStubsPtr->tcl_ParseCommand) /* 361 */ #define Tcl_ParseExpr \ (tclStubsPtr->tcl_ParseExpr) /* 362 */ #define Tcl_ParseQuotedString \ (tclStubsPtr->tcl_ParseQuotedString) /* 363 */ #define Tcl_ParseVarName \ (tclStubsPtr->tcl_ParseVarName) /* 364 */ #define Tcl_GetCwd \ (tclStubsPtr->tcl_GetCwd) /* 365 */ #define Tcl_Chdir \ (tclStubsPtr->tcl_Chdir) /* 366 */ #define Tcl_Access \ (tclStubsPtr->tcl_Access) /* 367 */ #define Tcl_Stat \ (tclStubsPtr->tcl_Stat) /* 368 */ #define Tcl_UtfNcmp \ (tclStubsPtr->tcl_UtfNcmp) /* 369 */ #define Tcl_UtfNcasecmp \ (tclStubsPtr->tcl_UtfNcasecmp) /* 370 */ #define Tcl_StringCaseMatch \ (tclStubsPtr->tcl_StringCaseMatch) /* 371 */ #define Tcl_UniCharIsControl \ (tclStubsPtr->tcl_UniCharIsControl) /* 372 */ #define Tcl_UniCharIsGraph \ (tclStubsPtr->tcl_UniCharIsGraph) /* 373 */ #define Tcl_UniCharIsPrint \ (tclStubsPtr->tcl_UniCharIsPrint) /* 374 */ #define Tcl_UniCharIsPunct \ (tclStubsPtr->tcl_UniCharIsPunct) /* 375 */ #define Tcl_RegExpExecObj \ (tclStubsPtr->tcl_RegExpExecObj) /* 376 */ #define Tcl_RegExpGetInfo \ (tclStubsPtr->tcl_RegExpGetInfo) /* 377 */ #define Tcl_NewUnicodeObj \ (tclStubsPtr->tcl_NewUnicodeObj) /* 378 */ #define Tcl_SetUnicodeObj \ (tclStubsPtr->tcl_SetUnicodeObj) /* 379 */ #define Tcl_GetCharLength \ (tclStubsPtr->tcl_GetCharLength) /* 380 */ #define Tcl_GetUniChar \ (tclStubsPtr->tcl_GetUniChar) /* 381 */ #define Tcl_GetUnicode \ (tclStubsPtr->tcl_GetUnicode) /* 382 */ #define Tcl_GetRange \ (tclStubsPtr->tcl_GetRange) /* 383 */ #define Tcl_AppendUnicodeToObj \ (tclStubsPtr->tcl_AppendUnicodeToObj) /* 384 */ #define Tcl_RegExpMatchObj \ (tclStubsPtr->tcl_RegExpMatchObj) /* 385 */ #define Tcl_SetNotifier \ (tclStubsPtr->tcl_SetNotifier) /* 386 */ #define Tcl_GetAllocMutex \ (tclStubsPtr->tcl_GetAllocMutex) /* 387 */ #define Tcl_GetChannelNames \ (tclStubsPtr->tcl_GetChannelNames) /* 388 */ #define Tcl_GetChannelNamesEx \ (tclStubsPtr->tcl_GetChannelNamesEx) /* 389 */ #define Tcl_ProcObjCmd \ (tclStubsPtr->tcl_ProcObjCmd) /* 390 */ #define Tcl_ConditionFinalize \ (tclStubsPtr->tcl_ConditionFinalize) /* 391 */ #define Tcl_MutexFinalize \ (tclStubsPtr->tcl_MutexFinalize) /* 392 */ #define Tcl_CreateThread \ (tclStubsPtr->tcl_CreateThread) /* 393 */ #define Tcl_ReadRaw \ (tclStubsPtr->tcl_ReadRaw) /* 394 */ #define Tcl_WriteRaw \ (tclStubsPtr->tcl_WriteRaw) /* 395 */ #define Tcl_GetTopChannel \ (tclStubsPtr->tcl_GetTopChannel) /* 396 */ #define Tcl_ChannelBuffered \ (tclStubsPtr->tcl_ChannelBuffered) /* 397 */ #define Tcl_ChannelName \ (tclStubsPtr->tcl_ChannelName) /* 398 */ #define Tcl_ChannelVersion \ (tclStubsPtr->tcl_ChannelVersion) /* 399 */ #define Tcl_ChannelBlockModeProc \ (tclStubsPtr->tcl_ChannelBlockModeProc) /* 400 */ #define Tcl_ChannelCloseProc \ (tclStubsPtr->tcl_ChannelCloseProc) /* 401 */ #define Tcl_ChannelClose2Proc \ (tclStubsPtr->tcl_ChannelClose2Proc) /* 402 */ #define Tcl_ChannelInputProc \ (tclStubsPtr->tcl_ChannelInputProc) /* 403 */ #define Tcl_ChannelOutputProc \ (tclStubsPtr->tcl_ChannelOutputProc) /* 404 */ #define Tcl_ChannelSeekProc \ (tclStubsPtr->tcl_ChannelSeekProc) /* 405 */ #define Tcl_ChannelSetOptionProc \ (tclStubsPtr->tcl_ChannelSetOptionProc) /* 406 */ #define Tcl_ChannelGetOptionProc \ (tclStubsPtr->tcl_ChannelGetOptionProc) /* 407 */ #define Tcl_ChannelWatchProc \ (tclStubsPtr->tcl_ChannelWatchProc) /* 408 */ #define Tcl_ChannelGetHandleProc \ (tclStubsPtr->tcl_ChannelGetHandleProc) /* 409 */ #define Tcl_ChannelFlushProc \ (tclStubsPtr->tcl_ChannelFlushProc) /* 410 */ #define Tcl_ChannelHandlerProc \ (tclStubsPtr->tcl_ChannelHandlerProc) /* 411 */ #define Tcl_JoinThread \ (tclStubsPtr->tcl_JoinThread) /* 412 */ #define Tcl_IsChannelShared \ (tclStubsPtr->tcl_IsChannelShared) /* 413 */ #define Tcl_IsChannelRegistered \ (tclStubsPtr->tcl_IsChannelRegistered) /* 414 */ #define Tcl_CutChannel \ (tclStubsPtr->tcl_CutChannel) /* 415 */ #define Tcl_SpliceChannel \ (tclStubsPtr->tcl_SpliceChannel) /* 416 */ #define Tcl_ClearChannelHandlers \ (tclStubsPtr->tcl_ClearChannelHandlers) /* 417 */ #define Tcl_IsChannelExisting \ (tclStubsPtr->tcl_IsChannelExisting) /* 418 */ #define Tcl_UniCharNcasecmp \ (tclStubsPtr->tcl_UniCharNcasecmp) /* 419 */ #define Tcl_UniCharCaseMatch \ (tclStubsPtr->tcl_UniCharCaseMatch) /* 420 */ #define Tcl_FindHashEntry \ (tclStubsPtr->tcl_FindHashEntry) /* 421 */ #define Tcl_CreateHashEntry \ (tclStubsPtr->tcl_CreateHashEntry) /* 422 */ #define Tcl_InitCustomHashTable \ (tclStubsPtr->tcl_InitCustomHashTable) /* 423 */ #define Tcl_InitObjHashTable \ (tclStubsPtr->tcl_InitObjHashTable) /* 424 */ #define Tcl_CommandTraceInfo \ (tclStubsPtr->tcl_CommandTraceInfo) /* 425 */ #define Tcl_TraceCommand \ (tclStubsPtr->tcl_TraceCommand) /* 426 */ #define Tcl_UntraceCommand \ (tclStubsPtr->tcl_UntraceCommand) /* 427 */ #define Tcl_AttemptAlloc \ (tclStubsPtr->tcl_AttemptAlloc) /* 428 */ #define Tcl_AttemptDbCkalloc \ (tclStubsPtr->tcl_AttemptDbCkalloc) /* 429 */ #define Tcl_AttemptRealloc \ (tclStubsPtr->tcl_AttemptRealloc) /* 430 */ #define Tcl_AttemptDbCkrealloc \ (tclStubsPtr->tcl_AttemptDbCkrealloc) /* 431 */ #define Tcl_AttemptSetObjLength \ (tclStubsPtr->tcl_AttemptSetObjLength) /* 432 */ #define Tcl_GetChannelThread \ (tclStubsPtr->tcl_GetChannelThread) /* 433 */ #define Tcl_GetUnicodeFromObj \ (tclStubsPtr->tcl_GetUnicodeFromObj) /* 434 */ #define Tcl_GetMathFuncInfo \ (tclStubsPtr->tcl_GetMathFuncInfo) /* 435 */ #define Tcl_ListMathFuncs \ (tclStubsPtr->tcl_ListMathFuncs) /* 436 */ #define Tcl_SubstObj \ (tclStubsPtr->tcl_SubstObj) /* 437 */ #define Tcl_DetachChannel \ (tclStubsPtr->tcl_DetachChannel) /* 438 */ #define Tcl_IsStandardChannel \ (tclStubsPtr->tcl_IsStandardChannel) /* 439 */ #define Tcl_FSCopyFile \ (tclStubsPtr->tcl_FSCopyFile) /* 440 */ #define Tcl_FSCopyDirectory \ (tclStubsPtr->tcl_FSCopyDirectory) /* 441 */ #define Tcl_FSCreateDirectory \ (tclStubsPtr->tcl_FSCreateDirectory) /* 442 */ #define Tcl_FSDeleteFile \ (tclStubsPtr->tcl_FSDeleteFile) /* 443 */ #define Tcl_FSLoadFile \ (tclStubsPtr->tcl_FSLoadFile) /* 444 */ #define Tcl_FSMatchInDirectory \ (tclStubsPtr->tcl_FSMatchInDirectory) /* 445 */ #define Tcl_FSLink \ (tclStubsPtr->tcl_FSLink) /* 446 */ #define Tcl_FSRemoveDirectory \ (tclStubsPtr->tcl_FSRemoveDirectory) /* 447 */ #define Tcl_FSRenameFile \ (tclStubsPtr->tcl_FSRenameFile) /* 448 */ #define Tcl_FSLstat \ (tclStubsPtr->tcl_FSLstat) /* 449 */ #define Tcl_FSUtime \ (tclStubsPtr->tcl_FSUtime) /* 450 */ #define Tcl_FSFileAttrsGet \ (tclStubsPtr->tcl_FSFileAttrsGet) /* 451 */ #define Tcl_FSFileAttrsSet \ (tclStubsPtr->tcl_FSFileAttrsSet) /* 452 */ #define Tcl_FSFileAttrStrings \ (tclStubsPtr->tcl_FSFileAttrStrings) /* 453 */ #define Tcl_FSStat \ (tclStubsPtr->tcl_FSStat) /* 454 */ #define Tcl_FSAccess \ (tclStubsPtr->tcl_FSAccess) /* 455 */ #define Tcl_FSOpenFileChannel \ (tclStubsPtr->tcl_FSOpenFileChannel) /* 456 */ #define Tcl_FSGetCwd \ (tclStubsPtr->tcl_FSGetCwd) /* 457 */ #define Tcl_FSChdir \ (tclStubsPtr->tcl_FSChdir) /* 458 */ #define Tcl_FSConvertToPathType \ (tclStubsPtr->tcl_FSConvertToPathType) /* 459 */ #define Tcl_FSJoinPath \ (tclStubsPtr->tcl_FSJoinPath) /* 460 */ #define Tcl_FSSplitPath \ (tclStubsPtr->tcl_FSSplitPath) /* 461 */ #define Tcl_FSEqualPaths \ (tclStubsPtr->tcl_FSEqualPaths) /* 462 */ #define Tcl_FSGetNormalizedPath \ (tclStubsPtr->tcl_FSGetNormalizedPath) /* 463 */ #define Tcl_FSJoinToPath \ (tclStubsPtr->tcl_FSJoinToPath) /* 464 */ #define Tcl_FSGetInternalRep \ (tclStubsPtr->tcl_FSGetInternalRep) /* 465 */ #define Tcl_FSGetTranslatedPath \ (tclStubsPtr->tcl_FSGetTranslatedPath) /* 466 */ #define Tcl_FSEvalFile \ (tclStubsPtr->tcl_FSEvalFile) /* 467 */ #define Tcl_FSNewNativePath \ (tclStubsPtr->tcl_FSNewNativePath) /* 468 */ #define Tcl_FSGetNativePath \ (tclStubsPtr->tcl_FSGetNativePath) /* 469 */ #define Tcl_FSFileSystemInfo \ (tclStubsPtr->tcl_FSFileSystemInfo) /* 470 */ #define Tcl_FSPathSeparator \ (tclStubsPtr->tcl_FSPathSeparator) /* 471 */ #define Tcl_FSListVolumes \ (tclStubsPtr->tcl_FSListVolumes) /* 472 */ #define Tcl_FSRegister \ (tclStubsPtr->tcl_FSRegister) /* 473 */ #define Tcl_FSUnregister \ (tclStubsPtr->tcl_FSUnregister) /* 474 */ #define Tcl_FSData \ (tclStubsPtr->tcl_FSData) /* 475 */ #define Tcl_FSGetTranslatedStringPath \ (tclStubsPtr->tcl_FSGetTranslatedStringPath) /* 476 */ #define Tcl_FSGetFileSystemForPath \ (tclStubsPtr->tcl_FSGetFileSystemForPath) /* 477 */ #define Tcl_FSGetPathType \ (tclStubsPtr->tcl_FSGetPathType) /* 478 */ #define Tcl_OutputBuffered \ (tclStubsPtr->tcl_OutputBuffered) /* 479 */ #define Tcl_FSMountsChanged \ (tclStubsPtr->tcl_FSMountsChanged) /* 480 */ #define Tcl_EvalTokensStandard \ (tclStubsPtr->tcl_EvalTokensStandard) /* 481 */ #define Tcl_GetTime \ (tclStubsPtr->tcl_GetTime) /* 482 */ #define Tcl_CreateObjTrace \ (tclStubsPtr->tcl_CreateObjTrace) /* 483 */ #define Tcl_GetCommandInfoFromToken \ (tclStubsPtr->tcl_GetCommandInfoFromToken) /* 484 */ #define Tcl_SetCommandInfoFromToken \ (tclStubsPtr->tcl_SetCommandInfoFromToken) /* 485 */ #define Tcl_DbNewWideIntObj \ (tclStubsPtr->tcl_DbNewWideIntObj) /* 486 */ #define Tcl_GetWideIntFromObj \ (tclStubsPtr->tcl_GetWideIntFromObj) /* 487 */ #define Tcl_NewWideIntObj \ (tclStubsPtr->tcl_NewWideIntObj) /* 488 */ #define Tcl_SetWideIntObj \ (tclStubsPtr->tcl_SetWideIntObj) /* 489 */ #define Tcl_AllocStatBuf \ (tclStubsPtr->tcl_AllocStatBuf) /* 490 */ #define Tcl_Seek \ (tclStubsPtr->tcl_Seek) /* 491 */ #define Tcl_Tell \ (tclStubsPtr->tcl_Tell) /* 492 */ #define Tcl_ChannelWideSeekProc \ (tclStubsPtr->tcl_ChannelWideSeekProc) /* 493 */ #define Tcl_DictObjPut \ (tclStubsPtr->tcl_DictObjPut) /* 494 */ #define Tcl_DictObjGet \ (tclStubsPtr->tcl_DictObjGet) /* 495 */ #define Tcl_DictObjRemove \ (tclStubsPtr->tcl_DictObjRemove) /* 496 */ #define Tcl_DictObjSize \ (tclStubsPtr->tcl_DictObjSize) /* 497 */ #define Tcl_DictObjFirst \ (tclStubsPtr->tcl_DictObjFirst) /* 498 */ #define Tcl_DictObjNext \ (tclStubsPtr->tcl_DictObjNext) /* 499 */ #define Tcl_DictObjDone \ (tclStubsPtr->tcl_DictObjDone) /* 500 */ #define Tcl_DictObjPutKeyList \ (tclStubsPtr->tcl_DictObjPutKeyList) /* 501 */ #define Tcl_DictObjRemoveKeyList \ (tclStubsPtr->tcl_DictObjRemoveKeyList) /* 502 */ #define Tcl_NewDictObj \ (tclStubsPtr->tcl_NewDictObj) /* 503 */ #define Tcl_DbNewDictObj \ (tclStubsPtr->tcl_DbNewDictObj) /* 504 */ #define Tcl_RegisterConfig \ (tclStubsPtr->tcl_RegisterConfig) /* 505 */ #define Tcl_CreateNamespace \ (tclStubsPtr->tcl_CreateNamespace) /* 506 */ #define Tcl_DeleteNamespace \ (tclStubsPtr->tcl_DeleteNamespace) /* 507 */ #define Tcl_AppendExportList \ (tclStubsPtr->tcl_AppendExportList) /* 508 */ #define Tcl_Export \ (tclStubsPtr->tcl_Export) /* 509 */ #define Tcl_Import \ (tclStubsPtr->tcl_Import) /* 510 */ #define Tcl_ForgetImport \ (tclStubsPtr->tcl_ForgetImport) /* 511 */ #define Tcl_GetCurrentNamespace \ (tclStubsPtr->tcl_GetCurrentNamespace) /* 512 */ #define Tcl_GetGlobalNamespace \ (tclStubsPtr->tcl_GetGlobalNamespace) /* 513 */ #define Tcl_FindNamespace \ (tclStubsPtr->tcl_FindNamespace) /* 514 */ #define Tcl_FindCommand \ (tclStubsPtr->tcl_FindCommand) /* 515 */ #define Tcl_GetCommandFromObj \ (tclStubsPtr->tcl_GetCommandFromObj) /* 516 */ #define Tcl_GetCommandFullName \ (tclStubsPtr->tcl_GetCommandFullName) /* 517 */ #define Tcl_FSEvalFileEx \ (tclStubsPtr->tcl_FSEvalFileEx) /* 518 */ #define Tcl_SetExitProc \ (tclStubsPtr->tcl_SetExitProc) /* 519 */ #define Tcl_LimitAddHandler \ (tclStubsPtr->tcl_LimitAddHandler) /* 520 */ #define Tcl_LimitRemoveHandler \ (tclStubsPtr->tcl_LimitRemoveHandler) /* 521 */ #define Tcl_LimitReady \ (tclStubsPtr->tcl_LimitReady) /* 522 */ #define Tcl_LimitCheck \ (tclStubsPtr->tcl_LimitCheck) /* 523 */ #define Tcl_LimitExceeded \ (tclStubsPtr->tcl_LimitExceeded) /* 524 */ #define Tcl_LimitSetCommands \ (tclStubsPtr->tcl_LimitSetCommands) /* 525 */ #define Tcl_LimitSetTime \ (tclStubsPtr->tcl_LimitSetTime) /* 526 */ #define Tcl_LimitSetGranularity \ (tclStubsPtr->tcl_LimitSetGranularity) /* 527 */ #define Tcl_LimitTypeEnabled \ (tclStubsPtr->tcl_LimitTypeEnabled) /* 528 */ #define Tcl_LimitTypeExceeded \ (tclStubsPtr->tcl_LimitTypeExceeded) /* 529 */ #define Tcl_LimitTypeSet \ (tclStubsPtr->tcl_LimitTypeSet) /* 530 */ #define Tcl_LimitTypeReset \ (tclStubsPtr->tcl_LimitTypeReset) /* 531 */ #define Tcl_LimitGetCommands \ (tclStubsPtr->tcl_LimitGetCommands) /* 532 */ #define Tcl_LimitGetTime \ (tclStubsPtr->tcl_LimitGetTime) /* 533 */ #define Tcl_LimitGetGranularity \ (tclStubsPtr->tcl_LimitGetGranularity) /* 534 */ #define Tcl_SaveInterpState \ (tclStubsPtr->tcl_SaveInterpState) /* 535 */ #define Tcl_RestoreInterpState \ (tclStubsPtr->tcl_RestoreInterpState) /* 536 */ #define Tcl_DiscardInterpState \ (tclStubsPtr->tcl_DiscardInterpState) /* 537 */ #define Tcl_SetReturnOptions \ (tclStubsPtr->tcl_SetReturnOptions) /* 538 */ #define Tcl_GetReturnOptions \ (tclStubsPtr->tcl_GetReturnOptions) /* 539 */ #define Tcl_IsEnsemble \ (tclStubsPtr->tcl_IsEnsemble) /* 540 */ #define Tcl_CreateEnsemble \ (tclStubsPtr->tcl_CreateEnsemble) /* 541 */ #define Tcl_FindEnsemble \ (tclStubsPtr->tcl_FindEnsemble) /* 542 */ #define Tcl_SetEnsembleSubcommandList \ (tclStubsPtr->tcl_SetEnsembleSubcommandList) /* 543 */ #define Tcl_SetEnsembleMappingDict \ (tclStubsPtr->tcl_SetEnsembleMappingDict) /* 544 */ #define Tcl_SetEnsembleUnknownHandler \ (tclStubsPtr->tcl_SetEnsembleUnknownHandler) /* 545 */ #define Tcl_SetEnsembleFlags \ (tclStubsPtr->tcl_SetEnsembleFlags) /* 546 */ #define Tcl_GetEnsembleSubcommandList \ (tclStubsPtr->tcl_GetEnsembleSubcommandList) /* 547 */ #define Tcl_GetEnsembleMappingDict \ (tclStubsPtr->tcl_GetEnsembleMappingDict) /* 548 */ #define Tcl_GetEnsembleUnknownHandler \ (tclStubsPtr->tcl_GetEnsembleUnknownHandler) /* 549 */ #define Tcl_GetEnsembleFlags \ (tclStubsPtr->tcl_GetEnsembleFlags) /* 550 */ #define Tcl_GetEnsembleNamespace \ (tclStubsPtr->tcl_GetEnsembleNamespace) /* 551 */ #define Tcl_SetTimeProc \ (tclStubsPtr->tcl_SetTimeProc) /* 552 */ #define Tcl_QueryTimeProc \ (tclStubsPtr->tcl_QueryTimeProc) /* 553 */ #define Tcl_ChannelThreadActionProc \ (tclStubsPtr->tcl_ChannelThreadActionProc) /* 554 */ #define Tcl_NewBignumObj \ (tclStubsPtr->tcl_NewBignumObj) /* 555 */ #define Tcl_DbNewBignumObj \ (tclStubsPtr->tcl_DbNewBignumObj) /* 556 */ #define Tcl_SetBignumObj \ (tclStubsPtr->tcl_SetBignumObj) /* 557 */ #define Tcl_GetBignumFromObj \ (tclStubsPtr->tcl_GetBignumFromObj) /* 558 */ #define Tcl_TakeBignumFromObj \ (tclStubsPtr->tcl_TakeBignumFromObj) /* 559 */ #define Tcl_TruncateChannel \ (tclStubsPtr->tcl_TruncateChannel) /* 560 */ #define Tcl_ChannelTruncateProc \ (tclStubsPtr->tcl_ChannelTruncateProc) /* 561 */ #define Tcl_SetChannelErrorInterp \ (tclStubsPtr->tcl_SetChannelErrorInterp) /* 562 */ #define Tcl_GetChannelErrorInterp \ (tclStubsPtr->tcl_GetChannelErrorInterp) /* 563 */ #define Tcl_SetChannelError \ (tclStubsPtr->tcl_SetChannelError) /* 564 */ #define Tcl_GetChannelError \ (tclStubsPtr->tcl_GetChannelError) /* 565 */ #define Tcl_InitBignumFromDouble \ (tclStubsPtr->tcl_InitBignumFromDouble) /* 566 */ #define Tcl_GetNamespaceUnknownHandler \ (tclStubsPtr->tcl_GetNamespaceUnknownHandler) /* 567 */ #define Tcl_SetNamespaceUnknownHandler \ (tclStubsPtr->tcl_SetNamespaceUnknownHandler) /* 568 */ #define Tcl_GetEncodingFromObj \ (tclStubsPtr->tcl_GetEncodingFromObj) /* 569 */ #define Tcl_GetEncodingSearchPath \ (tclStubsPtr->tcl_GetEncodingSearchPath) /* 570 */ #define Tcl_SetEncodingSearchPath \ (tclStubsPtr->tcl_SetEncodingSearchPath) /* 571 */ #define Tcl_GetEncodingNameFromEnvironment \ (tclStubsPtr->tcl_GetEncodingNameFromEnvironment) /* 572 */ #define Tcl_PkgRequireProc \ (tclStubsPtr->tcl_PkgRequireProc) /* 573 */ #define Tcl_AppendObjToErrorInfo \ (tclStubsPtr->tcl_AppendObjToErrorInfo) /* 574 */ #define Tcl_AppendLimitedToObj \ (tclStubsPtr->tcl_AppendLimitedToObj) /* 575 */ #define Tcl_Format \ (tclStubsPtr->tcl_Format) /* 576 */ #define Tcl_AppendFormatToObj \ (tclStubsPtr->tcl_AppendFormatToObj) /* 577 */ #define Tcl_ObjPrintf \ (tclStubsPtr->tcl_ObjPrintf) /* 578 */ #define Tcl_AppendPrintfToObj \ (tclStubsPtr->tcl_AppendPrintfToObj) /* 579 */ #define Tcl_CancelEval \ (tclStubsPtr->tcl_CancelEval) /* 580 */ #define Tcl_Canceled \ (tclStubsPtr->tcl_Canceled) /* 581 */ #define Tcl_CreatePipe \ (tclStubsPtr->tcl_CreatePipe) /* 582 */ #define Tcl_NRCreateCommand \ (tclStubsPtr->tcl_NRCreateCommand) /* 583 */ #define Tcl_NREvalObj \ (tclStubsPtr->tcl_NREvalObj) /* 584 */ #define Tcl_NREvalObjv \ (tclStubsPtr->tcl_NREvalObjv) /* 585 */ #define Tcl_NRCmdSwap \ (tclStubsPtr->tcl_NRCmdSwap) /* 586 */ #define Tcl_NRAddCallback \ (tclStubsPtr->tcl_NRAddCallback) /* 587 */ #define Tcl_NRCallObjProc \ (tclStubsPtr->tcl_NRCallObjProc) /* 588 */ #define Tcl_GetFSDeviceFromStat \ (tclStubsPtr->tcl_GetFSDeviceFromStat) /* 589 */ #define Tcl_GetFSInodeFromStat \ (tclStubsPtr->tcl_GetFSInodeFromStat) /* 590 */ #define Tcl_GetModeFromStat \ (tclStubsPtr->tcl_GetModeFromStat) /* 591 */ #define Tcl_GetLinkCountFromStat \ (tclStubsPtr->tcl_GetLinkCountFromStat) /* 592 */ #define Tcl_GetUserIdFromStat \ (tclStubsPtr->tcl_GetUserIdFromStat) /* 593 */ #define Tcl_GetGroupIdFromStat \ (tclStubsPtr->tcl_GetGroupIdFromStat) /* 594 */ #define Tcl_GetDeviceTypeFromStat \ (tclStubsPtr->tcl_GetDeviceTypeFromStat) /* 595 */ #define Tcl_GetAccessTimeFromStat \ (tclStubsPtr->tcl_GetAccessTimeFromStat) /* 596 */ #define Tcl_GetModificationTimeFromStat \ (tclStubsPtr->tcl_GetModificationTimeFromStat) /* 597 */ #define Tcl_GetChangeTimeFromStat \ (tclStubsPtr->tcl_GetChangeTimeFromStat) /* 598 */ #define Tcl_GetSizeFromStat \ (tclStubsPtr->tcl_GetSizeFromStat) /* 599 */ #define Tcl_GetBlocksFromStat \ (tclStubsPtr->tcl_GetBlocksFromStat) /* 600 */ #define Tcl_GetBlockSizeFromStat \ (tclStubsPtr->tcl_GetBlockSizeFromStat) /* 601 */ #define Tcl_SetEnsembleParameterList \ (tclStubsPtr->tcl_SetEnsembleParameterList) /* 602 */ #define Tcl_GetEnsembleParameterList \ (tclStubsPtr->tcl_GetEnsembleParameterList) /* 603 */ #define Tcl_ParseArgsObjv \ (tclStubsPtr->tcl_ParseArgsObjv) /* 604 */ #define Tcl_GetErrorLine \ (tclStubsPtr->tcl_GetErrorLine) /* 605 */ #define Tcl_SetErrorLine \ (tclStubsPtr->tcl_SetErrorLine) /* 606 */ #define Tcl_TransferResult \ (tclStubsPtr->tcl_TransferResult) /* 607 */ #define Tcl_InterpActive \ (tclStubsPtr->tcl_InterpActive) /* 608 */ #define Tcl_BackgroundException \ (tclStubsPtr->tcl_BackgroundException) /* 609 */ #define Tcl_ZlibDeflate \ (tclStubsPtr->tcl_ZlibDeflate) /* 610 */ #define Tcl_ZlibInflate \ (tclStubsPtr->tcl_ZlibInflate) /* 611 */ #define Tcl_ZlibCRC32 \ (tclStubsPtr->tcl_ZlibCRC32) /* 612 */ #define Tcl_ZlibAdler32 \ (tclStubsPtr->tcl_ZlibAdler32) /* 613 */ #define Tcl_ZlibStreamInit \ (tclStubsPtr->tcl_ZlibStreamInit) /* 614 */ #define Tcl_ZlibStreamGetCommandName \ (tclStubsPtr->tcl_ZlibStreamGetCommandName) /* 615 */ #define Tcl_ZlibStreamEof \ (tclStubsPtr->tcl_ZlibStreamEof) /* 616 */ #define Tcl_ZlibStreamChecksum \ (tclStubsPtr->tcl_ZlibStreamChecksum) /* 617 */ #define Tcl_ZlibStreamPut \ (tclStubsPtr->tcl_ZlibStreamPut) /* 618 */ #define Tcl_ZlibStreamGet \ (tclStubsPtr->tcl_ZlibStreamGet) /* 619 */ #define Tcl_ZlibStreamClose \ (tclStubsPtr->tcl_ZlibStreamClose) /* 620 */ #define Tcl_ZlibStreamReset \ (tclStubsPtr->tcl_ZlibStreamReset) /* 621 */ #define Tcl_SetStartupScript \ (tclStubsPtr->tcl_SetStartupScript) /* 622 */ #define Tcl_GetStartupScript \ (tclStubsPtr->tcl_GetStartupScript) /* 623 */ #define Tcl_CloseEx \ (tclStubsPtr->tcl_CloseEx) /* 624 */ #define Tcl_NRExprObj \ (tclStubsPtr->tcl_NRExprObj) /* 625 */ #define Tcl_NRSubstObj \ (tclStubsPtr->tcl_NRSubstObj) /* 626 */ #define Tcl_LoadFile \ (tclStubsPtr->tcl_LoadFile) /* 627 */ #define Tcl_FindSymbol \ (tclStubsPtr->tcl_FindSymbol) /* 628 */ #define Tcl_FSUnloadFile \ (tclStubsPtr->tcl_FSUnloadFile) /* 629 */ #define Tcl_ZlibStreamSetCompressionDictionary \ (tclStubsPtr->tcl_ZlibStreamSetCompressionDictionary) /* 630 */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ #if defined(USE_TCL_STUBS) # undef Tcl_CreateInterp # undef Tcl_FindExecutable # undef Tcl_GetStringResult # undef Tcl_Init # undef Tcl_SetPanicProc # undef Tcl_SetVar # undef Tcl_ObjSetVar2 # undef Tcl_StaticPackage # undef TclFSGetNativePath # define Tcl_CreateInterp() (tclStubsPtr->tcl_CreateInterp()) # define Tcl_GetStringResult(interp) (tclStubsPtr->tcl_GetStringResult(interp)) # define Tcl_Init(interp) (tclStubsPtr->tcl_Init(interp)) # define Tcl_SetPanicProc(proc) (tclStubsPtr->tcl_SetPanicProc(proc)) # define Tcl_SetVar(interp, varName, newValue, flags) \ (tclStubsPtr->tcl_SetVar(interp, varName, newValue, flags)) # define Tcl_ObjSetVar2(interp, part1, part2, newValue, flags) \ (tclStubsPtr->tcl_ObjSetVar2(interp, part1, part2, newValue, flags)) #endif #if defined(_WIN32) && defined(UNICODE) # define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg))) # define Tcl_MainEx Tcl_MainExW EXTERN void Tcl_MainExW(int argc, wchar_t **argv, Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); #endif #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #undef Tcl_SeekOld #undef Tcl_TellOld #undef Tcl_PkgPresent #define Tcl_PkgPresent(interp, name, version, exact) \ Tcl_PkgPresentEx(interp, name, version, exact, NULL) #undef Tcl_PkgProvide #define Tcl_PkgProvide(interp, name, version) \ Tcl_PkgProvideEx(interp, name, version, NULL) #undef Tcl_PkgRequire #define Tcl_PkgRequire(interp, name, version, exact) \ Tcl_PkgRequireEx(interp, name, version, exact, NULL) #undef Tcl_GetIndexFromObj #define Tcl_GetIndexFromObj(interp, objPtr, tablePtr, msg, flags, indexPtr) \ Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, \ sizeof(char *), msg, flags, indexPtr) #undef Tcl_NewBooleanObj #define Tcl_NewBooleanObj(boolValue) \ Tcl_NewIntObj((boolValue)!=0) #undef Tcl_DbNewBooleanObj #define Tcl_DbNewBooleanObj(boolValue, file, line) \ Tcl_DbNewLongObj((boolValue)!=0, file, line) #undef Tcl_SetBooleanObj #define Tcl_SetBooleanObj(objPtr, boolValue) \ Tcl_SetIntObj((objPtr), (boolValue)!=0) #undef Tcl_SetVar #define Tcl_SetVar(interp, varName, newValue, flags) \ Tcl_SetVar2(interp, varName, NULL, newValue, flags) #undef Tcl_UnsetVar #define Tcl_UnsetVar(interp, varName, flags) \ Tcl_UnsetVar2(interp, varName, NULL, flags) #undef Tcl_GetVar #define Tcl_GetVar(interp, varName, flags) \ Tcl_GetVar2(interp, varName, NULL, flags) #undef Tcl_TraceVar #define Tcl_TraceVar(interp, varName, flags, proc, clientData) \ Tcl_TraceVar2(interp, varName, NULL, flags, proc, clientData) #undef Tcl_UntraceVar #define Tcl_UntraceVar(interp, varName, flags, proc, clientData) \ Tcl_UntraceVar2(interp, varName, NULL, flags, proc, clientData) #undef Tcl_VarTraceInfo #define Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData) \ Tcl_VarTraceInfo2(interp, varName, NULL, flags, proc, prevClientData) #undef Tcl_UpVar #define Tcl_UpVar(interp, frameName, varName, localName, flags) \ Tcl_UpVar2(interp, frameName, varName, NULL, localName, flags) #if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) # if defined(__CYGWIN__) && defined(TCL_WIDE_INT_IS_LONG) /* On Cygwin64, long is 64-bit while on Win64 long is 32-bit. Therefore * we have to make sure that all stub entries on Cygwin64 follow the * Win64 signature. Cygwin64 stubbed extensions cannot use those stub * entries any more, they should use the 64-bit alternatives where * possible. Tcl 9 must find a better solution, but that cannot be done * without introducing a binary incompatibility. */ # undef Tcl_DbNewLongObj # undef Tcl_GetLongFromObj # undef Tcl_NewLongObj # undef Tcl_SetLongObj # undef Tcl_ExprLong # undef Tcl_ExprLongObj # undef Tcl_UniCharNcmp # undef Tcl_UtfNcmp # undef Tcl_UtfNcasecmp # undef Tcl_UniCharNcasecmp # define Tcl_DbNewLongObj ((Tcl_Obj*(*)(long,const char*,int))Tcl_DbNewWideIntObj) # define Tcl_GetLongFromObj ((int(*)(Tcl_Interp*,Tcl_Obj*,long*))Tcl_GetWideIntFromObj) # define Tcl_NewLongObj ((Tcl_Obj*(*)(long))Tcl_NewWideIntObj) # define Tcl_SetLongObj ((void(*)(Tcl_Obj*,long))Tcl_SetWideIntObj) # define Tcl_ExprLong TclExprLong static inline int TclExprLong(Tcl_Interp *interp, const char *string, long *ptr){ int intValue; int result = tclStubsPtr->tcl_ExprLong(interp, string, (long *)&intValue); if (result == TCL_OK) *ptr = (long)intValue; return result; } # define Tcl_ExprLongObj TclExprLongObj static inline int TclExprLongObj(Tcl_Interp *interp, Tcl_Obj *obj, long *ptr){ int intValue; int result = tclStubsPtr->tcl_ExprLongObj(interp, obj, (long *)&intValue); if (result == TCL_OK) *ptr = (long)intValue; return result; } # define Tcl_UniCharNcmp(ucs,uct,n) \ ((int(*)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned int))tclStubsPtr->tcl_UniCharNcmp)(ucs,uct,(unsigned int)(n)) # define Tcl_UtfNcmp(s1,s2,n) \ ((int(*)(const char*,const char*,unsigned int))tclStubsPtr->tcl_UtfNcmp)(s1,s2,(unsigned int)(n)) # define Tcl_UtfNcasecmp(s1,s2,n) \ ((int(*)(const char*,const char*,unsigned int))tclStubsPtr->tcl_UtfNcasecmp)(s1,s2,(unsigned int)(n)) # define Tcl_UniCharNcasecmp(ucs,uct,n) \ ((int(*)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned int))tclStubsPtr->tcl_UniCharNcasecmp)(ucs,uct,(unsigned int)(n)) # endif #endif /* * Deprecated Tcl procedures: */ #undef Tcl_EvalObj #define Tcl_EvalObj(interp,objPtr) \ Tcl_EvalObjEx((interp),(objPtr),0) #undef Tcl_GlobalEvalObj #define Tcl_GlobalEvalObj(interp,objPtr) \ Tcl_EvalObjEx((interp),(objPtr),TCL_EVAL_GLOBAL) #endif /* _TCLDECLS */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/tcl/tclPlatDecls.h0000644000175100017510000000631715106067236021453 0ustar00runnerrunner/* * tclPlatDecls.h -- * * Declarations of platform specific Tcl APIs. * * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. */ #ifndef _TCLPLATDECLS #define _TCLPLATDECLS #undef TCL_STORAGE_CLASS #ifdef BUILD_tcl # define TCL_STORAGE_CLASS DLLEXPORT #else # ifdef USE_TCL_STUBS # define TCL_STORAGE_CLASS # else # define TCL_STORAGE_CLASS DLLIMPORT # endif #endif /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the generic/tcl.decls script. */ /* * TCHAR is needed here for win32, so if it is not defined yet do it here. * This way, we don't need to include just for one define. */ #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(_TCHAR_DEFINED) # if defined(_UNICODE) typedef wchar_t TCHAR; # else typedef char TCHAR; # endif # define _TCHAR_DEFINED #endif /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ #if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ /* 0 */ EXTERN TCHAR * Tcl_WinUtfToTChar(const char *str, int len, Tcl_DString *dsPtr); /* 1 */ EXTERN char * Tcl_WinTCharToUtf(const TCHAR *str, int len, Tcl_DString *dsPtr); #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 0 */ EXTERN int Tcl_MacOSXOpenBundleResources(Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath); /* 1 */ EXTERN int Tcl_MacOSXOpenVersionedBundleResources( Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath); #endif /* MACOSX */ typedef struct TclPlatStubs { int magic; void *hooks; #if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */ char * (*tcl_WinTCharToUtf) (const TCHAR *str, int len, Tcl_DString *dsPtr); /* 1 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ int (*tcl_MacOSXOpenBundleResources) (Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath); /* 0 */ int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath); /* 1 */ #endif /* MACOSX */ } TclPlatStubs; extern const TclPlatStubs *tclPlatStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_TCL_STUBS) /* * Inline function declarations: */ #if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ #define Tcl_WinUtfToTChar \ (tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */ #define Tcl_WinTCharToUtf \ (tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ #define Tcl_MacOSXOpenBundleResources \ (tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */ #define Tcl_MacOSXOpenVersionedBundleResources \ (tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */ #endif /* MACOSX */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLPLATDECLS */ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3447025 cocotb-2.0.1/src/cocotb/_vendor/vhpi/0000755000175100017510000000000015106070715017075 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/vhpi/vhpi_user.h0000644000175100017510000012217315106067236021264 0ustar00runnerrunner/* * |---------------------------------------------------------------| * | | * | This is the VHPI header file | * | | * | | * | | * | FOR CONFORMANCE WITH THE VHPI STANDARD, A VHPI APPLICATION | * | OR PROGRAM MUST REFERENCE THIS HEADER FILE | * | Its contents can be modified to include vendor extensions. | * | | * |---------------------------------------------------------------| */ /*** File vhpi_user.h ***/ /*** This file describes the procedural interface to access VHDL compiled, instantiated and run-time data. It is derived from the UML model. ***/ #ifndef VHPI_USER_H #define VHPI_USER_H #include #include /* Ensure that size-critical types are defined on all OS platforms. */ #if defined(_MSC_VER) typedef unsigned __int64 uint64_t; typedef unsigned __int32 uint32_t; typedef unsigned __int8 uint8_t; typedef signed __int64 int64_t; typedef signed __int32 int32_t; typedef signed __int8 int8_t; #elif defined(__MINGW32__) || (defined(__APPLE__) && defined(__MACH__)) #include #elif defined(__linux) #include #else #include #endif #ifdef __cplusplus extern "C" { #endif #pragma pack(8) /*---------------------------------------------------------------------------*/ /*--------------------------- Portability Help ------------------------------*/ /*---------------------------------------------------------------------------*/ /* Use to import/export a symbol */ #if defined(WIN32) || defined(WIN64) #ifndef PLI_DLLISPEC #define PLI_DLLISPEC __declspec(dllimport) #define VHPI_USER_DEFINED_DLLISPEC 1 #endif #ifndef PLI_DLLESPEC #define PLI_DLLESPEC __declspec(dllexport) #define VHPI_USER_DEFINED_DLLESPEC 1 #endif #else #ifndef PLI_DLLISPEC #define PLI_DLLISPEC #endif #ifndef PLI_DLLESPEC #define PLI_DLLESPEC #endif #endif /* Use to mark a function as external */ #ifndef PLI_EXTERN #define PLI_EXTERN #endif /* Use to mark a variable as external */ #ifndef PLI_VEXTERN #define PLI_VEXTERN extern #endif #ifndef PLI_PROTOTYPES #define PLI_PROTOTYPES /* object is defined imported by the application */ #define XXTERN PLI_EXTERN PLI_DLLISPEC /* object is exported by the application */ #define EETERN PLI_EXTERN PLI_DLLESPEC #endif /* basic typedefs */ #ifndef VHPI_TYPES #define VHPI_TYPES typedef uint32_t *vhpiHandleT; typedef uint32_t vhpiEnumT; typedef uint8_t vhpiSmallEnumT; typedef uint32_t vhpiIntT; typedef uint64_t vhpiLongIntT; typedef char vhpiCharT; typedef double vhpiRealT; typedef uint32_t vhpiSmallPhysT; typedef struct vhpiPhysS { int32_t high; uint32_t low; } vhpiPhysT; /* Sized variables */ #ifndef PLI_TYPES #define PLI_TYPES typedef int PLI_INT32; typedef unsigned int PLI_UINT32; typedef short PLI_INT16; typedef unsigned short PLI_UINT16; typedef char PLI_BYTE8; typedef unsigned char PLI_UBYTE8; typedef void PLI_VOID; #endif /********************** time structure ****************************/ typedef struct vhpiTimeS { uint32_t high; uint32_t low; } vhpiTimeT; /********************** value structure **************************/ /* value formats */ typedef enum { vhpiBinStrVal = 1, /* do not move */ vhpiOctStrVal = 2, /* do not move */ vhpiDecStrVal = 3, /* do not move */ vhpiHexStrVal = 4, /* do not move */ vhpiEnumVal = 5, vhpiIntVal = 6, vhpiLogicVal = 7, vhpiRealVal = 8, vhpiStrVal = 9, vhpiCharVal = 10, vhpiTimeVal = 11, vhpiPhysVal = 12, vhpiObjTypeVal = 13, vhpiPtrVal = 14, vhpiEnumVecVal = 15, vhpiIntVecVal = 16, vhpiLogicVecVal = 17, vhpiRealVecVal = 18, vhpiTimeVecVal = 19, vhpiPhysVecVal = 20, vhpiPtrVecVal = 21, vhpiRawDataVal = 22, vhpiSmallEnumVal = 23, vhpiSmallEnumVecVal = 24, vhpiLongIntVal = 25, vhpiLongIntVecVal = 26, vhpiSmallPhysVal = 27, vhpiSmallPhysVecVal = 28 #ifdef VHPIEXTEND_VAL_FORMATS VHPIEXTEND_VAL_FORMATS #endif } vhpiFormatT; /* value structure */ typedef struct vhpiValueS { vhpiFormatT format; /* vhpi[Char,[Bin,Oct,Dec,Hex]Str, [Small]Enum,Logic,Int,Real,[Small]Phys,Time,Ptr, [Small]EnumVec,LogicVec,IntVect,RealVec,[Small]PhysVec,TimeVec, PtrVec,ObjType,RawData]Val */ #ifndef IUS size_t bufSize; /* the size in bytes of the value buffer; this is set by the user */ #else int32_t bufSize; /* IUS/Xcelium defines this as 32-bits, even when running in 64-bit mode */ #endif int32_t numElems; /* different meanings depending on the format: vhpiStrVal, vhpi{Bin...}StrVal: size of string array type values: number of array elements scalar type values: undefined */ vhpiPhysT unit; union { vhpiEnumT enumv, *enumvs; vhpiSmallEnumT smallenumv, *smallenumvs; vhpiIntT intg, *intgs; vhpiLongIntT longintg, *longintgs; vhpiRealT real, *reals; vhpiSmallPhysT smallphys, *smallphyss; vhpiPhysT phys, *physs; vhpiTimeT time, *times; vhpiCharT ch, *str; void *ptr, **ptrs; } value; } vhpiValueT; #endif /* Following are the constant definitions. They are divided into three major areas: 1) object types 2) access methods 3) properties */ #ifndef IUS #define vhpiUndefined -1 #else #define vhpiUndefined 1000 #endif /*************** OBJECT KINDS *******************/ typedef enum { vhpiAccessTypeDeclK = 1001, vhpiAggregateK = 1002, vhpiAliasDeclK = 1003, vhpiAllK = 1004, vhpiAllocatorK = 1005, vhpiAnyCollectionK = 1006, vhpiArchBodyK = 1007, vhpiArgvK = 1008, vhpiArrayTypeDeclK = 1009, vhpiAssertStmtK = 1010, vhpiAssocElemK = 1011, vhpiAttrDeclK = 1012, vhpiAttrSpecK = 1013, vhpiBinaryExprK = 1014, /* DEPRECATED */ vhpiBitStringLiteralK = 1015, vhpiBlockConfigK = 1016, vhpiBlockStmtK = 1017, vhpiBranchK = 1018, vhpiCallbackK = 1019, vhpiCaseStmtK = 1020, vhpiCharLiteralK = 1021, vhpiCompConfigK = 1022, vhpiCompDeclK = 1023, vhpiCompInstStmtK = 1024, vhpiCondSigAssignStmtK = 1025, vhpiCondWaveformK = 1026, vhpiConfigDeclK = 1027, vhpiConstDeclK = 1028, vhpiConstParamDeclK = 1029, vhpiConvFuncK = 1030, vhpiDerefObjK = 1031, vhpiDisconnectSpecK = 1032, vhpiDriverK = 1033, vhpiDriverCollectionK = 1034, vhpiElemAssocK = 1035, vhpiElemDeclK = 1036, vhpiEntityClassEntryK = 1037, vhpiEntityDeclK = 1038, vhpiEnumLiteralK = 1039, vhpiEnumRangeK = 1040, vhpiEnumTypeDeclK = 1041, vhpiExitStmtK = 1042, vhpiFileDeclK = 1043, vhpiFileParamDeclK = 1044, vhpiFileTypeDeclK = 1045, vhpiFloatRangeK = 1046, vhpiFloatTypeDeclK = 1047, vhpiForGenerateK = 1048, vhpiForLoopK = 1049, vhpiForeignfK = 1050, vhpiFuncCallK = 1051, vhpiFuncDeclK = 1052, vhpiGenericDeclK = 1053, vhpiGroupDeclK = 1054, vhpiGroupTempDeclK = 1055, vhpiIfGenerateK = 1056, vhpiIfStmtK = 1057, vhpiInPortK = 1058, vhpiIndexedNameK = 1059, vhpiIntLiteralK = 1060, vhpiIntRangeK = 1061, vhpiIntTypeDeclK = 1062, vhpiIteratorK = 1063, vhpiLibraryDeclK = 1064, vhpiLoopStmtK = 1065, vhpiNextStmtK = 1066, vhpiNullLiteralK = 1067, vhpiNullStmtK = 1068, vhpiOperatorK = 1069, vhpiOthersK = 1070, vhpiOutPortK = 1071, vhpiPackBodyK = 1072, vhpiPackDeclK = 1073, vhpiPackInstK = 1074, vhpiParamAttrNameK = 1075, vhpiPhysLiteralK = 1076, vhpiPhysRangeK = 1077, vhpiPhysTypeDeclK = 1078, vhpiPortDeclK = 1079, vhpiProcCallStmtK = 1080, vhpiProcDeclK = 1081, vhpiProcessStmtK = 1082, vhpiProtectedTypeK = 1083, vhpiProtectedTypeBodyK = 1084, vhpiProtectedTypeDeclK = 1085, vhpiRealLiteralK = 1086, vhpiRecordTypeDeclK = 1087, vhpiReportStmtK = 1088, vhpiReturnStmtK = 1089, vhpiRootInstK = 1090, vhpiSelectSigAssignStmtK = 1091, vhpiSelectWaveformK = 1092, vhpiSelectedNameK = 1093, vhpiSigDeclK = 1094, vhpiSigParamDeclK = 1095, vhpiSimpAttrNameK = 1096, vhpiSimpleSigAssignStmtK = 1097, vhpiSliceNameK = 1098, vhpiStringLiteralK = 1099, vhpiSubpBodyK = 1100, vhpiSubtypeDeclK = 1101, vhpiSubtypeIndicK = 1102, /* DEPRECATED */ vhpiToolK = 1103, vhpiTransactionK = 1104, vhpiTypeConvK = 1105, vhpiUnaryExprK = 1106, /* DEPRECATED */ vhpiUnitDeclK = 1107, vhpiUserAttrNameK = 1108, vhpiVarAssignStmtK = 1109, vhpiVarDeclK = 1110, vhpiVarParamDeclK = 1111, vhpiWaitStmtK = 1112, vhpiWaveformElemK = 1113, vhpiWhileLoopK = 1114, vhpiQualifiedExprK = 1115, #ifndef IUS vhpiUseClauseK = 1116, #else vhpiUseClauseK = 1200, #endif #ifdef VHPIEXTEND_CLASSES VHPIEXTEND_CLASSES #endif /* private vendor extensions */ vhpiVerilog = 1117, vhpiEdifUnit = 1118, vhpiCollectionK = 1119, vhpiVHDL = 1120, vhpiSystemC = 1121 } vhpiClassKindT; /************** methods used to traverse 1 to 1 relationships *******************/ typedef enum { vhpiAbstractLiteral = 1301, vhpiActual = 1302, vhpiAll = 1303, vhpiAttrDecl = 1304, vhpiAttrSpec = 1305, vhpiBaseType = 1306, vhpiBaseUnit = 1307, vhpiBasicSignal = 1308, vhpiBlockConfig = 1309, vhpiCaseExpr = 1310, vhpiCondExpr = 1311, vhpiConfigDecl = 1312, vhpiConfigSpec = 1313, vhpiConstraint = 1314, vhpiContributor = 1315, vhpiCurCallback = 1316, vhpiCurEqProcess = 1317, vhpiCurStackFrame = 1318, vhpiDerefObj = 1319, vhpiDecl = 1320, vhpiDesignUnit = 1321, vhpiDownStack = 1322, vhpiElemSubtype = 1323, /* DEPRECATED */ vhpiEntityAspect = 1324, vhpiEntityDecl = 1325, vhpiEqProcessStmt = 1326, vhpiExpr = 1327, vhpiFormal = 1328, vhpiFuncDecl = 1329, vhpiGroupTempDecl = 1330, vhpiGuardExpr = 1331, vhpiGuardSig = 1332, vhpiImmRegion = 1333, vhpiInPort = 1334, vhpiInitExpr = 1335, vhpiIterScheme = 1336, vhpiLeftExpr = 1337, vhpiLexicalScope = 1338, vhpiLhsExpr = 1339, vhpiLocal = 1340, vhpiLogicalExpr = 1341, vhpiName = 1342, vhpiOperator = 1343, vhpiOthers = 1344, vhpiOutPort = 1345, vhpiParamDecl = 1346, vhpiParamExpr = 1347, vhpiParent = 1348, vhpiPhysLiteral = 1349, vhpiPrefix = 1350, vhpiPrimaryUnit = 1351, vhpiProtectedTypeBody = 1352, vhpiProtectedTypeDecl = 1353, vhpiRejectTime = 1354, vhpiReportExpr = 1355, vhpiResolFunc = 1356, vhpiReturnExpr = 1357, vhpiReturnTypeMark = 1358, /* DEPRECATED */ vhpiRhsExpr = 1359, vhpiRightExpr = 1360, vhpiRootInst = 1361, vhpiSelectExpr = 1362, vhpiSeverityExpr = 1363, vhpiSimpleName = 1364, vhpiSubpBody = 1365, vhpiSubpDecl = 1366, vhpiSubtype = 1367, /* DEPRECATED */ vhpiSuffix = 1368, vhpiTimeExpr = 1369, vhpiTimeOutExpr = 1370, vhpiTool = 1371, vhpiType = 1372, vhpiTypeMark = 1373, /* DEPRECATED */ vhpiTypespec , vhpiUnitDecl = 1374, vhpiUpStack = 1375, vhpiUpperRegion = 1376, vhpiUse = 1377, vhpiValExpr = 1378, vhpiValSubtype = 1379, /* DEPRECATED */ vhpiElemType = 1380, vhpiFirstNamedType = 1381, vhpiReturnType = 1382, vhpiValType = 1383, vhpiCurRegion = 1384 #ifdef VHPIEXTEND_ONE_METHODS VHPIEXTEND_ONE_METHODS #endif } vhpiOneToOneT; /************** methods used to traverse 1 to many relationships *******************/ typedef enum { vhpiAliasDecls = 1501, vhpiArgvs = 1502, vhpiAttrDecls = 1503, vhpiAttrSpecs = 1504, vhpiBasicSignals = 1505, vhpiBlockStmts = 1506, vhpiBranchs = 1507, /* 1508 */ vhpiChoices = 1509, vhpiCompInstStmts = 1510, vhpiCondExprs = 1511, vhpiCondWaveforms = 1512, vhpiConfigItems = 1513, vhpiConfigSpecs = 1514, vhpiConstDecls = 1515, vhpiConstraints = 1516, vhpiContributors = 1517, /* 1518 */ vhpiDecls = 1519, vhpiDepUnits = 1520, vhpiDesignUnits = 1521, vhpiDrivenSigs = 1522, vhpiDrivers = 1523, vhpiElemAssocs = 1524, vhpiEntityClassEntrys = 1525, vhpiEntityDesignators = 1526, vhpiEnumLiterals = 1527, vhpiForeignfs = 1528, vhpiGenericAssocs = 1529, vhpiGenericDecls = 1530, vhpiIndexExprs = 1531, vhpiIndexedNames = 1532, vhpiInternalRegions = 1533, vhpiMembers = 1534, vhpiPackInsts = 1535, vhpiParamAssocs = 1536, vhpiParamDecls = 1537, vhpiPortAssocs = 1538, vhpiPortDecls = 1539, vhpiRecordElems = 1540, vhpiSelectWaveforms = 1541, vhpiSelectedNames = 1542, vhpiSensitivitys = 1543, vhpiSeqStmts = 1544, vhpiSigAttrs = 1545, vhpiSigDecls = 1546, vhpiSigNames = 1547, vhpiSignals = 1548, vhpiSpecNames = 1549, vhpiSpecs = 1550, vhpiStmts = 1551, vhpiTransactions = 1552, vhpiTypeMarks = 1553, /* DEPRECATED */ vhpiUnitDecls = 1554, vhpiUses = 1555, vhpiVarDecls = 1556, vhpiWaveformElems = 1557, vhpiLibraryDecls = 1558, vhpiLocalLoads = 1559, vhpiOptimizedLoads = 1560, vhpiTypes = 1561, #ifndef IUS vhpiUseClauses = 1562, #else vhpiUseClauses = 1650, #endif #ifdef VHPIEXTEND_MANY_METHODS VHPIEXTEND_MANY_METHODS #endif vhpiCallbacks = 1563, vhpiCurRegions = 1564 } vhpiOneToManyT; /****************** PROPERTIES *******************/ /******* INTEGER or BOOLEAN PROPERTIES **********/ typedef enum { vhpiAccessP = 1001, vhpiArgcP = 1002, vhpiAttrKindP = 1003, vhpiBaseIndexP = 1004, vhpiBeginLineNoP = 1005, vhpiEndLineNoP = 1006, vhpiEntityClassP = 1007, vhpiForeignKindP = 1008, vhpiFrameLevelP = 1009, vhpiGenerateIndexP = 1010, vhpiIntValP = 1011, vhpiIsAnonymousP = 1012, vhpiIsBasicP = 1013, vhpiIsCompositeP = 1014, vhpiIsDefaultP = 1015, vhpiIsDeferredP = 1016, vhpiIsDiscreteP = 1017, vhpiIsForcedP = 1018, vhpiIsForeignP = 1019, vhpiIsGuardedP = 1020, vhpiIsImplicitDeclP = 1021, vhpiIsInvalidP = 1022, /* DEPRECATED */ vhpiIsLocalP = 1023, vhpiIsNamedP = 1024, vhpiIsNullP = 1025, vhpiIsOpenP = 1026, vhpiIsPLIP = 1027, vhpiIsPassiveP = 1028, vhpiIsPostponedP = 1029, vhpiIsProtectedTypeP = 1030, vhpiIsPureP = 1031, vhpiIsResolvedP = 1032, vhpiIsScalarP = 1033, vhpiIsSeqStmtP = 1034, vhpiIsSharedP = 1035, vhpiIsTransportP = 1036, vhpiIsUnaffectedP = 1037, vhpiIsUnconstrainedP = 1038, vhpiIsUninstantiatedP = 1039, vhpiIsUpP = 1040, vhpiIsVitalP = 1041, vhpiIteratorTypeP = 1042, vhpiKindP = 1043, vhpiLeftBoundP = 1044, vhpiLevelP = 1045, /* DEPRECATED */ vhpiLineNoP = 1046, vhpiLineOffsetP = 1047, vhpiLoopIndexP = 1048, vhpiModeP = 1049, vhpiNumDimensionsP = 1050, vhpiNumFieldsP = 1051, /* DEPRECATED */ vhpiNumGensP = 1052, vhpiNumLiteralsP = 1053, vhpiNumMembersP = 1054, vhpiNumParamsP = 1055, vhpiNumPortsP = 1056, vhpiOpenModeP = 1057, vhpiPhaseP = 1058, vhpiPositionP = 1059, vhpiPredefAttrP = 1060, /* 1061 */ vhpiReasonP = 1062, vhpiRightBoundP = 1063, vhpiSigKindP = 1064, vhpiSizeP = 1065, vhpiStartLineNoP = 1066, vhpiStateP = 1067, vhpiStaticnessP = 1068, vhpiVHDLversionP = 1069, vhpiIdP = 1070, vhpiCapabilitiesP = 1071, #ifdef VHPIEXTEND_INT_PROPERTIES VHPIEXTEND_INT_PROPERTIES #endif vhpiIsStdLogicP = 1072, vhpiIsStdULogicP = 1073, vhpiIsStdLogicVectorP = 1074, vhpiIsStdULogicVectorP = 1075, # vhpiLanguageP = 1200 } vhpiIntPropertyT; /******* STRING PROPERTIES **********/ typedef enum { vhpiCaseNameP = 1301, vhpiCompNameP = 1302, vhpiDefNameP = 1303, vhpiFileNameP = 1304, vhpiFullCaseNameP = 1305, vhpiFullNameP = 1306, vhpiKindStrP = 1307, vhpiLabelNameP = 1308, vhpiLibLogicalNameP = 1309, vhpiLibPhysicalNameP = 1310, vhpiLogicalNameP = 1311, vhpiLoopLabelNameP = 1312, vhpiNameP = 1313, vhpiOpNameP = 1314, vhpiStrValP = 1315, vhpiToolVersionP = 1316, vhpiUnitNameP = 1317, vhpiSaveRestartLocationP = 1318, /* Cadence IUS/Xcelium */ vhpiFullVlogNameP = 1500, /* Full path name (VHDL names are Verilogized) */ vhpiFullVHDLNameP = 1501, /* Full path name (Verilog names are vhdlized) */ vhpiFullLSNameP = 1502, /* Full path name (Upper case) using ':' and '.' separators */ vhpiFullLSCaseNameP = 1503 /* Full path name (VHDL case sensitive) */ #ifdef VHPIEXTEND_STR_PROPERTIES VHPIEXTEND_STR_PROPERTIES #endif } vhpiStrPropertyT; /******* REAL PROPERTIES **********/ typedef enum { vhpiFloatLeftBoundP = 1601, vhpiFloatRightBoundP = 1602, vhpiRealValP = 1603 #ifdef VHPIEXTEND_REAL_PROPERTIES VHPIEXTEND_REAL_PROPERTIES #endif } vhpiRealPropertyT; /******* PHYSICAL PROPERTIES **********/ typedef enum { vhpiPhysLeftBoundP = 1651, vhpiPhysPositionP = 1652, vhpiPhysRightBoundP = 1653, vhpiPhysValP = 1654, vhpiPrecisionP = 1655, /* DEPRECATED */ vhpiSimTimeUnitP = 1656, /* DEPRECATED */ vhpiResolutionLimitP = 1657 #ifdef VHPIEXTEND_PHYS_PROPERTIES VHPIEXTEND_PHYS_PROPERTIES #endif } vhpiPhysPropertyT; /******************* PROPERTY VALUES ************************/ /* vhpiCapabilitiesP */ typedef enum { vhpiProvidesHierarchy = 1, vhpiProvidesStaticAccess = 2, vhpiProvidesConnectivity = 4, vhpiProvidesPostAnalysis = 8, vhpiProvidesForeignModel = 16, vhpiProvidesAdvancedForeignModel = 32, vhpiProvidesSaveRestart = 64, vhpiProvidesReset = 128, vhpiProvidesDebugRuntime = 256, vhpiProvidesAdvancedDebugRuntime = 512, vhpiProvidesDynamicElab = 1024 } vhpiCapabibilityT; /* vhpiOpenModeP */ typedef enum { vhpiInOpen = 1001, vhpiOutOpen = 1002, vhpiReadOpen = 1003, vhpiWriteOpen = 1004, vhpiAppendOpen = 1005 } vhpiOpenModeT; /* vhpiModeP */ typedef enum { vhpiInMode = 1001, vhpiOutMode = 1002, vhpiInoutMode = 1003, vhpiBufferMode = 1004, vhpiLinkageMode = 1005 } vhpiModeT; /* vhpiSigKindP */ typedef enum { vhpiRegister = 1001, vhpiBus = 1002, vhpiNormal = 1003 } vhpiSigKindT; /* vhpiStaticnessP */ typedef enum { vhpiLocallyStatic = 1001, vhpiGloballyStatic = 1002, vhpiDynamic = 1003 } vhpiStaticnessT; /* vhpiPredefAttrP */ typedef enum { vhpiActivePA = 1001, vhpiAscendingPA = 1002, vhpiBasePA = 1003, vhpiDelayedPA = 1004, vhpiDrivingPA = 1005, vhpiDriving_valuePA = 1006, vhpiEventPA = 1007, vhpiHighPA = 1008, vhpiImagePA = 1009, vhpiInstance_namePA = 1010, vhpiLast_activePA = 1011, vhpiLast_eventPA = 1012, vhpiLast_valuePA = 1013, vhpiLeftPA = 1014, vhpiLeftofPA = 1015, vhpiLengthPA = 1016, vhpiLowPA = 1017, vhpiPath_namePA = 1018, vhpiPosPA = 1019, vhpiPredPA = 1020, vhpiQuietPA = 1021, vhpiRangePA = 1022, vhpiReverse_rangePA = 1023, vhpiRightPA = 1024, vhpiRightofPA = 1025, vhpiSimple_namePA = 1026, vhpiStablePA = 1027, vhpiSuccPA = 1028, vhpiTransactionPA = 1029, vhpiValPA = 1030, vhpiValuePA = 1031 } vhpiPredefAttrT; /* vhpiAttrKindP */ typedef enum { vhpiFunctionAK = 1, vhpiRangeAK = 2, vhpiSignalAK = 3, vhpiTypeAK = 4, vhpiValueAK = 5 #ifdef VHPIEXTEND_INT_ATTR VHPI_EXTEND_INT_ATTR #endif } vhpiAttrKindT; /* vhpiEntityClassP */ typedef enum { vhpiEntityEC = 1001, vhpiArchitectureEC = 1002, vhpiConfigurationEC = 1003, vhpiProcedureEC = 1004, vhpiFunctionEC = 1005, vhpiPackageEC = 1006, vhpiTypeEC = 1007, vhpiSubtypeEC = 1008, vhpiConstantEC = 1009, vhpiSignalEC = 1010, vhpiVariableEC = 1011, vhpiComponentEC = 1012, vhpiLabelEC = 1013, vhpiLiteralEC = 1014, vhpiUnitsEC = 1015, vhpiFileEC = 1016, vhpiGroupEC = 1017 } vhpiEntityClassT; /* vhpiAccessP */ typedef enum { vhpiRead = 1, vhpiWrite = 2, vhpiConnectivity = 4, vhpiNoAccess = 8 } vhpiAccessT; /* value for vhpiStateP property for callbacks */ typedef enum { vhpiEnable, vhpiDisable, vhpiMature /* callback has occurred */ } vhpiStateT; /* enumeration type for vhpiCompInstKindP property */ typedef enum { vhpiDirect, vhpiComp, vhpiConfig } vhpiCompInstKindT; /* the following values are used only for the vhpiResolutionLimitP property and for setting the unit field of the value structure; they represent the physical position of a given VHDL time unit */ /* time unit physical position values {high, low} */ PLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiFS; PLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiPS; PLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiNS; PLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiUS; PLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiMS; PLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiS; PLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiMN; PLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiHR; /* IEEE std_logic values */ #define vhpiU 0 /* uninitialized */ #define vhpiX 1 /* unknown */ #define vhpi0 2 /* forcing 0 */ #define vhpi1 3 /* forcing 1 */ #define vhpiZ 4 /* high impedance */ #define vhpiW 5 /* weak unknown */ #define vhpiL 6 /* weak 0 */ #define vhpiH 7 /* weak 1 */ #define vhpiDontCare 8 /* don't care */ /* IEEE std bit values */ #define vhpibit0 0 /* bit 0 */ #define vhpibit1 1 /* bit 1 */ /* IEEE std boolean values */ #define vhpiFalse 0 /* false */ #define vhpiTrue 1 /* true */ /************** vhpiPhaseP property values *************/ typedef enum { vhpiRegistrationPhase = 1, vhpiAnalysisPhase = 2, vhpiElaborationPhase = 3, vhpiInitializationPhase = 4, vhpiSimulationPhase = 5, vhpiTerminationPhase = 6, vhpiSavePhase = 7, vhpiRestartPhase = 8, vhpiResetPhase = 9 } vhpiPhaseT ; /**************** PLI error information structure ****************/ typedef enum { vhpiNote = 1, vhpiWarning = 2, vhpiError = 3, vhpiFailure = 6, vhpiSystem = 4, vhpiInternal = 5 } vhpiSeverityT; typedef struct vhpiErrorInfoS { vhpiSeverityT severity; char *message; char *str; char *file; /* Name of the VHDL file where the VHPI error originated */ int32_t line; /* Line number in the VHDL file */ } vhpiErrorInfoT; /********************* callback structures ************************/ /* callback user data structure */ typedef struct vhpiCbDataS { int32_t reason; /* callback reason */ void (*cb_rtn) (const struct vhpiCbDataS *); /* call routine */ vhpiHandleT obj; /* trigger object */ vhpiTimeT *time; /* callback time */ vhpiValueT *value; /* trigger object value */ void *user_data; /* pointer to user data to be passed to the callback function */ } vhpiCbDataT; /**************************** CALLBACK REASONS ****************************/ /*************************** Simulation object related ***********************/ /* These are repetitive callbacks */ #define vhpiCbValueChange 1001 #define vhpiCbForce 1002 #define vhpiCbRelease 1003 #define vhpiCbTransaction 1004 /* optional callback reason */ /****************************** Statement related ****************************/ /* These are repetitive callbacks */ #define vhpiCbStmt 1005 #define vhpiCbResume 1006 #define vhpiCbSuspend 1007 #define vhpiCbStartOfSubpCall 1008 #define vhpiCbEndOfSubpCall 1009 /****************************** Time related ******************************/ /* the Rep callback reasons are the repeated versions of the callbacks */ #define vhpiCbAfterDelay 1010 #define vhpiCbRepAfterDelay 1011 /*************************** Simulation cycle phase related *****************/ #define vhpiCbNextTimeStep 1012 #define vhpiCbRepNextTimeStep 1013 #define vhpiCbStartOfNextCycle 1014 #define vhpiCbRepStartOfNextCycle 1015 #define vhpiCbStartOfProcesses 1016 #define vhpiCbRepStartOfProcesses 1017 #define vhpiCbEndOfProcesses 1018 #define vhpiCbRepEndOfProcesses 1019 #define vhpiCbLastKnownDeltaCycle 1020 #define vhpiCbRepLastKnownDeltaCycle 1021 #define vhpiCbStartOfPostponed 1022 #define vhpiCbRepStartOfPostponed 1023 #define vhpiCbEndOfTimeStep 1024 #define vhpiCbRepEndOfTimeStep 1025 /***************************** Action related *****************************/ /* these are one time callback unless otherwise noted */ #define vhpiCbStartOfTool 1026 #define vhpiCbEndOfTool 1027 #define vhpiCbStartOfAnalysis 1028 #define vhpiCbEndOfAnalysis 1029 #define vhpiCbStartOfElaboration 1030 #define vhpiCbEndOfElaboration 1031 #define vhpiCbStartOfInitialization 1032 #define vhpiCbEndOfInitialization 1033 #define vhpiCbStartOfSimulation 1034 #define vhpiCbEndOfSimulation 1035 #define vhpiCbQuiescense 1036 /* repetitive */ #define vhpiCbPLIError 1037 /* repetitive */ #define vhpiCbStartOfSave 1038 #define vhpiCbEndOfSave 1039 #define vhpiCbStartOfRestart 1040 #define vhpiCbEndOfRestart 1041 #define vhpiCbStartOfReset 1042 #define vhpiCbEndOfReset 1043 #define vhpiCbEnterInteractive 1044 /* repetitive */ #define vhpiCbExitInteractive 1045 /* repetitive */ #define vhpiCbSigInterrupt 1046 /* repetitive */ /* Foreign model callbacks */ #define vhpiCbTimeOut 1047 /* non repetitive */ #define vhpiCbRepTimeOut 1048 /* repetitive */ #define vhpiCbSensitivity 1049 /* repetitive */ /**************************** CALLBACK FLAGS ******************************/ #define vhpiReturnCb 0x00000001 #define vhpiDisableCb 0x00000010 /************** vhpiAutomaticRestoreP property values *************/ typedef enum { vhpiRestoreAll = 1, vhpiRestoreUserData = 2, vhpiRestoreHandles = 4, vhpiRestoreCallbacks = 8 } vhpiAutomaticRestoreT; /******************** FUNCTION DECLARATIONS *********************/ XXTERN int vhpi_assert (vhpiSeverityT severity, const char *formatmsg, ...); /* callback related */ XXTERN vhpiHandleT vhpi_register_cb (vhpiCbDataT *cb_data_p, int32_t flags); XXTERN int vhpi_remove_cb (vhpiHandleT cb_obj); XXTERN int vhpi_disable_cb (vhpiHandleT cb_obj); XXTERN int vhpi_enable_cb (vhpiHandleT cb_obj); XXTERN int vhpi_get_cb_info (vhpiHandleT object, vhpiCbDataT *cb_data_p); /* utilities for sensitivity-set bitmaps */ /* The replacement text for these macros is implementation defined */ /* The behavior is specified in G.1 */ XXTERN int vhpi_sens_first (vhpiValueT *sens); XXTERN int vhpi_sens_zero (vhpiValueT *sens); XXTERN int vhpi_sens_clr (int obj, vhpiValueT *sens); XXTERN int vhpi_sens_set (int obj, vhpiValueT *sens); XXTERN int vhpi_sens_isset (int obj, vhpiValueT *sens); #define VHPI_SENS_ZERO(sens) vhpi_sens_zero(sens) #define VHPI_SENS_SET(obj, sens) vhpi_sens_set(obj, sens) #define VHPI_SENS_CLR(obj, sens) vhpi_sens_clr(obj, sens) #define VHPI_SENS_ISSET(obj, sens) vhpi_sens_isset(obj, sens) #define VHPI_SENS_FIRST(sens) vhpi_sens_first(sens) /* for obtaining handles */ XXTERN vhpiHandleT vhpi_handle_by_name (const char *name, vhpiHandleT scope); XXTERN vhpiHandleT vhpi_handle_by_index (vhpiOneToManyT itRel, vhpiHandleT parent, int32_t indx); /* for traversing relationships */ XXTERN vhpiHandleT vhpi_handle (vhpiOneToOneT type, vhpiHandleT referenceHandle); XXTERN vhpiHandleT vhpi_iterator (vhpiOneToManyT type, vhpiHandleT referenceHandle); XXTERN vhpiHandleT vhpi_scan (vhpiHandleT iterator); /* for processsing properties */ XXTERN vhpiIntT vhpi_get (vhpiIntPropertyT property, vhpiHandleT object); XXTERN const vhpiCharT * vhpi_get_str (vhpiStrPropertyT property, vhpiHandleT object); XXTERN vhpiRealT vhpi_get_real (vhpiRealPropertyT property, vhpiHandleT object); XXTERN vhpiPhysT vhpi_get_phys (vhpiPhysPropertyT property, vhpiHandleT object); /* for access to protected types */ typedef int (*vhpiUserFctT)(void); XXTERN int vhpi_protected_call (vhpiHandleT varHdl, vhpiUserFctT userFct, void *userData); /* value processing */ /* vhpi_put_value flags */ typedef enum { vhpiDeposit, vhpiDepositPropagate, vhpiForce, vhpiForcePropagate, vhpiRelease, vhpiSizeConstraint } vhpiPutValueModeT; typedef enum { vhpiInertial, vhpiTransport } vhpiDelayModeT; XXTERN int vhpi_get_value (vhpiHandleT expr, vhpiValueT *value_p); XXTERN int vhpi_put_value (vhpiHandleT object, vhpiValueT *value_p, vhpiPutValueModeT flags); XXTERN int vhpi_schedule_transaction (vhpiHandleT drivHdl, vhpiValueT *value_p, uint32_t numValues, vhpiTimeT *delayp, vhpiDelayModeT delayMode, vhpiTimeT *pulseRejp); XXTERN int vhpi_format_value (const vhpiValueT *in_value_p, vhpiValueT *out_value_p); /* time processing */ XXTERN void vhpi_get_time (vhpiTimeT *time_p, long *cycles); #define vhpiNoActivity -1 XXTERN int vhpi_get_next_time (vhpiTimeT *time_p); /* simulation control */ typedef enum { vhpiStop = 0, vhpiFinish = 1, vhpiReset = 2 #ifdef VHPIEXTEND_CONTROL VHPIEXTEND_CONTROL #endif } vhpiSimControlT; XXTERN int vhpi_control (vhpiSimControlT command, ...); XXTERN int vhpi_sim_control (vhpiSimControlT command); /* for compatibility reasons */ /* I/O routine */ XXTERN int vhpi_printf (const char *format, ...); XXTERN int vhpi_vprintf (const char *format, va_list args); /* utilities to print VHDL strings */ XXTERN int vhpi_is_printable(char ch); /* utility routines */ XXTERN int vhpi_compare_handles (vhpiHandleT handle1, vhpiHandleT handle2); XXTERN int vhpi_check_error (vhpiErrorInfoT *error_info_p); XXTERN int vhpi_release_handle (vhpiHandleT object); /* creation functions */ XXTERN vhpiHandleT vhpi_create (vhpiClassKindT kind, vhpiHandleT handle1, vhpiHandleT handle2); /* Foreign model data structures and functions */ typedef enum { vhpiArchF = 1, vhpiArchFK = 1, /* for compatibility reasons */ vhpiFuncF = 2, vhpiFuncFK = 2, /* for compatibility reasons */ vhpiProcF = 3, vhpiProcFK = 3, /* for compatibility reasons */ vhpiLibF = 4, vhpiAppF = 5 } vhpiForeignT; typedef struct vhpiForeignDataS { vhpiForeignT kind; char * libraryName; char * modelName; void (*elabf)(const struct vhpiCbDataS *cb_data_p); void (*execf)(const struct vhpiCbDataS *cb_data_p); } vhpiForeignDataT; XXTERN vhpiHandleT vhpi_register_foreignf (vhpiForeignDataT *foreignDatap); XXTERN int vhpi_get_foreignf_info (vhpiHandleT hdl, vhpiForeignDataT *foreignDatap); /* vhpi_get_foreign_info is DEPRECATED */ XXTERN int vhpi_get_foreign_info (vhpiHandleT hdl, vhpiForeignDataT *foreignDatap); /* for saving and restoring foreign models data */ XXTERN size_t vhpi_get_data (int32_t id, void *dataLoc, size_t numBytes); XXTERN size_t vhpi_put_data (int32_t id, void *dataLoc, size_t numBytes); #ifdef VHPIEXTEND_FUNCTIONS VHPIEXTEND_FUNCTIONS #endif /* Visual Elite integration - Cause & Effect support Function returns instance handle for specified signal Warning!!! Function each time allocates new handle for returned instance, so you should free it !!! */ XXTERN vhpiHandleT vhpi_get_cause_instance (vhpiHandleT sigHandle); /* Function returns source point number to code which made event on specified signal */ XXTERN int vhpi_get_cause (vhpiHandleT sigHandle, unsigned int** p2MagicNumbersBuffer); /* Function returns info about line nr and instance hierarchy path for specified source point nr and instance handle returns: For invalid source point: *pnLineNr == -1 For insufficient buffer size, returns required buffer size For invalid args function returns -1 If all is OK, function returns 0 */ XXTERN int vhpi_get_cause_info (const unsigned int** pn2MagicNumbers, int nBufLen, char* pszHierScopeBuf, int nFilePathBufLen, char* pszSourceFilePathBuf, int* pnLineNr); /* * vhpi_value_size() * * Description: * The vhpi_value_size() function lets you query the size in bytes * required for a buffer to store the value of the specified object handle * in the specified format. Use this function to allocate memory for the * appropriate field of the value structure before using * vphi_get_value() or vhpi_put_value(). * * Returns the size in bytes required for a buffer to store the value of * the specified object handle in the specified format. * * Syntax: vhpi_value_size(vhpiHandleT objHdl, vhpiFormatT format) * Returns: vhpiIntT Size in bytes * * Arguments: * VhpiHandleT objHdl Object handle whose value is needed. * VhpiFormatT format Format in which the value needs to be represented * *******************************************************************************/ XXTERN vhpiIntT vhpi_value_size (vhpiHandleT objHdl, vhpiFormatT format); /**************************** Typedef for VHPI bootstrap functions ****************************/ typedef void (*vhpiBootstrapFctT)(void); #undef PLI_EXTERN #undef PLI_VEXTERN #ifdef VHPI_USER_DEFINED_DLLISPEC #undef VHPI_USER_DEFINED_DLLISPEC #undef PLI_DLLISPEC #endif #ifdef VHPI_USER_DEFINED_DLLESPEC #undef VHPI_USER_DEFINED_DLLESPEC #undef PLI_DLLESPEC #endif #ifdef PLI_PROTOTYPES #undef PLI_PROTOTYPES #undef XXTERN #undef EETERN #endif #ifdef __cplusplus } #endif #pragma pack() #endif /* VHPI_USER_H */ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3447025 cocotb-2.0.1/src/cocotb/_vendor/vpi/0000755000175100017510000000000015106070715016725 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/vpi/sv_vpi_user.h0000644000175100017510000006236415106067236021461 0ustar00runnerrunner/*************************************************************************** * sv_vpi_user.h * * SystemVerilog VPI extensions. * * This file contains the constant definitions, structure definitions, and * routine declarations used by the SystemVerilog Verification Procedural * Interface (VPI) access routines. * ***************************************************************************/ /*************************************************************************** * NOTE: * The constant values 600 through 999 are reserved for use in this file. * - the range 600-749 is reserved for SV VPI model extensions * - the range 750-779 is reserved for the Coverage VPI * - the range 800-899 is reserved for future use * Overlaps in the numerical ranges are permitted for different categories * of identifiers; e.g. * - object types * - properties * - callbacks **************************************************************************/ #ifndef SV_VPI_USER_H #define SV_VPI_USER_H #include "_vendor/vpi/vpi_user.h" #ifdef __cplusplus extern "C" { #endif /****************************** OBJECT TYPES ******************************/ #define vpiPackage 600 #define vpiInterface 601 #define vpiProgram 602 #define vpiInterfaceArray 603 #define vpiProgramArray 604 #define vpiTypespec 605 #define vpiModport 606 #define vpiInterfaceTfDecl 607 #define vpiRefObj 608 #define vpiTypeParameter 609 /* variables */ #define vpiVarBit vpiRegBit #define vpiLongIntVar 610 #define vpiShortIntVar 611 #define vpiIntVar 612 #define vpiShortRealVar 613 #define vpiByteVar 614 #define vpiClassVar 615 #define vpiStringVar 616 #define vpiEnumVar 617 #define vpiStructVar 618 #define vpiUnionVar 619 #define vpiBitVar 620 #define vpiLogicVar vpiReg #define vpiArrayVar vpiRegArray #define vpiClassObj 621 #define vpiChandleVar 622 #define vpiPackedArrayVar 623 #define vpiVirtualInterfaceVar 728 /* typespecs */ #define vpiLongIntTypespec 625 #define vpiShortRealTypespec 626 #define vpiByteTypespec 627 #define vpiShortIntTypespec 628 #define vpiIntTypespec 629 #define vpiClassTypespec 630 #define vpiStringTypespec 631 #define vpiChandleTypespec 632 #define vpiEnumTypespec 633 #define vpiEnumConst 634 #define vpiIntegerTypespec 635 #define vpiTimeTypespec 636 #define vpiRealTypespec 637 #define vpiStructTypespec 638 #define vpiUnionTypespec 639 #define vpiBitTypespec 640 #define vpiLogicTypespec 641 #define vpiArrayTypespec 642 #define vpiVoidTypespec 643 #define vpiTypespecMember 644 #define vpiPackedArrayTypespec 692 #define vpiSequenceTypespec 696 #define vpiPropertyTypespec 697 #define vpiEventTypespec 698 #define vpiInterfaceTypespec 906 #define vpiClockingBlock 650 #define vpiClockingIODecl 651 #define vpiClassDefn 652 #define vpiConstraint 653 #define vpiConstraintOrdering 654 #define vpiDistItem 645 #define vpiAliasStmt 646 #define vpiThread 647 #define vpiMethodFuncCall 648 #define vpiMethodTaskCall 649 /* concurrent assertions */ #define vpiAssert 686 #define vpiAssume 687 #define vpiCover 688 #define vpiRestrict 901 #define vpiDisableCondition 689 #define vpiClockingEvent 690 /* property decl, spec */ #define vpiPropertyDecl 655 #define vpiPropertySpec 656 #define vpiPropertyExpr 657 #define vpiMulticlockSequenceExpr 658 #define vpiClockedSeq 659 #define vpiClockedProp 902 #define vpiPropertyInst 660 #define vpiSequenceDecl 661 #define vpiCaseProperty 662 /* property case */ #define vpiCasePropertyItem 905 /* property case item */ #define vpiSequenceInst 664 #define vpiImmediateAssert 665 #define vpiImmediateAssume 694 #define vpiImmediateCover 695 #define vpiReturn 666 /* pattern */ #define vpiAnyPattern 667 #define vpiTaggedPattern 668 #define vpiStructPattern 669 /* do .. while */ #define vpiDoWhile 670 /* waits */ #define vpiOrderedWait 671 #define vpiWaitFork 672 /* disables */ #define vpiDisableFork 673 #define vpiExpectStmt 674 #define vpiForeachStmt 675 #define vpiReturnStmt 691 #define vpiFinal 676 #define vpiExtends 677 #define vpiDistribution 678 #define vpiSeqFormalDecl 679 #define vpiPropFormalDecl 699 #define vpiArrayNet vpiNetArray #define vpiEnumNet 680 #define vpiIntegerNet 681 #define vpiLogicNet vpiNet #define vpiTimeNet 682 #define vpiStructNet 683 #define vpiBreak 684 #define vpiContinue 685 #define vpiPackedArrayNet 693 #define vpiConstraintExpr 747 #define vpiElseConst 748 #define vpiImplication 749 #define vpiConstrIf 738 #define vpiConstrIfElse 739 #define vpiConstrForEach 736 #define vpiSoftDisable 733 #define vpiLetDecl 903 #define vpiLetExpr 904 /******************************** METHODS *********************************/ /************* methods used to traverse 1 to 1 relationships **************/ #define vpiActual 700 #define vpiTypedefAlias 701 #define vpiIndexTypespec 702 #define vpiBaseTypespec 703 #define vpiElemTypespec 704 #define vpiInputSkew 706 #define vpiOutputSkew 707 #define vpiGlobalClocking 708 #define vpiDefaultClocking 709 #define vpiDefaultDisableIff 710 #define vpiOrigin 713 #define vpiPrefix 714 #define vpiWith 715 #define vpiProperty 718 #define vpiValueRange 720 #define vpiPattern 721 #define vpiWeight 722 #define vpiConstraintItem 746 /************ methods used to traverse 1 to many relationships ************/ #define vpiTypedef 725 #define vpiImport 726 #define vpiDerivedClasses 727 #define vpiInterfaceDecl vpiVirtualInterfaceVar /* interface decl deprecated */ #define vpiMethods 730 #define vpiSolveBefore 731 #define vpiSolveAfter 732 #define vpiWaitingProcesses 734 #define vpiMessages 735 #define vpiLoopVars 737 #define vpiConcurrentAssertions 740 #define vpiMatchItem 741 #define vpiMember 742 #define vpiElement 743 /************* methods used to traverse 1 to many relationships ***************/ #define vpiAssertion 744 /*********** methods used to traverse both 1-1 and 1-many relations ***********/ #define vpiInstance 745 /**************************************************************************/ /************************ generic object properties ***********************/ /**************************************************************************/ #define vpiTop 600 #define vpiUnit 602 #define vpiJoinType 603 #define vpiJoin 0 #define vpiJoinNone 1 #define vpiJoinAny 2 #define vpiAccessType 604 #define vpiForkJoinAcc 1 #define vpiExternAcc 2 #define vpiDPIExportAcc 3 #define vpiDPIImportAcc 4 #define vpiArrayType 606 #define vpiStaticArray 1 #define vpiDynamicArray 2 #define vpiAssocArray 3 #define vpiQueueArray 4 #define vpiArrayMember 607 #define vpiIsRandomized 608 #define vpiLocalVarDecls 609 #define vpiOpStrong 656 /* strength of temporal operator */ #define vpiRandType 610 #define vpiNotRand 1 #define vpiRand 2 #define vpiRandC 3 #define vpiPortType 611 #define vpiInterfacePort 1 #define vpiModportPort 2 /* vpiPort is also a port type. It is defined in vpi_user.h */ #define vpiConstantVariable 612 #define vpiStructUnionMember 615 #define vpiVisibility 620 #define vpiPublicVis 1 #define vpiProtectedVis 2 #define vpiLocalVis 3 /* Return values for vpiConstType property */ #define vpiOneStepConst 9 #define vpiUnboundedConst 10 #define vpiNullConst 11 #define vpiAlwaysType 624 #define vpiAlwaysComb 2 #define vpiAlwaysFF 3 #define vpiAlwaysLatch 4 #define vpiDistType 625 #define vpiEqualDist 1 /* constraint equal distribution */ #define vpiDivDist 2 /* constraint divided distribution */ #define vpiPacked 630 #define vpiTagged 632 #define vpiRef 6 /* Return value for vpiDirection property */ #define vpiVirtual 635 #define vpiHasActual 636 #define vpiIsConstraintEnabled 638 #define vpiSoft 639 #define vpiClassType 640 #define vpiMailboxClass 1 #define vpiSemaphoreClass 2 #define vpiUserDefinedClass 3 #define vpiProcessClass 4 #define vpiMethod 645 #define vpiIsClockInferred 649 #define vpiIsDeferred 657 #define vpiIsFinal 670 #define vpiIsCoverSequence 659 #define vpiQualifier 650 #define vpiNoQualifier 0 #define vpiUniqueQualifier 1 #define vpiPriorityQualifier 2 #define vpiTaggedQualifier 4 #define vpiRandQualifier 8 #define vpiInsideQualifier 16 #define vpiInputEdge 651 /* returns vpiNoEdge, vpiPosedge, vpiNegedge */ #define vpiOutputEdge 652 /* returns vpiNoEdge, vpiPosedge, vpiNegedge */ #define vpiGeneric 653 /* Compatibility-mode property and values (object argument == NULL) */ #define vpiCompatibilityMode 654 #define vpiMode1364v1995 1 #define vpiMode1364v2001 2 #define vpiMode1364v2005 3 #define vpiMode1800v2005 4 #define vpiMode1800v2009 5 #define vpiPackedArrayMember 655 #define vpiStartLine 661 #define vpiColumn 662 #define vpiEndLine 663 #define vpiEndColumn 664 /* memory allocation scheme for transient objects */ #define vpiAllocScheme 658 #define vpiAutomaticScheme 1 #define vpiDynamicScheme 2 #define vpiOtherScheme 3 #define vpiObjId 660 #define vpiDPIPure 665 #define vpiDPIContext 666 #define vpiDPICStr 667 #define vpiDPI 1 #define vpiDPIC 2 #define vpiDPICIdentifier 668 #define vpiIsModPort 669 /******************************** Operators *******************************/ #define vpiImplyOp 50 /* -> implication operator */ #define vpiNonOverlapImplyOp 51 /* |=> nonoverlapped implication */ #define vpiOverlapImplyOp 52 /* |-> overlapped implication operator */ #define vpiAcceptOnOp 83 /* accept_on operator */ #define vpiRejectOnOp 84 /* reject_on operator */ #define vpiSyncAcceptOnOp 85 /* sync_accept_on operator */ #define vpiSyncRejectOnOp 86 /* sync_reject_on operator */ #define vpiOverlapFollowedByOp 87 /* overlapped followed_by operator */ #define vpiNonOverlapFollowedByOp 88 /* nonoverlapped followed_by operator */ #define vpiNexttimeOp 89 /* nexttime operator */ #define vpiAlwaysOp 90 /* always operator */ #define vpiEventuallyOp 91 /* eventually operator */ #define vpiUntilOp 92 /* until operator */ #define vpiUntilWithOp 93 /* until_with operator */ #define vpiUnaryCycleDelayOp 53 /* binary cycle delay (##) operator */ #define vpiCycleDelayOp 54 /* binary cycle delay (##) operator */ #define vpiIntersectOp 55 /* intersection operator */ #define vpiFirstMatchOp 56 /* first_match operator */ #define vpiThroughoutOp 57 /* throughout operator */ #define vpiWithinOp 58 /* within operator */ #define vpiRepeatOp 59 /* [=] nonconsecutive repetition */ #define vpiConsecutiveRepeatOp 60 /* [*] consecutive repetition */ #define vpiGotoRepeatOp 61 /* [->] goto repetition */ #define vpiPostIncOp 62 /* ++ post-increment */ #define vpiPreIncOp 63 /* ++ pre-increment */ #define vpiPostDecOp 64 /* -- post-decrement */ #define vpiPreDecOp 65 /* -- pre-decrement */ #define vpiMatchOp 66 /* match() operator */ #define vpiCastOp 67 /* type'() operator */ #define vpiIffOp 68 /* iff operator */ #define vpiWildEqOp 69 /* ==? operator */ #define vpiWildNeqOp 70 /* !=? operator */ #define vpiStreamLROp 71 /* left-to-right streaming {>>} operator */ #define vpiStreamRLOp 72 /* right-to-left streaming {<<} operator */ #define vpiMatchedOp 73 /* the .matched sequence operation */ #define vpiTriggeredOp 74 /* the .triggered sequence operation */ #define vpiAssignmentPatternOp 75 /* '{} assignment pattern */ #define vpiMultiAssignmentPatternOp 76 /* '{n{}} multi assignment pattern */ #define vpiIfOp 77 /* if operator */ #define vpiIfElseOp 78 /* if/else operator */ #define vpiCompAndOp 79 /* Composite and operator */ #define vpiCompOrOp 80 /* Composite or operator */ #define vpiImpliesOp 94 /* implies operator */ #define vpiInsideOp 95 /* inside operator */ #define vpiTypeOp 81 /* type operator */ #define vpiAssignmentOp 82 /* Normal assignment */ /*********************** task/function properties ***********************/ #define vpiOtherFunc 6 /* returns other types; for property vpiFuncType */ /* vpiValid,vpiValidTrue,vpiValidFalse are deprecated in 1800-2009 */ /*********************** value for vpiValid *****************************/ #define vpiValidUnknown 2 /* Validity of variable is unknown */ /************************** STRUCTURE DEFINITIONS *************************/ /***************************** structure *****************************/ /**************************** CALLBACK REASONS ****************************/ #define cbStartOfThread 600 /* callback on thread creation */ #define cbEndOfThread 601 /* callback on thread termination */ #define cbEnterThread 602 /* callback on reentering thread */ #define cbStartOfFrame 603 /* callback on frame creation */ #define cbEndOfFrame 604 /* callback on frame exit */ #define cbSizeChange 605 /* callback on array variable size change */ #define cbCreateObj 700 /* callback on class object creation */ #define cbReclaimObj 701 /* callback on class object reclaimed by automatic memory management */ #define cbEndOfObject 702 /* callback on transient object deletion */ /************************* FUNCTION DECLARATIONS **************************/ /**************************************************************************/ /*************************** Coverage VPI *********************************/ /**************************************************************************/ /* coverage control */ #define vpiCoverageStart 750 #define vpiCoverageStOp 751 #define vpiCoverageReset 752 #define vpiCoverageCheck 753 #define vpiCoverageMerge 754 #define vpiCoverageSave 755 /* coverage type properties */ #define vpiAssertCoverage 760 #define vpiFsmStateCoverage 761 #define vpiStatementCoverage 762 #define vpiToggleCoverage 763 /* coverage status properties */ #define vpiCovered 765 #define vpiCoverMax 766 #define vpiCoveredCount 767 /* assertion-specific coverage status properties */ #define vpiAssertAttemptCovered 770 #define vpiAssertSuccessCovered 771 #define vpiAssertFailureCovered 772 #define vpiAssertVacuousSuccessCovered 773 #define vpiAssertDisableCovered 774 #define vpiAssertKillCovered 777 /* FSM-specific coverage status properties */ #define vpiFsmStates 775 #define vpiFsmStateExpression 776 /* FSM handle types */ #define vpiFsm 758 #define vpiFsmHandle 759 /***************************************************************************/ /***************************** Assertion VPI *******************************/ /***************************************************************************/ /* assertion callback types */ #define cbAssertionStart 606 #define cbAssertionSuccess 607 #define cbAssertionFailure 608 #define cbAssertionVacuousSuccess 657 #define cbAssertionDisabledEvaluation 658 #define cbAssertionStepSuccess 609 #define cbAssertionStepFailure 610 #define cbAssertionLock 661 #define cbAssertionUnlock 662 #define cbAssertionDisable 611 #define cbAssertionEnable 612 #define cbAssertionReset 613 #define cbAssertionKill 614 #define cbAssertionEnablePassAction 645 #define cbAssertionEnableFailAction 646 #define cbAssertionDisablePassAction 647 #define cbAssertionDisableFailAction 648 #define cbAssertionEnableNonvacuousAction 649 #define cbAssertionDisableVacuousAction 650 /* assertion "system" callback types */ #define cbAssertionSysInitialized 615 #define cbAssertionSysOn 616 #define cbAssertionSysOff 617 #define cbAssertionSysKill 631 #define cbAssertionSysLock 659 #define cbAssertionSysUnlock 660 #define cbAssertionSysEnd 618 #define cbAssertionSysReset 619 #define cbAssertionSysEnablePassAction 651 #define cbAssertionSysEnableFailAction 652 #define cbAssertionSysDisablePassAction 653 #define cbAssertionSysDisableFailAction 654 #define cbAssertionSysEnableNonvacuousAction 655 #define cbAssertionSysDisableVacuousAction 656 /* assertion control constants */ #define vpiAssertionLock 645 #define vpiAssertionUnlock 646 #define vpiAssertionDisable 620 #define vpiAssertionEnable 621 #define vpiAssertionReset 622 #define vpiAssertionKill 623 #define vpiAssertionEnableStep 624 #define vpiAssertionDisableStep 625 #define vpiAssertionClockSteps 626 #define vpiAssertionSysLock 647 #define vpiAssertionSysUnlock 648 #define vpiAssertionSysOn 627 #define vpiAssertionSysOff 628 #define vpiAssertionSysKill 632 #define vpiAssertionSysEnd 629 #define vpiAssertionSysReset 630 #define vpiAssertionDisablePassAction 633 #define vpiAssertionEnablePassAction 634 #define vpiAssertionDisableFailAction 635 #define vpiAssertionEnableFailAction 636 #define vpiAssertionDisableVacuousAction 637 #define vpiAssertionEnableNonvacuousAction 638 #define vpiAssertionSysEnablePassAction 639 #define vpiAssertionSysEnableFailAction 640 #define vpiAssertionSysDisablePassAction 641 #define vpiAssertionSysDisableFailAction 642 #define vpiAssertionSysEnableNonvacuousAction 643 #define vpiAssertionSysDisableVacuousAction 644 typedef struct t_vpi_assertion_step_info { PLI_INT32 matched_expression_count; vpiHandle *matched_exprs; /* array of expressions */ PLI_INT32 stateFrom, stateTo; /* identify transition */ } s_vpi_assertion_step_info, *p_vpi_assertion_step_info; typedef struct t_vpi_attempt_info { union { vpiHandle failExpr; p_vpi_assertion_step_info step; } detail; s_vpi_time attemptStartTime; /* Time attempt triggered */ } s_vpi_attempt_info, *p_vpi_attempt_info; /* typedef for vpi_register_assertion_cb callback function */ typedef PLI_INT32(vpi_assertion_callback_func)( PLI_INT32 reason, /* callback reason */ p_vpi_time cb_time, /* callback time */ vpiHandle assertion, /* handle to assertion */ p_vpi_attempt_info info, /* attempt related information */ PLI_BYTE8 *user_data /* user data entered upon registration */ ); vpiHandle vpi_register_assertion_cb( vpiHandle assertion, /* handle to assertion */ PLI_INT32 reason, /* reason for which callbacks needed */ vpi_assertion_callback_func *cb_rtn, PLI_BYTE8 *user_data /* user data to be supplied to cb */ ); #ifdef __cplusplus } #endif #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_vendor/vpi/vpi_user.h0000644000175100017510000012647515106067236020755 0ustar00runnerrunner/******************************************************************************* * vpi_user.h * * IEEE Std 1800 Programming Language Interface (PLI) * * This file contains the constant definitions, structure definitions, and * routine declarations used by the SystemVerilog Verification Procedural * Interface (VPI) access routines. * ******************************************************************************/ /******************************************************************************* * NOTE: the constant values 1 through 299 are reserved for use in this * vpi_user.h file. ******************************************************************************/ #ifndef VPI_USER_H #define VPI_USER_H #include #ifdef __cplusplus extern "C" { #endif /*----------------------------------------------------------------------------*/ /*----------------------------- Portability Help -----------------------------*/ /*----------------------------------------------------------------------------*/ #if defined (_MSC_VER) typedef unsigned __int64 uint64_t; typedef unsigned __int32 uint32_t; typedef unsigned __int8 uint8_t; typedef signed __int64 int64_t; typedef signed __int32 int32_t; typedef signed __int8 int8_t; #elif defined(__MINGW32__) || (defined(__APPLE__) && defined(__MACH__)) #include #elif defined(__linux) #include #else #include #endif /* Sized variables */ #ifndef SVPI_TYPES #define SVPI_TYPES typedef int64_t PLI_INT64; typedef uint64_t PLI_UINT64; #endif #ifndef PLI_TYPES #define PLI_TYPES typedef int PLI_INT32; typedef unsigned int PLI_UINT32; typedef short PLI_INT16; typedef unsigned short PLI_UINT16; typedef char PLI_BYTE8; typedef unsigned char PLI_UBYTE8; #endif /* Use to import a symbol */ #if defined(WIN32) || defined(WIN64) #ifndef PLI_DLLISPEC #define PLI_DLLISPEC __declspec(dllimport) #define VPI_USER_DEFINED_DLLISPEC 1 #endif #else #ifndef PLI_DLLISPEC #define PLI_DLLISPEC #endif #endif /* Use to export a symbol */ #if defined(WIN32) || defined(WIN64) #ifndef PLI_DLLESPEC #define PLI_DLLESPEC __declspec(dllexport) #define VPI_USER_DEFINED_DLLESPEC 1 #endif #else #ifndef PLI_DLLESPEC #define PLI_DLLESPEC #endif #endif /* Use to mark a function as external */ #ifndef PLI_EXTERN #define PLI_EXTERN #endif /* Use to mark a variable as external */ #ifndef PLI_VEXTERN #define PLI_VEXTERN extern #endif #ifndef PLI_PROTOTYPES #define PLI_PROTOTYPES #define PROTO_PARAMS(params) params /* object is defined imported by the application */ #define XXTERN PLI_EXTERN PLI_DLLISPEC /* object is exported by the application */ #define EETERN PLI_EXTERN PLI_DLLESPEC #endif /********************************** TYPEDEFS **********************************/ typedef PLI_UINT32 *vpiHandle; /******************************** OBJECT TYPES ********************************/ #define vpiAlways 1 /* always construct */ #define vpiAssignStmt 2 /* quasi-continuous assignment */ #define vpiAssignment 3 /* procedural assignment */ #define vpiBegin 4 /* block statement */ #define vpiCase 5 /* case statement */ #define vpiCaseItem 6 /* case statement item */ #define vpiConstant 7 /* numerical constant or literal string */ #define vpiContAssign 8 /* continuous assignment */ #define vpiDeassign 9 /* deassignment statement */ #define vpiDefParam 10 /* defparam */ #define vpiDelayControl 11 /* delay statement (e.g. #10) */ #define vpiDisable 12 /* named block disable statement */ #define vpiEventControl 13 /* wait on event, e.g. @e */ #define vpiEventStmt 14 /* event trigger, e.g. ->e */ #define vpiFor 15 /* for statement */ #define vpiForce 16 /* force statement */ #define vpiForever 17 /* forever statement */ #define vpiFork 18 /* fork-join block */ #define vpiFuncCall 19 /* HDL function call */ #define vpiFunction 20 /* HDL function */ #define vpiGate 21 /* primitive gate */ #define vpiIf 22 /* if statement */ #define vpiIfElse 23 /* if-else statement */ #define vpiInitial 24 /* initial construct */ #define vpiIntegerVar 25 /* integer variable */ #define vpiInterModPath 26 /* intermodule wire delay */ #define vpiIterator 27 /* iterator */ #define vpiIODecl 28 /* input/output declaration */ #define vpiMemory 29 /* behavioral memory */ #define vpiMemoryWord 30 /* single word of memory */ #define vpiModPath 31 /* module path for path delays */ #define vpiModule 32 /* module instance */ #define vpiNamedBegin 33 /* named block statement */ #define vpiNamedEvent 34 /* event variable */ #define vpiNamedFork 35 /* named fork-join block */ #define vpiNet 36 /* scalar or vector net */ #define vpiNetBit 37 /* bit of vector net */ #define vpiNullStmt 38 /* a semicolon. Ie. #10 ; */ #define vpiOperation 39 /* behavioral operation */ #define vpiParamAssign 40 /* module parameter assignment */ #define vpiParameter 41 /* module parameter */ #define vpiPartSelect 42 /* part-select */ #define vpiPathTerm 43 /* terminal of module path */ #define vpiPort 44 /* module port */ #define vpiPortBit 45 /* bit of vector module port */ #define vpiPrimTerm 46 /* primitive terminal */ #define vpiRealVar 47 /* real variable */ #define vpiReg 48 /* scalar or vector reg */ #define vpiRegBit 49 /* bit of vector reg */ #define vpiRelease 50 /* release statement */ #define vpiRepeat 51 /* repeat statement */ #define vpiRepeatControl 52 /* repeat control in an assign stmt */ #define vpiSchedEvent 53 /* vpi_put_value() event */ #define vpiSpecParam 54 /* specparam */ #define vpiSwitch 55 /* transistor switch */ #define vpiSysFuncCall 56 /* system function call */ #define vpiSysTaskCall 57 /* system task call */ #define vpiTableEntry 58 /* UDP state table entry */ #define vpiTask 59 /* HDL task */ #define vpiTaskCall 60 /* HDL task call */ #define vpiTchk 61 /* timing check */ #define vpiTchkTerm 62 /* terminal of timing check */ #define vpiTimeVar 63 /* time variable */ #define vpiTimeQueue 64 /* simulation event queue */ #define vpiUdp 65 /* user-defined primitive */ #define vpiUdpDefn 66 /* UDP definition */ #define vpiUserSystf 67 /* user defined system task or function */ #define vpiVarSelect 68 /* variable array selection */ #define vpiWait 69 /* wait statement */ #define vpiWhile 70 /* while statement */ /********************** object types added with 1364-2001 *********************/ #define vpiAttribute 105 /* attribute of an object */ #define vpiBitSelect 106 /* Bit-select of parameter, var select */ #define vpiCallback 107 /* callback object */ #define vpiDelayTerm 108 /* Delay term which is a load or driver */ #define vpiDelayDevice 109 /* Delay object within a net */ #define vpiFrame 110 /* reentrant task/func frame */ #define vpiGateArray 111 /* gate instance array */ #define vpiModuleArray 112 /* module instance array */ #define vpiPrimitiveArray 113 /* vpiprimitiveArray type */ #define vpiNetArray 114 /* multidimensional net */ #define vpiRange 115 /* range declaration */ #define vpiRegArray 116 /* multidimensional reg */ #define vpiSwitchArray 117 /* switch instance array */ #define vpiUdpArray 118 /* UDP instance array */ #define vpiContAssignBit 128 /* Bit of a vector continuous assignment */ #define vpiNamedEventArray 129 /* multidimensional named event */ /********************** object types added with 1364-2005 *********************/ #define vpiIndexedPartSelect 130 /* Indexed part-select object */ #define vpiGenScopeArray 133 /* array of generated scopes */ #define vpiGenScope 134 /* A generated scope */ #define vpiGenVar 135 /* Object used to instantiate gen scopes */ /*********************************** METHODS **********************************/ /**************** methods used to traverse 1 to 1 relationships ***************/ #define vpiCondition 71 /* condition expression */ #define vpiDelay 72 /* net or gate delay */ #define vpiElseStmt 73 /* else statement */ #define vpiForIncStmt 74 /* increment statement in for loop */ #define vpiForInitStmt 75 /* initialization statement in for loop */ #define vpiHighConn 76 /* higher connection to port */ #define vpiLhs 77 /* left-hand side of assignment */ #define vpiIndex 78 /* index of var select, bit-select, etc. */ #define vpiLeftRange 79 /* left range of vector or part-select */ #define vpiLowConn 80 /* lower connection to port */ #define vpiParent 81 /* parent object */ #define vpiRhs 82 /* right-hand side of assignment */ #define vpiRightRange 83 /* right range of vector or part-select */ #define vpiScope 84 /* containing scope object */ #define vpiSysTfCall 85 /* task function call */ #define vpiTchkDataTerm 86 /* timing check data term */ #define vpiTchkNotifier 87 /* timing check notifier */ #define vpiTchkRefTerm 88 /* timing check reference term */ /************* methods used to traverse 1 to many relationships ***************/ #define vpiArgument 89 /* argument to (system) task/function */ #define vpiBit 90 /* bit of vector net or port */ #define vpiDriver 91 /* driver for a net */ #define vpiInternalScope 92 /* internal scope in module */ #define vpiLoad 93 /* load on net or reg */ #define vpiModDataPathIn 94 /* data terminal of a module path */ #define vpiModPathIn 95 /* Input terminal of a module path */ #define vpiModPathOut 96 /* output terminal of a module path */ #define vpiOperand 97 /* operand of expression */ #define vpiPortInst 98 /* connected port instance */ #define vpiProcess 99 /* process in module */ #define vpiVariables 100 /* variables in module */ #define vpiUse 101 /* usage */ /******** methods which can traverse 1 to 1, or 1 to many relationships *******/ #define vpiExpr 102 /* connected expression */ #define vpiPrimitive 103 /* primitive (gate, switch, UDP) */ #define vpiStmt 104 /* statement in process or task */ /************************ methods added with 1364-2001 ************************/ #define vpiActiveTimeFormat 119 /* active $timeformat() system task */ #define vpiInTerm 120 /* To get to a delay device's drivers. */ #define vpiInstanceArray 121 /* vpiInstance arrays */ #define vpiLocalDriver 122 /* local drivers (within a module */ #define vpiLocalLoad 123 /* local loads (within a module */ #define vpiOutTerm 124 /* To get to a delay device's loads. */ #define vpiPorts 125 /* Module port */ #define vpiSimNet 126 /* simulated net after collapsing */ #define vpiTaskFunc 127 /* HDL task or function */ /************************ methods added with 1364-2005 ************************/ #define vpiBaseExpr 131 /* Indexed part-select's base expression */ #define vpiWidthExpr 132 /* Indexed part-select's width expression */ /************************ methods added with 1800-2009 ************************/ #define vpiAutomatics 136 /* Automatic variables of a frame */ /********************************* PROPERTIES *********************************/ /************************** generic object properties *************************/ #define vpiUndefined -1 /* undefined property */ #define vpiType 1 /* type of object */ #define vpiName 2 /* local name of object */ #define vpiFullName 3 /* full hierarchical name */ #define vpiSize 4 /* size of gate, net, port, etc. */ #define vpiFile 5 /* File name in which the object is used*/ #define vpiLineNo 6 /* line number where the object is used */ /***************************** module properties ******************************/ #define vpiTopModule 7 /* top-level module (boolean) */ #define vpiCellInstance 8 /* cell (boolean) */ #define vpiDefName 9 /* module definition name */ #define vpiProtected 10 /* source protected module (boolean) */ #define vpiTimeUnit 11 /* module time unit */ #define vpiTimePrecision 12 /* module time precision */ #define vpiDefNetType 13 /* default net type */ #define vpiUnconnDrive 14 /* unconnected port drive strength */ #define vpiHighZ 1 /* No default drive given */ #define vpiPull1 2 /* default pull1 drive */ #define vpiPull0 3 /* default pull0 drive */ #define vpiDefFile 15 /* File name where the module is defined*/ #define vpiDefLineNo 16 /* line number for module definition */ #define vpiDefDelayMode 47 /* Default delay mode for a module */ #define vpiDelayModeNone 1 /* no delay mode specified */ #define vpiDelayModePath 2 /* path delay mode */ #define vpiDelayModeDistrib 3 /* distributed delay mode */ #define vpiDelayModeUnit 4 /* unit delay mode */ #define vpiDelayModeZero 5 /* zero delay mode */ #define vpiDelayModeMTM 6 /* min:typ:max delay mode */ #define vpiDefDecayTime 48 /* Default decay time for a module */ /*************************** port and net properties **************************/ #define vpiScalar 17 /* scalar (boolean) */ #define vpiVector 18 /* vector (boolean) */ #define vpiExplicitName 19 /* port is explicitly named */ #define vpiDirection 20 /* direction of port: */ #define vpiInput 1 /* input */ #define vpiOutput 2 /* output */ #define vpiInout 3 /* inout */ #define vpiMixedIO 4 /* mixed input-output */ #define vpiNoDirection 5 /* no direction */ #define vpiConnByName 21 /* connected by name (boolean) */ #define vpiNetType 22 /* net subtypes: */ #define vpiWire 1 /* wire net */ #define vpiWand 2 /* wire-and net */ #define vpiWor 3 /* wire-or net */ #define vpiTri 4 /* three-state net */ #define vpiTri0 5 /* pull-down net */ #define vpiTri1 6 /* pull-up net */ #define vpiTriReg 7 /* tri state reg net */ #define vpiTriAnd 8 /* three-state wire-and net */ #define vpiTriOr 9 /* three-state wire-or net */ #define vpiSupply1 10 /* supply 1 net */ #define vpiSupply0 11 /* supply zero net */ #define vpiNone 12 /* no default net type (1364-2001) */ #define vpiUwire 13 /* unresolved wire net (1364-2005) */ #define vpiExplicitScalared 23 /* explicitly scalared (boolean) */ #define vpiExplicitVectored 24 /* explicitly vectored (boolean) */ #define vpiExpanded 25 /* expanded vector net (boolean) */ #define vpiImplicitDecl 26 /* implicitly declared net (boolean) */ #define vpiChargeStrength 27 /* charge decay strength of net */ /* Defined as part of strengths section. #define vpiLargeCharge 0x10 #define vpiMediumCharge 0x04 #define vpiSmallCharge 0x02 */ #define vpiArray 28 /* variable array (boolean) */ #define vpiPortIndex 29 /* Port index */ /************************ gate and terminal properties ************************/ #define vpiTermIndex 30 /* Index of a primitive terminal */ #define vpiStrength0 31 /* 0-strength of net or gate */ #define vpiStrength1 32 /* 1-strength of net or gate */ #define vpiPrimType 33 /* prmitive subtypes: */ #define vpiAndPrim 1 /* and gate */ #define vpiNandPrim 2 /* nand gate */ #define vpiNorPrim 3 /* nor gate */ #define vpiOrPrim 4 /* or gate */ #define vpiXorPrim 5 /* xor gate */ #define vpiXnorPrim 6 /* xnor gate */ #define vpiBufPrim 7 /* buffer */ #define vpiNotPrim 8 /* not gate */ #define vpiBufif0Prim 9 /* zero-enabled buffer */ #define vpiBufif1Prim 10 /* one-enabled buffer */ #define vpiNotif0Prim 11 /* zero-enabled not gate */ #define vpiNotif1Prim 12 /* one-enabled not gate */ #define vpiNmosPrim 13 /* nmos switch */ #define vpiPmosPrim 14 /* pmos switch */ #define vpiCmosPrim 15 /* cmos switch */ #define vpiRnmosPrim 16 /* resistive nmos switch */ #define vpiRpmosPrim 17 /* resistive pmos switch */ #define vpiRcmosPrim 18 /* resistive cmos switch */ #define vpiRtranPrim 19 /* resistive bidirectional */ #define vpiRtranif0Prim 20 /* zero-enable resistive bidirectional */ #define vpiRtranif1Prim 21 /* one-enable resistive bidirectional */ #define vpiTranPrim 22 /* bidirectional */ #define vpiTranif0Prim 23 /* zero-enabled bidirectional */ #define vpiTranif1Prim 24 /* one-enabled bidirectional */ #define vpiPullupPrim 25 /* pullup */ #define vpiPulldownPrim 26 /* pulldown */ #define vpiSeqPrim 27 /* sequential UDP */ #define vpiCombPrim 28 /* combinational UDP */ /**************** path, path terminal, timing check properties ****************/ #define vpiPolarity 34 /* polarity of module path... */ #define vpiDataPolarity 35 /* ...or data path: */ #define vpiPositive 1 /* positive */ #define vpiNegative 2 /* negative */ #define vpiUnknown 3 /* unknown (unspecified) */ #define vpiEdge 36 /* edge type of module path: */ #define vpiNoEdge 0x00 /* no edge */ #define vpiEdge01 0x01 /* 0 -> 1 */ #define vpiEdge10 0x02 /* 1 -> 0 */ #define vpiEdge0x 0x04 /* 0 -> x */ #define vpiEdgex1 0x08 /* x -> 1 */ #define vpiEdge1x 0x10 /* 1 -> x */ #define vpiEdgex0 0x20 /* x -> 0 */ #define vpiPosedge (vpiEdgex1 | vpiEdge01 | vpiEdge0x) #define vpiNegedge (vpiEdgex0 | vpiEdge10 | vpiEdge1x) #define vpiAnyEdge (vpiPosedge | vpiNegedge) #define vpiPathType 37 /* path delay connection subtypes: */ #define vpiPathFull 1 /* ( a *> b ) */ #define vpiPathParallel 2 /* ( a => b ) */ #define vpiTchkType 38 /* timing check subtypes: */ #define vpiSetup 1 /* $setup */ #define vpiHold 2 /* $hold */ #define vpiPeriod 3 /* $period */ #define vpiWidth 4 /* $width */ #define vpiSkew 5 /* $skew */ #define vpiRecovery 6 /* $recovery */ #define vpiNoChange 7 /* $nochange */ #define vpiSetupHold 8 /* $setuphold */ #define vpiFullskew 9 /* $fullskew -- added for 1364-2001 */ #define vpiRecrem 10 /* $recrem -- added for 1364-2001 */ #define vpiRemoval 11 /* $removal -- added for 1364-2001 */ #define vpiTimeskew 12 /* $timeskew -- added for 1364-2001 */ /**************************** expression properties ***************************/ #define vpiOpType 39 /* operation subtypes: */ #define vpiMinusOp 1 /* unary minus */ #define vpiPlusOp 2 /* unary plus */ #define vpiNotOp 3 /* unary not */ #define vpiBitNegOp 4 /* bitwise negation */ #define vpiUnaryAndOp 5 /* bitwise reduction and */ #define vpiUnaryNandOp 6 /* bitwise reduction nand */ #define vpiUnaryOrOp 7 /* bitwise reduction or */ #define vpiUnaryNorOp 8 /* bitwise reduction nor */ #define vpiUnaryXorOp 9 /* bitwise reduction xor */ #define vpiUnaryXNorOp 10 /* bitwise reduction xnor */ #define vpiSubOp 11 /* binary subtraction */ #define vpiDivOp 12 /* binary division */ #define vpiModOp 13 /* binary modulus */ #define vpiEqOp 14 /* binary equality */ #define vpiNeqOp 15 /* binary inequality */ #define vpiCaseEqOp 16 /* case (x and z) equality */ #define vpiCaseNeqOp 17 /* case inequality */ #define vpiGtOp 18 /* binary greater than */ #define vpiGeOp 19 /* binary greater than or equal */ #define vpiLtOp 20 /* binary less than */ #define vpiLeOp 21 /* binary less than or equal */ #define vpiLShiftOp 22 /* binary left shift */ #define vpiRShiftOp 23 /* binary right shift */ #define vpiAddOp 24 /* binary addition */ #define vpiMultOp 25 /* binary multiplication */ #define vpiLogAndOp 26 /* binary logical and */ #define vpiLogOrOp 27 /* binary logical or */ #define vpiBitAndOp 28 /* binary bitwise and */ #define vpiBitOrOp 29 /* binary bitwise or */ #define vpiBitXorOp 30 /* binary bitwise xor */ #define vpiBitXNorOp 31 /* binary bitwise xnor */ #define vpiBitXnorOp vpiBitXNorOp /* added with 1364-2001 */ #define vpiConditionOp 32 /* ternary conditional */ #define vpiConcatOp 33 /* n-ary concatenation */ #define vpiMultiConcatOp 34 /* repeated concatenation */ #define vpiEventOrOp 35 /* event or */ #define vpiNullOp 36 /* null operation */ #define vpiListOp 37 /* list of expressions */ #define vpiMinTypMaxOp 38 /* min:typ:max: delay expression */ #define vpiPosedgeOp 39 /* posedge */ #define vpiNegedgeOp 40 /* negedge */ #define vpiArithLShiftOp 41 /* arithmetic left shift (1364-2001) */ #define vpiArithRShiftOp 42 /* arithmetic right shift (1364-2001) */ #define vpiPowerOp 43 /* arithmetic power op (1364-2001) */ #define vpiConstType 40 /* constant subtypes: */ #define vpiDecConst 1 /* decimal integer */ #define vpiRealConst 2 /* real */ #define vpiBinaryConst 3 /* binary integer */ #define vpiOctConst 4 /* octal integer */ #define vpiHexConst 5 /* hexadecimal integer */ #define vpiStringConst 6 /* string literal */ #define vpiIntConst 7 /* HDL integer constant (1364-2001) */ #define vpiTimeConst 8 /* time constant */ #define vpiBlocking 41 /* blocking assignment (boolean) */ #define vpiCaseType 42 /* case statement subtypes: */ #define vpiCaseExact 1 /* exact match */ #define vpiCaseX 2 /* ignore X's */ #define vpiCaseZ 3 /* ignore Z's */ #define vpiNetDeclAssign 43 /* assign part of decl (boolean) */ /************************** task/function properties **************************/ #define vpiFuncType 44 /* HDL function & system function type */ #define vpiIntFunc 1 /* returns integer */ #define vpiRealFunc 2 /* returns real */ #define vpiTimeFunc 3 /* returns time */ #define vpiSizedFunc 4 /* returns an arbitrary size */ #define vpiSizedSignedFunc 5 /* returns sized signed value */ /** alias 1364-1995 system function subtypes to 1364-2001 function subtypes ***/ #define vpiSysFuncType vpiFuncType #define vpiSysFuncInt vpiIntFunc #define vpiSysFuncReal vpiRealFunc #define vpiSysFuncTime vpiTimeFunc #define vpiSysFuncSized vpiSizedFunc #define vpiUserDefn 45 /*user defined system task/func(boolean)*/ #define vpiScheduled 46 /* object still scheduled (boolean) */ /*********************** properties added with 1364-2001 **********************/ #define vpiActive 49 /* reentrant task/func frame is active */ #define vpiAutomatic 50 /* task/func obj is automatic */ #define vpiCell 51 /* configuration cell */ #define vpiConfig 52 /* configuration config file */ #define vpiConstantSelect 53 /* (boolean) bit-select or part-select indices are constant expressions */ #define vpiDecompile 54 /* decompile the object */ #define vpiDefAttribute 55 /* Attribute defined for the obj */ #define vpiDelayType 56 /* delay subtype */ #define vpiModPathDelay 1 /* module path delay */ #define vpiInterModPathDelay 2 /* intermodule path delay */ #define vpiMIPDelay 3 /* module input port delay */ #define vpiIteratorType 57 /* object type of an iterator */ #define vpiLibrary 58 /* configuration library */ #define vpiMultiArray 59 /* Object is a multidimensional array */ #define vpiOffset 60 /* offset from LSB */ #define vpiResolvedNetType 61 /* net subtype after resolution, returns same subtypes as vpiNetType */ #define vpiSaveRestartID 62 /* unique ID for save/restart data */ #define vpiSaveRestartLocation 63 /* name of save/restart data file */ #define vpiValid 64 /* reentrant task/func frame or automatic variable is valid */ #define vpiValidFalse 0 #define vpiValidTrue 1 #define vpiSigned 65 /* TRUE for vpiIODecl and any object in the expression class if the object has the signed attribute */ #define vpiLocalParam 70 /* TRUE when a param is declared as a localparam */ #define vpiModPathHasIfNone 71 /* Mod path has an ifnone statement */ /*********************** properties added with 1364-2005 **********************/ #define vpiIndexedPartSelectType 72 /* Indexed part-select type */ #define vpiPosIndexed 1 /* +: */ #define vpiNegIndexed 2 /* -: */ #define vpiIsMemory 73 /* TRUE for a one-dimensional reg array */ #define vpiIsProtected 74 /* TRUE for protected design information */ /*************** vpi_control() constants (added with 1364-2001) ***************/ #define vpiStop 66 /* execute simulator's $stop */ #define vpiFinish 67 /* execute simulator's $finish */ #define vpiReset 68 /* execute simulator's $reset */ #define vpiSetInteractiveScope 69 /* set simulator's interactive scope */ /**************************** I/O related defines *****************************/ #define VPI_MCD_STDOUT 0x00000001 /*************************** STRUCTURE DEFINITIONS ****************************/ /******************************* time structure *******************************/ typedef struct t_vpi_time { PLI_INT32 type; /* [vpiScaledRealTime, vpiSimTime, vpiSuppressTime] */ PLI_UINT32 high, low; /* for vpiSimTime */ double real; /* for vpiScaledRealTime */ } s_vpi_time, *p_vpi_time; /* time types */ #define vpiScaledRealTime 1 #define vpiSimTime 2 #define vpiSuppressTime 3 /****************************** delay structures ******************************/ typedef struct t_vpi_delay { struct t_vpi_time *da; /* pointer to user allocated array of delay values */ PLI_INT32 no_of_delays; /* number of delays */ PLI_INT32 time_type; /* [vpiScaledRealTime, vpiSimTime, vpiSuppressTime] */ PLI_INT32 mtm_flag; /* true for mtm values */ PLI_INT32 append_flag; /* true for append */ PLI_INT32 pulsere_flag; /* true for pulsere values */ } s_vpi_delay, *p_vpi_delay; /***************************** value structures *******************************/ /* vector value */ #ifndef VPI_VECVAL /* added in 1364-2005 */ #define VPI_VECVAL typedef struct t_vpi_vecval { /* following fields are repeated enough times to contain vector */ PLI_INT32 aval, bval; /* bit encoding: ab: 00=0, 10=1, 11=X, 01=Z */ } s_vpi_vecval, *p_vpi_vecval; #endif /* strength (scalar) value */ typedef struct t_vpi_strengthval { PLI_INT32 logic; /* vpi[0,1,X,Z] */ PLI_INT32 s0, s1; /* refer to strength coding below */ } s_vpi_strengthval, *p_vpi_strengthval; /* strength values */ #define vpiSupplyDrive 0x80 #define vpiStrongDrive 0x40 #define vpiPullDrive 0x20 #define vpiWeakDrive 0x08 #define vpiLargeCharge 0x10 #define vpiMediumCharge 0x04 #define vpiSmallCharge 0x02 #define vpiHiZ 0x01 /* generic value */ typedef struct t_vpi_value { PLI_INT32 format; /* vpi[[Bin,Oct,Dec,Hex]Str,Scalar,Int,Real,String, Vector,Strength,Suppress,Time,ObjType]Val */ union { PLI_BYTE8 *str; /* string value */ PLI_INT32 scalar; /* vpi[0,1,X,Z] */ PLI_INT32 integer; /* integer value */ double real; /* real value */ struct t_vpi_time *time; /* time value */ struct t_vpi_vecval *vector; /* vector value */ struct t_vpi_strengthval *strength; /* strength value */ PLI_BYTE8 *misc; /* ...other */ } value; } s_vpi_value, *p_vpi_value; typedef struct t_vpi_arrayvalue { PLI_UINT32 format; PLI_UINT32 flags; union { PLI_INT32 *integers; PLI_INT16 *shortints; PLI_INT64 *longints; PLI_BYTE8 *rawvals; struct t_vpi_vecval *vectors; struct t_vpi_time *times; double *reals; float *shortreals; } value; } s_vpi_arrayvalue, *p_vpi_arrayvalue; /* value formats */ #define vpiBinStrVal 1 #define vpiOctStrVal 2 #define vpiDecStrVal 3 #define vpiHexStrVal 4 #define vpiScalarVal 5 #define vpiIntVal 6 #define vpiRealVal 7 #define vpiStringVal 8 #define vpiVectorVal 9 #define vpiStrengthVal 10 #define vpiTimeVal 11 #define vpiObjTypeVal 12 #define vpiSuppressVal 13 #define vpiShortIntVal 14 #define vpiLongIntVal 15 #define vpiShortRealVal 16 #define vpiRawTwoStateVal 17 #define vpiRawFourStateVal 18 /* delay modes */ #define vpiNoDelay 1 #define vpiInertialDelay 2 #define vpiTransportDelay 3 #define vpiPureTransportDelay 4 /* force and release flags */ #define vpiForceFlag 5 #define vpiReleaseFlag 6 /* scheduled event cancel flag */ #define vpiCancelEvent 7 /* bit mask for the flags argument to vpi_put_value() */ #define vpiReturnEvent 0x1000 /* bit flags for vpi_get_value_array flags field */ #define vpiUserAllocFlag 0x2000 /* bit flags for vpi_put_value_array flags field */ #define vpiOneValue 0x4000 #define vpiPropagateOff 0x8000 /* scalar values */ #define vpi0 0 #define vpi1 1 #define vpiZ 2 #define vpiX 3 #define vpiH 4 #define vpiL 5 #define vpiDontCare 6 /* #define vpiNoChange 7 Defined under vpiTchkType, but can be used here. */ /*********************** system task/function structure ***********************/ typedef struct t_vpi_systf_data { PLI_INT32 type; /* vpiSysTask, vpiSysFunc */ PLI_INT32 sysfunctype; /* vpiSysTask, vpi[Int,Real,Time,Sized, SizedSigned]Func */ const PLI_BYTE8 *tfname; /* first character must be '$' */ PLI_INT32 (*calltf)(PLI_BYTE8 *); PLI_INT32 (*compiletf)(PLI_BYTE8 *); PLI_INT32 (*sizetf)(PLI_BYTE8 *); /* for sized function callbacks only */ PLI_BYTE8 *user_data; } s_vpi_systf_data, *p_vpi_systf_data; #define vpiSysTask 1 #define vpiSysFunc 2 /* the subtypes are defined under the vpiFuncType property */ /****************** Verilog execution information structure *******************/ typedef struct t_vpi_vlog_info { PLI_INT32 argc; PLI_BYTE8 **argv; PLI_BYTE8 *product; PLI_BYTE8 *version; } s_vpi_vlog_info, *p_vpi_vlog_info; /*********************** PLI error information structure **********************/ typedef struct t_vpi_error_info { PLI_INT32 state; /* vpi[Compile,PLI,Run] */ PLI_INT32 level; /* vpi[Notice,Warning,Error,System,Internal] */ PLI_BYTE8 *message; PLI_BYTE8 *product; PLI_BYTE8 *code; PLI_BYTE8 *file; PLI_INT32 line; } s_vpi_error_info, *p_vpi_error_info; /* state when error occurred */ #define vpiCompile 1 #define vpiPLI 2 #define vpiRun 3 /* error severity levels */ #define vpiNotice 1 #define vpiWarning 2 #define vpiError 3 #define vpiSystem 4 #define vpiInternal 5 /**************************** callback structures *****************************/ #define vpiTimePrecision 12 /* module time precision */ /* normal callback structure */ typedef struct t_cb_data { PLI_INT32 reason; /* callback reason */ PLI_INT32 (*cb_rtn)(struct t_cb_data *); /* call routine */ vpiHandle obj; /* trigger object */ p_vpi_time time; /* callback time */ p_vpi_value value; /* trigger object value */ PLI_INT32 index; /* index of the memory word or var select that changed */ PLI_BYTE8 *user_data; } s_cb_data, *p_cb_data; /****************************** CALLBACK REASONS ******************************/ /***************************** Simulation related *****************************/ #define cbValueChange 1 #define cbStmt 2 #define cbForce 3 #define cbRelease 4 /******************************** Time related ********************************/ #define cbAtStartOfSimTime 5 #define cbReadWriteSynch 6 #define cbReadOnlySynch 7 #define cbNextSimTime 8 #define cbAfterDelay 9 /******************************* Action related *******************************/ #define cbEndOfCompile 10 #define cbStartOfSimulation 11 #define cbEndOfSimulation 12 #define cbError 13 #define cbTchkViolation 14 #define cbStartOfSave 15 #define cbEndOfSave 16 #define cbStartOfRestart 17 #define cbEndOfRestart 18 #define cbStartOfReset 19 #define cbEndOfReset 20 #define cbEnterInteractive 21 #define cbExitInteractive 22 #define cbInteractiveScopeChange 23 #define cbUnresolvedSystf 24 /**************************** Added with 1364-2001 ****************************/ #define cbAssign 25 #define cbDeassign 26 #define cbDisable 27 #define cbPLIError 28 #define cbSignal 29 /**************************** Added with 1364-2005 ****************************/ #define cbNBASynch 30 #define cbAtEndOfSimTime 31 /************************* FUNCTION DECLARATIONS **************************/ /* callback related */ XXTERN vpiHandle vpi_register_cb PROTO_PARAMS((p_cb_data cb_data_p)); XXTERN PLI_INT32 vpi_remove_cb PROTO_PARAMS((vpiHandle cb_obj)); XXTERN void vpi_get_cb_info PROTO_PARAMS((vpiHandle object, p_cb_data cb_data_p)); XXTERN vpiHandle vpi_register_systf PROTO_PARAMS((p_vpi_systf_data systf_data_p)); XXTERN void vpi_get_systf_info PROTO_PARAMS((vpiHandle object, p_vpi_systf_data systf_data_p)); /* for obtaining handles */ XXTERN vpiHandle vpi_handle_by_name PROTO_PARAMS((PLI_BYTE8 *name, vpiHandle scope)); XXTERN vpiHandle vpi_handle_by_index PROTO_PARAMS((vpiHandle object, PLI_INT32 indx)); /* for traversing relationships */ XXTERN vpiHandle vpi_handle PROTO_PARAMS((PLI_INT32 type, vpiHandle refHandle)); XXTERN vpiHandle vpi_handle_multi PROTO_PARAMS((PLI_INT32 type, vpiHandle refHandle1, vpiHandle refHandle2, ... )); XXTERN vpiHandle vpi_iterate PROTO_PARAMS((PLI_INT32 type, vpiHandle refHandle)); XXTERN vpiHandle vpi_scan PROTO_PARAMS((vpiHandle iterator)); /* for processing properties */ XXTERN PLI_INT32 vpi_get PROTO_PARAMS((PLI_INT32 property, vpiHandle object)); XXTERN PLI_INT64 vpi_get64 PROTO_PARAMS((PLI_INT32 property, vpiHandle object)); XXTERN PLI_BYTE8 *vpi_get_str PROTO_PARAMS((PLI_INT32 property, vpiHandle object)); /* delay processing */ XXTERN void vpi_get_delays PROTO_PARAMS((vpiHandle object, p_vpi_delay delay_p)); XXTERN void vpi_put_delays PROTO_PARAMS((vpiHandle object, p_vpi_delay delay_p)); /* value processing */ XXTERN void vpi_get_value PROTO_PARAMS((vpiHandle expr, p_vpi_value value_p)); XXTERN vpiHandle vpi_put_value PROTO_PARAMS((vpiHandle object, p_vpi_value value_p, p_vpi_time time_p, PLI_INT32 flags)); XXTERN void vpi_get_value_array PROTO_PARAMS((vpiHandle expr, p_vpi_arrayvalue arrayvalue_p, PLI_INT32 *index_p, PLI_UINT32 num)); XXTERN void vpi_put_value_array PROTO_PARAMS((vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_INT32 *index_p, PLI_UINT32 num)); /* time processing */ XXTERN void vpi_get_time PROTO_PARAMS((vpiHandle object, p_vpi_time time_p)); /* I/O routines */ XXTERN PLI_UINT32 vpi_mcd_open PROTO_PARAMS((const PLI_BYTE8 *fileName)); XXTERN PLI_UINT32 vpi_mcd_close PROTO_PARAMS((PLI_UINT32 mcd)); XXTERN PLI_BYTE8 *vpi_mcd_name PROTO_PARAMS((PLI_UINT32 cd)); XXTERN PLI_INT32 vpi_mcd_printf PROTO_PARAMS((PLI_UINT32 mcd, const PLI_BYTE8 *format, ...)); XXTERN PLI_INT32 vpi_printf PROTO_PARAMS((const PLI_BYTE8 *format, ...)); /* utility routines */ XXTERN PLI_INT32 vpi_compare_objects PROTO_PARAMS((vpiHandle object1, vpiHandle object2)); XXTERN PLI_INT32 vpi_chk_error PROTO_PARAMS((p_vpi_error_info error_info_p)); XXTERN PLI_INT32 vpi_free_object PROTO_PARAMS((vpiHandle object)); XXTERN PLI_INT32 vpi_release_handle PROTO_PARAMS((vpiHandle object)); XXTERN PLI_INT32 vpi_get_vlog_info PROTO_PARAMS((p_vpi_vlog_info vlog_info_p)); /* routines added with 1364-2001 */ XXTERN PLI_INT32 vpi_get_data PROTO_PARAMS((PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes)); XXTERN PLI_INT32 vpi_put_data PROTO_PARAMS((PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes)); XXTERN void *vpi_get_userdata PROTO_PARAMS((vpiHandle obj)); XXTERN PLI_INT32 vpi_put_userdata PROTO_PARAMS((vpiHandle obj, void *userdata)); XXTERN PLI_INT32 vpi_vprintf PROTO_PARAMS((const PLI_BYTE8 *format, va_list ap)); XXTERN PLI_INT32 vpi_mcd_vprintf PROTO_PARAMS((PLI_UINT32 mcd, const PLI_BYTE8 *format, va_list ap)); XXTERN PLI_INT32 vpi_flush PROTO_PARAMS((void)); XXTERN PLI_INT32 vpi_mcd_flush PROTO_PARAMS((PLI_UINT32 mcd)); XXTERN PLI_INT32 vpi_control PROTO_PARAMS((PLI_INT32 operation, ...)); XXTERN vpiHandle vpi_handle_by_multi_index PROTO_PARAMS((vpiHandle obj, PLI_INT32 num_index, PLI_INT32 *index_array)); /****************************** GLOBAL VARIABLES ******************************/ PLI_VEXTERN PLI_DLLESPEC void (*vlog_startup_routines[])(void); /* array of function pointers, last pointer should be null */ #undef PLI_EXTERN #undef PLI_VEXTERN #ifdef VPI_USER_DEFINED_DLLISPEC #undef VPI_USER_DEFINED_DLLISPEC #undef PLI_DLLISPEC #endif #ifdef VPI_USER_DEFINED_DLLESPEC #undef VPI_USER_DEFINED_DLLESPEC #undef PLI_DLLESPEC #endif #ifdef PLI_PROTOTYPES #undef PLI_PROTOTYPES #undef PROTO_PARAMS #undef XXTERN #undef EETERN #endif #ifdef __cplusplus } #endif #endif /* VPI_USER_H */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763209677.0 cocotb-2.0.1/src/cocotb/_version.py0000644000175100017510000000013315106070715016666 0ustar00runnerrunner# Package version # Generated by setup.py -- do not modify directly __version__ = "2.0.1" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/_xunit_reporter.py0000644000175100017510000000700615106067236020304 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import re import sys import xml.etree.ElementTree as ET from typing import Union from xml.etree.ElementTree import Element, SubElement # Shamelessly ripped from pytest source code. # https://github.com/pytest-dev/pytest/blob/d036b12bb6fa09f9a8a3b690cc7336113c93fa44/src/_pytest/junitxml.py#L37C1-L61C50 def bin_xml_escape(arg: object) -> str: r"""Visually escape invalid XML characters. For example, transforms 'hello\aworld\b' into 'hello#x07world#x08' Note that the #xABs are *not* XML escapes - missing the ampersand «. The idea is to escape visually for the user rather than for XML itself. """ def repl(matchobj: "re.Match[str]") -> str: i = ord(matchobj.group()) if i <= 0xFF: return f"#x{i:02X}" else: return f"#x{i:04X}" # The spec range of valid chars is: # Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] # For an unknown(?) reason, we disallow #x7F (DEL) as well. illegal_xml_re = ( "[^\u0009\u000a\u000d\u0020-\u007e\u0080-\ud7ff\ue000-\ufffd\u10000-\u10ffff]" ) return re.sub(illegal_xml_re, repl, str(arg)) if sys.version_info < (3, 9): def indent(elem: Element, level: int = 0) -> None: i = "\n" + level * " " if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + " " if not elem.tail or not elem.tail.strip(): elem.tail = i for sub_elem in elem: indent(sub_elem, level + 1) if not sub_elem.tail or not sub_elem.tail.strip(): sub_elem.tail = i elif level and (not elem.tail or not elem.tail.strip()): elem.tail = i else: from xml.etree.ElementTree import indent class XUnitReporter: last_testsuite: Element last_testcase: Element def __init__(self, filename: str = "results.xml") -> None: self.results = Element("testsuites", name="results") self.filename = filename def add_testsuite(self, **kwargs: str) -> Element: self.last_testsuite = SubElement(self.results, "testsuite", kwargs) return self.last_testsuite def add_testcase( self, testsuite: Union[Element, None] = None, **kwargs: str ) -> Element: if testsuite is None: testsuite = self.last_testsuite self.last_testcase = SubElement(testsuite, "testcase", kwargs) return self.last_testcase def add_property( self, testsuite: Union[Element, None] = None, **kwargs: str ) -> Element: if testsuite is None: testsuite = self.last_testsuite self.last_property = SubElement(testsuite, "property", kwargs) return self.last_property def add_failure(self, testcase: Union[Element, None] = None, **kwargs: str) -> None: if testcase is None: testcase = self.last_testcase SubElement(testcase, "failure", kwargs) def add_skipped(self, testcase: Union[Element, None] = None, **kwargs: str) -> None: if testcase is None: testcase = self.last_testcase SubElement(testcase, "skipped", kwargs) def write(self) -> None: indent(self.results) ET.ElementTree(self.results).write(self.filename, encoding="UTF-8") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/clock.py0000644000175100017510000003313415106067236016150 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """A clock class.""" import logging import warnings from decimal import Decimal from fractions import Fraction from logging import Logger from typing import ClassVar, Type, Union import cocotb from cocotb._py_compat import ( Literal, TypeAlias, cached_property, ) from cocotb._typing import TimeUnit from cocotb.handle import ( Deposit, Force, Immediate, LogicObject, _GPISetAction, _trust_inertial, ) from cocotb.simulator import clock_create from cocotb.task import Task from cocotb.triggers import ( Event, FallingEdge, NullTrigger, RisingEdge, Timer, ValueChange, ) from cocotb.utils import get_sim_steps, get_time_from_sim_steps __all__ = ("Clock",) Impl: TypeAlias = Literal["gpi", "py"] _valid_impls = ("gpi", "py") class Clock: r"""Simple 50:50 duty cycle clock driver. .. code-block:: python c = Clock(dut.clk, 10, "ns") c.start() Args: signal: The clock pin/signal to be driven. period: The clock period. Must be a multiple of the time precision of the simulator. unit: One of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``. When *unit* is ``'step'``, the timestep is determined by the simulator (see :make:var:`COCOTB_HDL_TIMEPRECISION`). .. versionchanged:: 2.0 Renamed from ``units``. impl: One of ``'auto'``, ``'gpi'``, ``'py'``. Specify whether the clock is implemented with a :class:`~cocotb.simulator.GpiClock` (faster), or with a Python coroutine. When ``'auto'`` is used (default), the fastest implementation that supports your environment and use case is picked. .. versionadded:: 2.0 set_action: One of :class:`.Immediate`, :class:`.Deposit`, or :class:`.Force`. Specify the action to use when setting the clock signal value. Defaults to the value of :attr:`default_set_action`. .. versionadded:: 2.0 period_high: The period of time when the clock is driven to ``1``. Defaults to half of the *period*. Must be a multiple of the time precision of the simulator and less than *period*. .. versionadded:: 2.0 When *impl* is ``'auto'``, if :envvar:`COCOTB_TRUST_INERTIAL_WRITES` is defined, the :class:`~cocotb.simulator.GpiClock` implementation will be used. Otherwise, the Python coroutine implementation will be used. See the environment variable's documentation for more information on the consequences of using the simulator's inertial write mechanism. If you need more features like a phase shift and an asymmetric duty cycle, it is simple to create your own clock generator (that you then :func:`cocotb.start_soon`): .. code-block:: python async def custom_clock(): # pre-construct triggers for performance high_time = Timer(high_delay, unit="ns") low_time = Timer(low_delay, unit="ns") await Timer(initial_delay, unit="ns") while True: dut.clk.value = 1 await high_time dut.clk.value = 0 await low_time If you also want to change the timing during simulation, use this slightly more inefficient example instead where the :class:`Timer`\ s inside the while loop are created with current delay values: .. code-block:: python async def custom_clock(): while True: dut.clk.value = 1 await Timer(high_delay, unit="ns") dut.clk.value = 0 await Timer(low_delay, unit="ns") high_delay = low_delay = 100 cocotb.start_soon(custom_clock()) await Timer(1000, unit="ns") high_delay = low_delay = 10 # change the clock speed await Timer(1000, unit="ns") .. versionadded:: 1.5 Support ``'step'`` as the *unit* argument to mean "simulator time step". .. versionremoved:: 2.0 Passing ``None`` as the *unit* argument was removed, use ``'step'`` instead. .. versionchanged:: 2.0 :meth:`start` now automatically calls :func:`cocotb.start_soon` and stores the Task on the Clock object, so that it may later be :meth:`stop`\ ped. """ _impl: Impl default_set_action: ClassVar[Union[Type[Immediate], Type[Deposit], Type[Force]]] = ( Deposit ) """The default action used to set the clock signal value. One of :class:`.Immediate`, :class:`.Deposit`, or :class:`.Force`. .. versionadded:: 2.0 """ def __init__( self, signal: LogicObject, period: Union[float, Fraction, Decimal], unit: TimeUnit = "step", impl: Union[Impl, None] = None, *, units: None = None, set_action: Union[Type[Immediate], Type[Deposit], Type[Force], None] = None, period_high: Union[float, Fraction, Decimal, None] = None, ) -> None: self._signal = signal if units is not None: warnings.warn( "The 'units' argument has been renamed to 'unit'.", DeprecationWarning, stacklevel=2, ) unit = units self._unit: TimeUnit = unit self._period = period try: self._period_steps = get_sim_steps(self._period, self._unit) except ValueError as e: raise ValueError(f"Bad `period`: {e}") from None if set_action is None: set_action = type(self).default_set_action if set_action not in (Immediate, Deposit, Force): raise TypeError( "Invalid value for `set_action`. `set_action` must be one of Immediate, Deposit, or Force" ) self._set_action = set_action if impl is None: self._impl = "gpi" if _trust_inertial else "py" elif impl in _valid_impls: self._impl = impl else: valid_impls_str = ", ".join([repr(i) for i in _valid_impls]) raise ValueError( f"Invalid clock impl {impl!r}, must be one of: {valid_impls_str}" ) self._period_high: Union[float, Fraction, Decimal] if period_high is not None: if period_high >= self._period: raise ValueError("`period_high` must be strictly less than `period`.") self._period_high = period_high try: self._period_high_steps = get_sim_steps(self._period_high, self._unit) except ValueError as e: raise ValueError(f"Bad `period_high`: {e}") from None else: if self._period_steps % 2 != 0: raise ValueError( "Bad `period`: Must be divisible by 2 if `period_high` is not given." ) self._period_high = period / 2 self._period_high_steps = self._period_steps // 2 self._task: Union[Task[None], None] = None @property def signal(self) -> LogicObject: """The clock signal being driven.""" return self._signal @property def period(self) -> Union[float, Fraction, Decimal]: """The clock period. The unit is :attr:`unit`. """ return self._period @property def period_high(self) -> Union[float, Fraction, Decimal]: """The period of time when the clock is driven to ``1``. The unit is :attr:`unit`. .. versionadded:: 2.0 """ return self._period_high @property def unit(self) -> TimeUnit: """The unit of the clock period. .. versionadded:: 2.0 """ return self._unit @property def impl(self) -> Impl: """The concrete implementation of the clock used. ``"gpi"`` if the clock is implemented in C in the GPI layer, or ``"py"`` if the clock is implemented in Python using cocotb Tasks. .. versionadded:: 2.0 """ return self._impl @property def set_action(self) -> Union[Type[Immediate], Type[Deposit], Type[Force]]: """The value setting action used to set the clock signal value. .. versionadded:: 2.0 """ return self._set_action def start(self, start_high: bool = True) -> Task[None]: r"""Start driving the clock signal. You can later stop the clock by calling :meth:`stop`. Args: start_high: Whether to start the clock with a ``1`` for the first half of the period. Default is ``True``. .. versionadded:: 1.3 Raises: RuntimeError: If attempting to start a clock that has already been started. Returns: Object which can be passed to :func:`cocotb.start_soon` or ignored. .. versionremoved:: 2.0 Removed ``cycles`` arguments for toggling for a finite amount of cycles. Use :meth:`stop` to stop a clock from running. .. versionchanged:: 2.0 Previously, this method returned a :term:`coroutine` which needed to be passed to :func:`cocotb.start_soon`. Now the Clock object keeps track of its own driver Task, so this is no longer necessary. Simply call ``clock.start()`` to start running the clock. """ if self._task is not None: raise RuntimeError("Starting clock that has already been started.") if self._impl == "gpi": clkobj = clock_create(self._signal._handle) set_action = { Deposit: _GPISetAction.DEPOSIT, Immediate: _GPISetAction.NO_DELAY, Force: _GPISetAction.FORCE, }[self._set_action] clkobj.start( self._period_steps, self._period_high_steps, start_high, set_action.value, ) async def drive() -> None: # The clock is meant to toggle forever, so awaiting this should # never return by awaiting on Event that's never set. e = Event() try: await e.wait() finally: clkobj.stop() else: async def drive() -> None: timer_high = Timer(self._period_high_steps) timer_low = Timer(self._period_steps - self._period_high_steps) if start_high: self._signal.set(self._set_action(1)) await timer_high while True: self._signal.set(self._set_action(0)) await timer_low self._signal.set(self._set_action(1)) await timer_high self._task = cocotb.start_soon(drive()) return self._task def stop(self) -> None: """Stop driving the clock signal. You can later start the clock again by calling :meth:`start`. Raises: RuntimeError: If attempting to stop a clock that has never been started. .. versionadded:: 2.0 """ if self._task is None: raise RuntimeError("Stopping a clock that was never started.") self._task.cancel() self._task = None async def cycles( self, num_cycles: int, edge_type: Union[ Type[RisingEdge], Type[FallingEdge], Type[ValueChange] ] = RisingEdge, ) -> None: """Wait for a number of clock cycles. Args: num_cycles: The number of clock cycles to wait. edge_type: The edge of the clock to wait on. Must be one of :class:`.RisingEdge`, :class:`.FallingEdge`, or :class:`.ValueChange`. Raises: ValueError: if *num_cycles* is negative. """ if num_cycles == 0: await NullTrigger() return elif num_cycles < 0: raise ValueError("`num_cycles` cannot be negative") # Synchronize first. await edge_type(self._signal) num_cycles -= 1 # Use Timer as an optimization if we are waiting long enough. if num_cycles >= 2: # NOTE: num_cycles must end 1 higher than expected because all edge_types occur # strictly after beginning of time steps, so the last edge_type will jump within # the same time step. if edge_type is ValueChange: # Make cycles_skipped the nearest even number so division by 2 doesn't cause issues. cycles_skipped = (num_cycles // 2) * 2 await Timer(self._period_steps * cycles_skipped / 2, "step") num_cycles = num_cycles - cycles_skipped + 1 else: await Timer(self._period_steps * num_cycles, "step") num_cycles = 1 # Run N edge_type trigger. for _ in range(num_cycles): await edge_type(self._signal) def __repr__(self) -> str: return self._repr @cached_property def _repr(self) -> str: freq_mhz = 1 / get_time_from_sim_steps( get_sim_steps(self._period, self._unit), "us" ) return f"<{type(self).__qualname__}, {self._signal._path} @ {freq_mhz} MHz>" @cached_property def _log(self) -> Logger: return logging.getLogger( f"cocotb.{type(self).__qualname__}.{self._signal._name}" ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/debug.py0000644000175100017510000000143015106067236016135 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import os debug: bool = bool(os.getenv("COCOTB_SCHEDULER_DEBUG")) """Global flag to enable additional debugging functionality. Defaults to ``True`` if the :envvar:`COCOTB_SCHEDULER_DEBUG` environment variable is set, but can be programmatically set by the user afterwards. The ``"cocotb"`` logger should have its logging level set to :data:`logging.DEBUG` to see additional debugging information in the test log. This can be accomplished by setting the :envvar:`COCOTB_LOG_LEVEL` environment variable to ``DEBUG``, or using the following code. .. code-block:: python import logging logging.getLogger("cocotb").setLevel(logging.DEBUG) """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/handle.py0000644000175100017510000016725115106067236016320 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import enum import logging import os import re from abc import ABC, abstractmethod from functools import lru_cache from logging import Logger from typing import ( Any, Callable, Dict, Generic, Iterable, Iterator, NoReturn, Optional, Sequence, Tuple, Type, TypeVar, Union, cast, ) import cocotb from cocotb import simulator from cocotb._base_triggers import Event from cocotb._deprecation import deprecated from cocotb._gpi_triggers import ( Edge, FallingEdge, ReadOnly, ReadWrite, RisingEdge, ValueChange, current_gpi_trigger, ) from cocotb._py_compat import cached_property, insertion_ordered_dict from cocotb._utils import DocIntEnum from cocotb.task import Task from cocotb.types import Array, Logic, LogicArray, Range from cocotb.types._indexing import do_indexing_changed_warning, indexing_changed __all__ = ( "ArrayObject", "Deposit", "EnumObject", "Force", "Freeze", "GPIDiscovery", "HierarchyArrayObject", "HierarchyObject", "Immediate", "IntegerObject", "LogicArrayObject", "LogicObject", "RealObject", "Release", "SimHandleBase", "StringObject", "ValueObjectBase", ) class _Limits(enum.IntEnum): SIGNED_NBIT = 1 UNSIGNED_NBIT = 2 VECTOR_NBIT = 3 @lru_cache(maxsize=None) def _value_limits(n_bits: int, limits: _Limits) -> Tuple[int, int]: """Calculate min/max for given number of bits and limits class""" if limits == _Limits.SIGNED_NBIT: min_val = -(2 ** (n_bits - 1)) max_val = 2 ** (n_bits - 1) - 1 elif limits == _Limits.UNSIGNED_NBIT: min_val = 0 max_val = 2**n_bits - 1 else: min_val = -(2 ** (n_bits - 1)) max_val = 2**n_bits - 1 return min_val, max_val class SimHandleBase(ABC): """Base class for all simulation objects. All simulation objects are hashable and equatable by identity. .. code-block:: python a = dut.clk b = dut.clk assert a == b .. versionchanged:: 2.0 ``get_definition_name()`` and ``get_definition_file()`` were removed in favor of :meth:`_def_name` and :meth:`_def_file`, respectively. """ @abstractmethod def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: self._handle = handle self._path: str = self._name if path is None else path """The path to this handle, or its name if this is the root handle. :meta public: """ @cached_property def _name(self) -> str: """The name of an object. :meta public: """ return self._handle.get_name_string() @cached_property def _type(self) -> str: """The type of an object as a string. :meta public: """ return self._handle.get_type_string() @cached_property def _log(self) -> Logger: return logging.getLogger(f"cocotb.{self._name}") @cached_property def _def_name(self) -> str: """The name of a GPI object's definition. This is the value of ``vpiDefName`` for VPI, ``vhpiNameP`` for VHPI, and ``mti_GetPrimaryName`` for FLI. Support for this depends on the specific object type and simulator used. :meta public: """ return self._handle.get_definition_name() @cached_property def _def_file(self) -> str: """The name of the file that sources the object's definition. This is the value of ``vpiDefFile`` for VPI, ``vhpiFileNameP`` for VHPI, and ``mti_GetRegionSourceName`` for FLI. Support for this depends on the specific object type and simulator used. :meta public: """ return self._handle.get_definition_file() def __hash__(self) -> int: return hash(self._handle) def __eq__(self, other: object) -> bool: if not isinstance(other, SimHandleBase): return NotImplemented return self._handle == other._handle def __repr__(self) -> str: desc = self._path defname = self._def_name if defname: desc += " with definition " + defname deffile = self._def_file if deffile: desc += " (at " + deffile + ")" return type(self).__qualname__ + "(" + desc + ")" def __bool__(self) -> NoReturn: raise TypeError( "This object cannot be cast to bool or used in conditionals. Use `obj is not None` check in conditionals." ) class _RangeableObjectMixin(SimHandleBase): """Base class for simulation objects that have a range.""" @cached_property def range(self) -> Range: """Return a :class:`~cocotb.types.Range` over the indexes of the array/vector.""" left, right, direction = self._handle.get_range() if direction == simulator.RANGE_NO_DIR: raise RuntimeError("Expected range to have a direction but got none!") return Range(left, "to" if direction == simulator.RANGE_UP else "downto", right) @property def left(self) -> int: """Return the leftmost index in the array/vector.""" return self.range.left @property def direction(self) -> str: """Return the direction (``"to"``/``"downto"``) of indexes in the array/vector.""" return self.range.direction @property def right(self) -> int: """Return the rightmost index in the array/vector.""" return self.range.right def __len__(self) -> int: return len(self.range) #: Type of keys (name or index) in HierarchyObjectBase. KeyType = TypeVar("KeyType") #: Subtype of :class:`SimHandleBase` returned when iterating or indexing a :class:`HierarchyArrayObject`. HierarchyChildObjectT = TypeVar("HierarchyChildObjectT", bound=SimHandleBase) class GPIDiscovery(DocIntEnum): """Simulator object discovery strategy.""" AUTO = (0, "Automatic discovery using all registered interfaces.") NATIVE = (1, "Native discovery using only the parent's native interface.") class _HierarchyObjectBase(SimHandleBase, Generic[KeyType]): """Base class for hierarchical simulation objects. Hierarchical objects don't have values, they are just scopes/namespaces of other objects. This includes array-like hierarchical structures like "generate loops" and named hierarchical structures like "generate blocks" or "module"/"entity" instantiations. This base class defines logic to discover, cache, and inspect child objects. It provides a :class:`dict`-like interface for doing so. :meth:`_keys`, :meth:`_values`, and :meth:`_items` mimic their :class:`dict` counterparts. You can also iterate over an object, which returns child objects, not keys like in :class:`dict`; and can check the :func:`len`. See :class:`HierarchyObject` and :class:`HierarchyArrayObject` for examples. """ @abstractmethod def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) self._sub_handles: Dict[KeyType, SimHandleBase] = {} self._discovered = False def _keys(self) -> Iterable[KeyType]: """Iterate over the keys (name or index) of the child objects. :meta public: """ self._discover_all() return self._sub_handles.keys() def _values(self) -> Iterable[SimHandleBase]: """Iterate over the child objects. :meta public: """ self._discover_all() return self._sub_handles.values() def _items(self) -> Iterable[Tuple[KeyType, SimHandleBase]]: """Iterate over ``(key, object)`` tuples of child objects. :meta public: """ self._discover_all() return self._sub_handles.items() def _discover_all(self) -> None: """When iterating or performing IPython tab completion, we run through ahead of time and discover all possible children, populating the :any:`_sub_handles` mapping. Hierarchy can't change after elaboration so we only have to do this once. """ if self._discovered: return for thing in self._handle.iterate(simulator.OBJECTS): name = thing.get_name_string() # translate HDL name into a consistent key name try: key = self._sub_handle_key(name) except ValueError: self._log.exception( "Unable to translate handle >%s< to a valid _sub_handle key", name, ) continue # compute a full path using the key name path = self._child_path(key) # attempt to create the child object try: hdl = _make_sim_object(thing, path) except NotImplementedError: self._log.exception( "Unable to construct a SimHandle object for %s", path ) continue # add to cache self._sub_handles[key] = hdl self._discovered = True def _get( self, key: KeyType, discovery_method: GPIDiscovery = GPIDiscovery.AUTO ) -> Union[SimHandleBase, None]: """Query the simulator for an object with the specified *key*. Like Python's native dictionary ``get``-function, this returns ``None`` if the object is not found instead of raising an :exc:`AttributeError`. Generally, use the ``handle[child_name]`` syntax instead, unless you have to change the *discovery_method* or want to check for optional signals. :meta public: Args: key: The child object by name. discovery_method: Optional selection of discovery strategy. :data:`~cocotb.handle.GPIDiscovery.AUTO` by default. Returns: The child object, or ``None`` if not found. """ # try to use cached value try: return self._sub_handles[key] except KeyError: pass # try to get value from GPI new_handle = self._get_handle_by_key(key, discovery_method) if new_handle is None: return None # if successful, construct and cache sub_handle = _make_sim_object(new_handle, self._child_path(key)) self._sub_handles[key] = sub_handle return sub_handle @abstractmethod def _get_handle_by_key( self, key: KeyType, discovery_method: GPIDiscovery ) -> Union[simulator.gpi_sim_hdl, None]: """Get child object by key from the simulator. Args: key: The key of the child object. discovery_method: How to discover the object using the GPI. Returns: A raw simulator handle for the child object at the given key, or ``None``. """ @abstractmethod def _child_path(self, key: KeyType) -> str: """Compute the path string of a child object at the given key. Args: key: The key of the child object. Returns: A path string of the child object at the a given key. """ @abstractmethod def _sub_handle_key(self, name: str) -> KeyType: """Translate a discovered child object name into a key. Args: name: The GPI name of the child object. Returns: A unique key for the child object. Raises: ValueError: if unable to translate handle to a valid _sub_handle key. """ def __iter__(self) -> Iterator[SimHandleBase]: return iter(self._values()) def __len__(self) -> int: self._discover_all() return len(self._sub_handles) def __dir__(self) -> Iterable[str]: """Permits IPython tab completion and debuggers to work.""" self._discover_all() return set(super().__dir__()) | {str(k) for k in self._keys()} class HierarchyObject(_HierarchyObjectBase[str]): r"""A simulation object that is a name-indexed collection of hierarchical simulation objects. Inherits from :class:`SimHandleBase`. This class is used for named hierarchical structures, such as "generate blocks" or "module"/"entity" instantiations. Children under this structure are found by using the name of the child with either the attribute syntax or index syntax. For example, if in your :envvar:`COCOTB_TOPLEVEL` entity/module you have a signal/net named ``count``, you could do either of the following. .. code-block:: python dut.count # attribute syntax dut["count"] # index syntax Attribute syntax is usually shorter and easier to read, and is more common. However, it has limitations: - the name cannot start with a number - the name cannot start with a ``_`` character - the name can only contain ASCII letters, numbers, and the ``_`` character. Any possible name of an object is supported with the index syntax, but it can be more verbose. Accessing a non-existent child with attribute syntax results in an :class:`AttributeError`, and accessing a non-existent child with index syntax results in a :class:`KeyError`. .. note:: If you need to access signals/nets that start with ``_``, or use escaped identifier (Verilog) or extended identifier (VHDL) characters, you have to use the index syntax. Accessing escaped/extended identifiers requires enclosing the name with leading and trailing double backslashes (``\\``). .. code-block:: python dut["_underscore_signal"] dut["\\%extended !ID\\"] Iteration yields all child objects in no particular order. The :func:`len` function can be used to find the number of children. .. code-block:: python # discover all children in 'some_module' total = 0 for handle in dut.some_module: cocotb.log("Found %r", handle._path) total += 1 # make sure we found them all assert len(dut.some_module) == total """ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) def __setattr__(self, name: str, value: object) -> None: # private attributes pass through directly if name.startswith("_"): return object.__setattr__(self, name, value) try: getattr(self, name) except AttributeError: raise AttributeError( f"Cannot set attribute {name!r} on simulation object {self._path}. No such object exists." ) from None else: raise AttributeError( f"Cannot set attribute {name!r} on simulation object {self._path}. Did you forget to add `.value`?" ) def __getattr__(self, name: str) -> SimHandleBase: if name.startswith("_"): return object.__getattribute__(self, name) handle = self._get(name) if handle is None: raise AttributeError(f"{self._path} contains no child object named {name}") return handle def __getitem__(self, key: str) -> SimHandleBase: handle = self._get(key) if handle is None: raise KeyError(f"{self._path} contains no child object named {key}") return handle @deprecated( "Use `handle[child_name]` syntax instead. If extended identifiers are needed simply add a '\\' character before and after the name." ) def _id(self, name: str, extended: bool = True) -> SimHandleBase: """Query the simulator for an object with the specified *name*. If *extended* is ``True``, run the query only for VHDL extended identifiers. For Verilog, only ``extended=False`` is supported. :meta public: Args: name: The child object by name. extended: If ``True``, treat the *name* as an extended identifier. Returns: The child object. Raises: AttributeError: If the child object is not found. .. deprecated:: 2.0 Use ``handle[child_name]`` syntax instead. If extended identifiers are needed simply add a ``\\`` character before and after the name. """ if extended: name = "\\" + name + "\\" handle = self._get(name) if handle is None: raise AttributeError(f"{self._path} contains no child object named {name}") return handle def _child_path(self, key: str) -> str: delimiter = "::" if self._type == "GPI_PACKAGE" else "." return f"{self._path}{delimiter}{key}" def _sub_handle_key(self, name: str) -> str: return name def _get_handle_by_key( self, key: str, discovery_method: GPIDiscovery ) -> Union[simulator.gpi_sim_hdl, None]: return self._handle.get_handle_by_name(key, discovery_method) class HierarchyArrayObject( _HierarchyObjectBase[int], _RangeableObjectMixin, Generic[HierarchyChildObjectT] ): """A simulation object that is an array of hierarchical simulation objects. Inherits from :class:`SimHandleBase`. This class is used for array-like hierarchical structures like "generate loops". Children of this object are found by supplying a numerical index using index syntax. For example, if you have a design with a generate loop ``gen_pipe_stages`` from the range ``0`` to ``7``: .. code-block:: python block_0 = dut.gen_pipe_stages[0] block_7 = dut.gen_pipe_stages[7] Accessing a non-existent child results in an :class:`IndexError`. Iteration yields all child objects in order. .. code-block:: python # set all 'reg's in each pipe stage to 0 for pipe_stage in dut.gen_pipe_stages: pipe_stage.reg.value = 0 Use the :meth:`range` property if you want to iterate over the indexes. The :func:`len` function can be used to find the number of elements. .. code-block:: python # set all 'reg's in each pipe stage to 0 for idx in dut.gen_pipe_stages.range: dut.gen_pipe_stages[idx].reg.value = 0 # make sure we have all the pipe stages assert len(dut.gen_pipe_stage) == len(dut.gen_pipe_stages.range) """ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) def _sub_handle_key(self, name: str) -> int: # This is slightly hacky, but we need to extract the index from the name # See also GEN_IDX_SEP_* in VhpiImpl.h for the VHPI separators. # # FLI and VHPI: _name(X) where X is the index # VHPI(ALDEC): _name__X where X is the index # VPI: _name[X] where X is the index result = re.match(rf"{re.escape(self._name)}__(?P\d+)$", name) if not result: result = re.match( rf"{re.escape(self._name)}\((?P\d+)\)$", name, re.IGNORECASE ) if not result: result = re.match(rf"{re.escape(self._name)}\[(?P\d+)\]$", name) if result: return int(result.group("index")) else: raise ValueError(f"Unable to match an index pattern: {name}") def _child_path(self, key: int) -> str: return f"{self._path}[{key}]" def _get_handle_by_key( self, key: int, discovery_method: GPIDiscovery ) -> Union[simulator.gpi_sim_hdl, None]: if discovery_method is not GPIDiscovery.AUTO: raise NotImplementedError( f"Only GPIDiscovery.AUTO is supported for {type(self).__qualname__} right now" ) return self._handle.get_handle_by_index(key) def __getitem__(self, key: int) -> HierarchyChildObjectT: if isinstance(key, slice): raise TypeError("Slice indexing is not supported") handle = self._get(key) if handle is None: raise IndexError(f"{self._path} contains no child object at index {key}") return cast("HierarchyChildObjectT", handle) # ideally `__len__` could be implemented in terms of `range`, but `range` doesn't work universally. def __iter__(self) -> Iterator[HierarchyChildObjectT]: # must use `sorted(self._keys())` instead of the range because `range` doesn't work universally. for i in sorted(self._keys()): yield self[i] class _GPISetAction(enum.Enum): DEPOSIT = 0 FORCE = 1 RELEASE = 2 NO_DELAY = 3 OLD_IMMEDIATE = 0 _ValueT = TypeVar("_ValueT") class Deposit(Generic[_ValueT]): r""":term:`Inertially deposit ` the given value on a simulator object. If another :term:`deposit` comes after this deposit, the newer deposit overwrites the old value. If an HDL process is :term:`driving` the signal/net/register where a deposit from cocotb is made, the deposited value will be overwritten at the end of the next delta cycle, essentially causing a single delta cycle "glitch" in the waveform. .. note:: VHDL applies writes according to their definition. ``signal`` writes are set inertially, regardless of using this class; while ``variable`` writes are set immediately, regardless of using this class. """ def __init__(self, value: _ValueT) -> None: self.value = value class Force(Generic[_ValueT]): r""":term:`Force ` the given value on a simulator object immediately. Further :term:`deposits ` from cocotb or :term:`drives ` from HDL processes do not cause the value to change until the handle is :term:`released ` by cocotb or HDL code. Further :term:`forces ` will overwrite the value and leave the value forced. .. note:: VHDL applies writes according to their definition. ``signal`` writes are set inertially, regardless of using this class; while ``variable`` writes are set immediately, regardless of using this class. .. note:: Verilog :class:`!Force`\ s are always immediate. This also means that if there are multiple cocotb Tasks or multiple ``always`` blocks writing to the same object, the resulting value is non-deterministic. .. note:: Issuing a :class:`!Force` and :class:`Release` in the same evaluation cycle in VHDL will result in the :class:`!Force` "winning". """ def __init__(self, value: _ValueT) -> None: self.value = value class Freeze: r""":term:`Force ` the simulator object with its current value. Useful if you have done a :term:`deposit` and later decide to lock the value from changing. Does not change the current value of the simulation object. See :class:`Force` for information on behavior after this write completes. .. note:: VHDL applies writes according to their definition. ``signal`` writes are set inertially, regardless of using this class; while ``variable`` writes are set immediately, regardless of using this class. .. note:: Verilog :class:`Force`\ s are always immediate. This also means that if there are multiple cocotb Tasks or multiple ``always`` blocks writing to the same object, the resulting value is non-deterministic. .. note:: Issuing a :class:`!Force` and :class:`Release` in the same evaluation cycle in VHDL will result in the :class:`!Force` "winning". """ class Release: r""":term:`Release ` a :term:`forced ` simulation object. Does not change the current value of the simulation object. See :class:`Deposit` for information on behavior after this write completes. .. note:: VHDL applies writes according to their definition. ``signal`` writes are set inertially, regardless of using this class, while ``variable`` writes are set immediately, regardless of using this class. .. note:: Verilog :class:`!Release`\ s are always immediate. This also means that if there are multiple cocotb Tasks or multiple ``always`` blocks writing to the same object, the resulting value is non-deterministic. .. note:: Issuing a :class:`Force` and :class:`!Release` in the same evaluation cycle in VHDL will result in the :class:`!Force` "winning". .. note:: Releasing a ``reg`` or ``logic`` in Verilog will leave the current value. Releasing a ``wire`` in Verilog will cause the value to be recomputed from the wire's drivers current values. Releasing a ``signal`` in VHDL will cause the value to be recomputed from the signal's drivers current value. Unconnected ``in`` ports and unconnected internal signals have no drivers and their value after :class:`!Release` will be ``U`` in VHDL and ``X`` in Verilog. """ class Immediate(Generic[_ValueT]): """:term:`Deposit ` a value on a simulator object without delay. The value of the signal will be changed immediately and should be able to be read back immediately following the write. Otherwise, behaves like :class:`Deposit`. .. note:: VHDL applies writes according to their definition. ``signal`` writes are set inertially, regardless of using this class; while ``variable`` writes are set immediately, regardless of using this class. .. note:: In Verilog, because these writes are immediate, if there are multiple cocotb Tasks or multiple ``always`` blocks writing to the same object, the resulting value is non-deterministic. """ def __init__(self, value: _ValueT) -> None: self.value = value class _OldImmediate(Generic[_ValueT]): def __init__(self, value: _ValueT) -> None: self.value = value _trust_inertial = bool(int(os.environ.get("COCOTB_TRUST_INERTIAL_WRITES", "0"))) # A dictionary of pending (write_func, args), keyed by handle. # Writes are applied oldest to newest (least recently used). # Only the last scheduled write to a particular handle in a timestep is performed. _write_calls: "dict[ValueObjectBase[Any, Any], Tuple[Callable[[int, Any], None], _GPISetAction, Any]]" = insertion_ordered_dict() _write_task: Union[Task[None], None] = None _writes_pending = Event() async def _do_writes() -> None: """An internal task that schedules a ReadWrite to force writes to occur.""" while True: await _writes_pending.wait() await ReadWrite() def _start_write_scheduler() -> None: global _write_task if _write_task is None: _write_task = Task(_do_writes()) cocotb._scheduler_inst._schedule_task(_write_task) def _stop_write_scheduler() -> None: global _write_task if _write_task is not None: _write_task.cancel() _write_task = None _write_calls.clear() _writes_pending.clear() def _apply_scheduled_writes() -> None: for func, action, value in _write_calls.values(): func(action.value, value) _write_calls.clear() _writes_pending.clear() if _trust_inertial: def _schedule_write( handle: "ValueObjectBase[Any, Any]", write_func: Callable[[int, _ValueT], None], action: _GPISetAction, value: _ValueT, ) -> None: # Trust the simulator and just write. write_func(action.value, value) else: def _schedule_write( handle: "ValueObjectBase[Any, Any]", write_func: Callable[[int, _ValueT], None], action: _GPISetAction, value: _ValueT, ) -> None: if isinstance(current_gpi_trigger(), ReadWrite): # If we are already in the ReadWrite phase, apply writes immediately as an optimization. write_func(action.value, value) elif action is _GPISetAction.DEPOSIT: # Queue write for the beginning of the next ReadWrite phase because we can't trust the simulator. =( if handle in _write_calls: del _write_calls[handle] _write_calls[handle] = (write_func, action, value) _writes_pending.set() else: # If we are writing anything that isn't an inertial write, it must be applied immediately. write_func(action.value, value) #: Type returned by the :attr:`~ValueObjectBase.value` getter and returned by the :meth:`~ValueObjectBase.get` method. ValueGetT = TypeVar("ValueGetT") #: Type accepted by the :attr:`~ValueObjectBase.value` setter and the :meth:`~ValueObjectBase.set` and :meth:`~ValueObjectBase.setimmediatevalue` methods. ValueSetT = TypeVar("ValueSetT") class ValueObjectBase(SimHandleBase, Generic[ValueGetT, ValueSetT]): """Abstract base class for simulation objects that have a value. Inherits from :class:`SimHandleBase`. """ @property def value(self) -> ValueGetT: """Get or set the value of the simulation object. :getter: Return the current value of the simulation object. :setter: Set the value of the simulation object. See :class:`Deposit`, :class:`Force`, :class:`Freeze`, :class:`Release`, and :class:`Immediate` for additional actions that can be taken when setting a value. These are used like so: .. code-block:: python dut.handle.value = 1 # default Deposit action dut.handle.value = Deposit(2) dut.handle.value = Force(3) dut.handle.value = Freeze() dut.handle.value = Release() dut.handle.value = Immediate(4) """ return self.get() @value.setter def value(self, value: ValueSetT) -> None: self.set(value) @abstractmethod def get(self) -> ValueGetT: """Return the current value of the simulation object.""" def set( self, value: Union[ ValueSetT, Deposit[ValueSetT], Force[ValueSetT], Freeze, Release, Immediate[ValueSetT], ], ) -> None: """Set the value of the simulation object. See :class:`Deposit`, :class:`Force`, :class:`Freeze`, :class:`Release`, and :class:`Immediate` for additional actions that can be taken when setting a value. Args: value: The value to set the simulation object to. This may include type conversion. Raises: TypeError: If the *value* is of a type that cannot be converted to a simulation value, or if the simulation object is immutable. ValueError: If the *value* is of the correct type, but the value fails to convert. """ if isinstance(current_gpi_trigger(), ReadOnly): raise RuntimeError("Attempting settings a value during the ReadOnly phase.") if self.is_const: raise TypeError("Attempted setting an immutable object") if isinstance(value, Deposit): self._set_value(value.value, _GPISetAction.DEPOSIT) elif isinstance(value, Force): self._set_value(value.value, _GPISetAction.FORCE) elif isinstance(value, Freeze): # We assume that ValueSetT >= ValueGetT self._set_value(cast("ValueSetT", self.get()), _GPISetAction.FORCE) elif isinstance(value, Release): # We assume that ValueSetT >= ValueGetT self._set_value(cast("ValueSetT", self.get()), _GPISetAction.RELEASE) elif isinstance(value, Immediate): self._set_value(value.value, _GPISetAction.NO_DELAY) elif isinstance(value, _OldImmediate): self._set_value(value.value, _GPISetAction.OLD_IMMEDIATE) else: self._set_value(value, _GPISetAction.DEPOSIT) @deprecated( "Use `handle.set(Immediate(...))` or `handle.value = Immediate(...)` instead." ) def setimmediatevalue( self, value: Union[ ValueSetT, Deposit[ValueSetT], Force[ValueSetT], Freeze, Release, Immediate[ValueSetT], ], ) -> None: r"""Set the value of the simulation object immediately. See :class:`Deposit`, :class:`Force`, :class:`Freeze`, :class:`Release`, and :class:`Immediate` for additional actions that can be taken when setting a value. Passing :class:`Deposit`\ s and unwrapped values is equivalent to passing an :class:`Immediate` to :meth:`set`. .. deprecated:: 2.0 Use ``handle.set(Immediate(...))`` or ``handle.value = Immediate(...)`` instead. This could result in a change in behavior because prior to version 2.0 this function did not set values immediately. """ if isinstance(value, Deposit): value = _OldImmediate(value.value) # type: ignore elif not isinstance(value, (Force, Freeze, Release, Immediate)): value = _OldImmediate(value) # type: ignore self.set(value) @cached_property def is_const(self) -> bool: """``True`` if the simulator object is immutable, e.g. a Verilog parameter or VHDL constant or generic.""" return self._handle.get_const() @abstractmethod def _set_value( self, value: ValueSetT, action: _GPISetAction, ) -> None: """Schedule a write of the given value to a simulator object. Conversion from multiple Python types into a type understood by the simulator is expected. This is used to implement the :attr:`value` property setter, :meth:`setimmediatevalue`, and :meth:`set`. Implementations can assume that handle isn't :meth:`const ` and the Scheduler is not in the :data:`ReadOnly ` phase. Args: value: A value used to set the handle. action: Whether to deposit, force, or release the value on the handle. """ #: Type of value of each element in an :class:`ArrayObject`. ElemValueT = TypeVar("ElemValueT") #: Subtype of :class:`ValueObjectBase` returned when iterating or indexing a :class:`ArrayObject`. ChildObjectT = TypeVar("ChildObjectT", bound=ValueObjectBase[Any, Any]) class ArrayObject( ValueObjectBase[Array[ElemValueT], Union[Array[ElemValueT], Sequence[ElemValueT]]], _RangeableObjectMixin, Generic[ElemValueT, ChildObjectT], ): """A simulation object that is an array of value-having simulation objects. Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`. With Verilog simulation objects, unpacked vectors are mapped to this type. Packed vectors are typically mapped to :class:`LogicArrayObject`. With VHDL simulation objects, all arrayed objects that aren't ``std_(u)logic``, ``sfixed``, ``ufixed``, ``unsigned``, ``signed``, and ``string`` are mapped to this type. These objects can be iterated over to yield child objects: .. code-block:: python for child in dut.array_object: print(child._path) A particular child can be retrieved using its index: .. code-block:: python child = dut.array_object[0] # reversed iteration over children for child_idx in reversed(dut.array_object.range): dut.array_object[child_idx] """ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) self._sub_handles: Dict[int, ChildObjectT] = {} def get(self) -> Array[ElemValueT]: """Return the current value as an :class:`~cocotb.types.Array`. Given the HDL array ``arr``, getting the value is equivalent to: +--------------+---------------------+--------------------------------------------------------------------------------------------------+ | Verilog | VHDL | ``arr.get()`` is equivalent to | +==============+=====================+==================================================================================================+ | ``arr[4:7]`` | ``arr(4 to 7)`` | ``Array([arr[4].value, arr[5].value, arr[6].value, arr[7].value], range=Range(4, 'to', 7))`` | +--------------+---------------------+--------------------------------------------------------------------------------------------------+ | ``arr[7:4]`` | ``arr(7 downto 4)`` | ``Array([arr[7].value, arr[6].value, arr[5].value, arr[4].value], range=Range(7, 'downto', 4))`` | +--------------+---------------------+--------------------------------------------------------------------------------------------------+ """ r = self.range return Array._from_handle( value=[self[i].value for i in r], range=r, warn_indexing=indexing_changed(r) if do_indexing_changed_warning else False, ) def set( self, value: Union[ Union[Array[ElemValueT], Sequence[ElemValueT]], Deposit[Union[Array[ElemValueT], Sequence[ElemValueT]]], Force[Union[Array[ElemValueT], Sequence[ElemValueT]]], Freeze, Release, Immediate[Union[Array[ElemValueT], Sequence[ElemValueT]]], ], ) -> None: """Set the value using an :class:`.Array`-like value. The simulation object is set, element-by-element, left-to-right, using the corresponding element of *value*. The indexes of *value* and the simulation object are not taken into account, only position. .. warning:: Assigning a value to a sub-handle: - **Wrong**: ``dut.some_array.value[0] = 1`` (gets value as an Array, updates index 0, then throws it away) - **Correct**: ``dut.some_array[0].value = 1`` Args: value: The value to set the signal to. This may include type conversion. Raises: TypeError: If *value* is of a type that can't be assigned to the simulation object. .. warning:: Exceptions from array element :meth:`.ValueObjectBase.set` calls will be propagated up, so the actual set of exceptions possible is greater than this list. """ super().set(value) def _set_value( self, value: Union[Array[ElemValueT], Sequence[ElemValueT]], action: _GPISetAction, ) -> None: if len(value) != len(self): raise ValueError( f"Assigning list of length {len(value)} to object {self._name} of length {len(self)}" ) for elem, self_idx in zip(value, self.range): self[self_idx]._set_value(elem, action) def __getitem__(self, index: int) -> ChildObjectT: if isinstance(index, slice): raise TypeError("Slicing is not supported") if index in self._sub_handles: return self._sub_handles[index] new_handle = self._handle.get_handle_by_index(index) if not new_handle: raise IndexError(f"{self._path} contains no object at index {index}") path = self._path + "[" + str(index) + "]" self._sub_handles[index] = cast( "ChildObjectT", _make_sim_object(new_handle, path) ) return self._sub_handles[index] def __iter__(self) -> Iterable[ChildObjectT]: for i in self.range: yield self[i] class _NonIndexableValueObjectBase(ValueObjectBase[ValueGetT, ValueSetT]): """ValueObject that is treated as a single object in the GPI. NonArrayValueObjects support :meth:`value_change` triggers. """ @cached_property def value_change(self) -> ValueChange: """A trigger which fires whenever the value changes.""" if self.is_const: raise TypeError("Can't get ValueChange on immutable signal.") return ValueChange._make(self) @cached_property def _edge(self) -> Edge: if self.is_const: raise TypeError("Can't get Edge on immutable signal.") return Edge._make(self) class LogicObject(_NonIndexableValueObjectBase[Logic, Union[Logic, int, str]]): """A scalar logic simulation object. Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`. Verilog data types that map to this object: * ``logic`` * ``bit`` VHDL types that map to this object: * ``std_logic`` * ``std_ulogic`` * ``bit`` """ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) def _set_value( self, value: Union[Logic, int, str], action: _GPISetAction, ) -> None: value_: str if isinstance(value, (int, str)): value_ = str(Logic(value)) elif isinstance(value, LogicArray): if len(value) != 1: raise ValueError( f"Cannot assign value of length {len(value)} to handle of length 1" ) value_ = str(value) elif isinstance(value, Logic): value_ = str(value) else: raise TypeError( f"Unsupported type for value assignment: {type(value)} ({value!r})" ) _schedule_write(self, self._handle.set_signal_val_binstr, action, value_) def get(self) -> Logic: """Return the current value of the simulation object as a :class:`.Logic`.""" binstr = self._handle.get_signal_val_binstr() return Logic(binstr) def set( self, value: Union[ Union[Logic, int, str], Deposit[Union[Logic, int, str]], Force[Union[Logic, int, str]], Freeze, Release, Immediate[Union[Logic, int, str]], ], ) -> None: """Set the value of the simulation object using a :class:`.Logic`-like value. Args: value: The value to set the simulation object to. Raises: TypeError: If *value* is of a type that can't be assigned to the simulation object, or readily converted into a type that can. ValueError: If *value* would not fit in the bounds of the simulation object. """ super().set(value) @cached_property def rising_edge(self) -> RisingEdge: """A trigger which fires whenever the value changes to a ``1``.""" if self.is_const: raise TypeError("Can't get RisingEdge on immutable signal") return RisingEdge._make(self) @cached_property def falling_edge(self) -> FallingEdge: """A trigger which fires whenever the value changes to a ``0``.""" if self.is_const: raise TypeError("Can't get FallingEdge on immutable signal") return FallingEdge._make(self) def __len__(self) -> int: return 1 @deprecated( "`int(handle)` casts have been deprecated. Use `int(handle.value)` instead." ) def __int__(self) -> int: return int(self.value) @deprecated( "`str(handle)` casts have been deprecated. Use `str(handle.value)` instead." ) def __str__(self) -> str: return str(self.value) class LogicArrayObject( _NonIndexableValueObjectBase[LogicArray, Union[LogicArray, Logic, int, str]], _RangeableObjectMixin, ): """A logic array simulation object. Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`. Verilog types that map to this object: * packed any-dimensional vectors of ``logic`` or ``bit`` * packed any-dimensional vectors of packed structures VHDL types that map to this object: * ``std_logic_vector`` and ``std_ulogic_vector`` * ``unsigned`` * ``signed`` * ``ufixed`` * ``sfixed`` * ``float`` """ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) def _set_value( self, value: Union[LogicArray, Logic, int, str], action: _GPISetAction, ) -> None: value_: str if isinstance(value, int): min_val, max_val = _value_limits(len(self), _Limits.VECTOR_NBIT) if min_val <= value <= max_val: if len(self) <= 32: _schedule_write( self, self._handle.set_signal_val_int, action, value ) return # LogicArray used for checking if value < 0: value_ = str( LogicArray.from_signed( value, Range(len(self) - 1, "downto", 0), ) ) else: value_ = str( LogicArray.from_unsigned( value, Range(len(self) - 1, "downto", 0), ) ) else: raise ValueError( f"Int value ({value!r}) out of range for assignment of {len(self)!r}-bit signal ({self._name!r})" ) elif isinstance(value, str): # LogicArray used for checking value_ = str(LogicArray(value, self.range)) elif isinstance(value, LogicArray): if len(self) != len(value): raise ValueError( f"cannot assign value of length {len(value)} to handle of length {len(self)}" ) value_ = str(value) elif isinstance(value, Logic): if len(self) != 1: raise ValueError( f"cannot assign value of length 1 to handle of length {len(self)}" ) value_ = str(value) else: raise TypeError( f"Unsupported type for value assignment: {type(value)} ({value!r})" ) _schedule_write(self, self._handle.set_signal_val_binstr, action, value_) def get(self) -> LogicArray: """Return the current value of the simulation object as a :class:`.LogicArray`.""" binstr = self._handle.get_signal_val_binstr() return LogicArray._from_handle( value=binstr, warn_indexing=indexing_changed(self.range) if do_indexing_changed_warning else False, ) def set( self, value: Union[ Union[LogicArray, Logic, int, str], Deposit[Union[LogicArray, Logic, int, str]], Force[Union[LogicArray, Logic, int, str]], Freeze, Release, Immediate[Union[LogicArray, Logic, int, str]], ], ) -> None: """Set the value of the simulation object using a :class:`.LogicArray`-like value. Args: value: The value to set the simulation object to. Raises: TypeError: If *value* is of a type that can't be assigned to the simulation object, or readily converted into a type that can. ValueError: If *value* would not fit in the bounds of the simulation object. .. versionchanged:: 2.0 Using :class:`ctypes.Structure` objects to set values was removed. Convert the struct object to a :class:`~cocotb.types.LogicArray` before assignment using ``LogicArray("".join(format(int(byte), "08b") for byte in bytes(struct_obj)))`` instead. .. versionchanged:: 2.0 Using :class:`dict` objects to set values was removed. Convert the dictionary to an integer before assignment using ``sum(v << (d['bits'] * i) for i, v in enumerate(d['values']))`` instead. .. versionchanged:: 2.0 Supplying too large of an :class:`int` value results in raising a :exc:`ValueError` instead of an :exc:`OverflowError`. """ super().set(value) @deprecated( "`int(handle)` casts have been deprecated. Use `int(handle.value)` instead." ) def __int__(self) -> int: return int(self.value) @deprecated( "`str(handle)` casts have been deprecated. Use `str(handle.value)` instead." ) def __str__(self) -> str: return str(self.value) def __len__(self) -> int: # can't use `range` to get length because `range` is for outer-most dimension only # and this object needs to support multi-dimensional packed arrays. return self._len @cached_property def _len(self) -> int: return self._handle.get_num_elems() def __getitem__(self, _: object) -> NoReturn: raise TypeError( "Packed objects, either arrays or structs, cannot be indexed.\n" "Try instead reading the whole value and slicing: `t = handle.value; t[0:3]`.\n" "If you need to use an element in an Edge Trigger, consider making the array or struct unpacked.\n" "Alternatively, use `ValueChange` on the whole object and check the bit(s) you care about for changes afterwards." ) class RealObject(_NonIndexableValueObjectBase[float, float]): """A floating point simulation object. Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`. This type is used when a ``real`` object in VHDL or ``float`` object in Verilog is seen. """ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) def _set_value( self, value: float, action: _GPISetAction, ) -> None: if not isinstance(value, (float, int)): raise TypeError( f"Unsupported type for real value assignment: {type(value)} ({value!r})" ) _schedule_write(self, self._handle.set_signal_val_real, action, value) def get(self) -> float: """Return the current value of the simulation object as a :class:`float`.""" return self._handle.get_signal_val_real() def set( self, value: Union[ float, Deposit[float], Force[float], Freeze, Release, Immediate[float], ], ) -> None: """Set the value of the simulation object using a :class:`float` value. Args: value: The value to set the simulation object to. Raises: TypeError: If *value* is any type other than :class:`float`. """ super().set(value) @deprecated( "`float(handle)` casts have been deprecated. Use `float(handle.value)` instead." ) def __float__(self) -> float: return self.value class EnumObject(_NonIndexableValueObjectBase[int, int]): """An enumeration simulation object. Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`. This type is used when an enumerated-type simulation object is seen that aren't a "logic" or similar type. The value of this object is represented with an :class:`int`. For VHDL objects, the value being represented is the enumeration value at the integer index into the original ``type`` declaration, as if it were a 1-based array. For Verilog objects, enumerations are little more than named integer values. There may be many enumeration values that a given :class:`int` value represents. """ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) def _set_value( self, value: int, action: _GPISetAction, ) -> None: if not isinstance(value, int): raise TypeError( f"Unsupported type for enum value assignment: {type(value)} ({value!r})" ) min_val, max_val = _value_limits(32, _Limits.UNSIGNED_NBIT) if min_val <= value <= max_val: _schedule_write(self, self._handle.set_signal_val_int, action, value) else: raise ValueError( f"Int value ({value!r}) out of range for assignment of enum signal ({self._name!r})" ) def get(self) -> int: """Return the current value of the simulation object as an :class:`int`. See :class:`EnumObject` for details on what :class:`int` values correspond to which enumeration values. """ return self._handle.get_signal_val_long() def set( self, value: Union[ int, Deposit[int], Force[int], Freeze, Release, Immediate[int], ], ) -> None: """Set the value of the simulation object using an :class:`int`. See :class:`EnumObject` for details on what :class:`int` values correspond to which enumeration values. Args: value: The value to set the simulation object to. Raises: TypeError: If *value* is any type other than :class:`int`. ValueError: If *value* would not fit in a 32-bit signed integer. .. versionchanged:: 2.0 Supplying too large of a value results in raising a :exc:`ValueError` instead of an :exc:`OverflowError`. """ super().set(value) @deprecated( "`int(handle)` casts have been deprecated. Use `int(handle.value)` instead." ) def __int__(self) -> int: return int(self.value) class IntegerObject(_NonIndexableValueObjectBase[int, int]): """An integer simulation object. Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`. Verilog types that map to this object: * ``byte`` * ``shortint`` * ``int`` * ``longint`` This type should not be used for the 4-state integer types ``integer`` and ``time``. VHDL types that map to this object: * ``integer`` * ``natural`` * ``positive`` Objects that use this type are assumed to be two's complement 32-bit integers with 2-state (``0`` and ``1``) bits. """ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) def _set_value( self, value: int, action: _GPISetAction, ) -> None: if not isinstance(value, int): raise TypeError( f"Unsupported type for integer value assignment: {type(value)} ({value!r})" ) min_val, max_val = _value_limits(32, _Limits.SIGNED_NBIT) if min_val <= value <= max_val: _schedule_write(self, self._handle.set_signal_val_int, action, value) else: raise ValueError( f"Int value ({value!r}) out of range for assignment of integer signal ({self._name!r})" ) def get(self) -> int: """Return the current value of the simulation object as an :class:`int`.""" return self._handle.get_signal_val_long() def set( self, value: Union[ int, Deposit[int], Force[int], Freeze, Release, Immediate[int], ], ) -> None: """Set the the value of the simulation object using an :class:`int` value. Args: value: The value to set the simulation object to. Raises: TypeError: If *value* is any type other than :class:`int`. ValueError: If *value* would not fit in a 32-bit signed integer. .. versionchanged:: 2.0 Supplying too large of a value results in raising a :exc:`ValueError` instead of an :exc:`OverflowError`. """ super().set(value) @deprecated( "`int(handle)` casts have been deprecated. Use `int(handle.value)` instead." ) def __int__(self) -> int: return self.value class StringObject( _NonIndexableValueObjectBase[bytes, bytes], _RangeableObjectMixin, ): """A string simulation object. Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`. This type is used when a ``string`` (VHDL or Verilog) simulation object is seen. """ def __init__(self, handle: simulator.gpi_sim_hdl, path: Optional[str]) -> None: super().__init__(handle, path) def _set_value( self, value: bytes, action: _GPISetAction, ) -> None: if not isinstance(value, (bytes, bytearray)): raise TypeError( f"Unsupported type for string value assignment: {type(value)} ({value!r})" ) _schedule_write(self, self._handle.set_signal_val_str, action, value) def get(self) -> bytes: """Return the current value of the simulation object as a :class:`bytes`.""" return self._handle.get_signal_val_str() def set( self, value: Union[ bytes, Deposit[bytes], Force[bytes], Freeze, Release, Immediate[bytes], ], ) -> None: """Set the value of the simulation object with a :class:`bytes` or :class:`bytearray` value. When *value*'s length is less than the simulation object's, the value is padded with NUL (``'\0'``) characters up to the appropriate length. When the value's length is greater than the simulation object's, the value is truncated without a NUL terminator to the appropriate length, without warning. Strings in both Verilog and VHDL are byte arrays without any particular encoding. Encoding must be done to turn Python strings into byte arrays. Because `there are many encodings `_, this step is left up to the user. An example of how encoding and decoding could be accomplished using an ASCII string. .. code-block:: python # lowercase a string value = dut.string_handle.value.decode("ascii") value = value.lower() dut.string_handle.value = value.encode("ascii") Args: value: The value to set the simulation object to. Raises: TypeError: If *value* is any type other than :class:`bytes`. .. versionchanged:: 1.4 Takes :class:`bytes` instead of :class:`str`. Users are now expected to choose an encoding when using these objects. """ super().set(value) @deprecated( '`str(handle)` casts have been deprecated. Use `handle.value.decode("ascii")` instead.' ) def __str__(self) -> str: return self.value.decode("ascii") _ConcreteHandleTypes = Union[ HierarchyObject, HierarchyArrayObject[SimHandleBase], LogicObject, LogicArrayObject, ArrayObject[Any, ValueObjectBase[Any, Any]], RealObject, IntegerObject, EnumObject, StringObject, ] _handle2obj: Dict[ simulator.gpi_sim_hdl, _ConcreteHandleTypes, ] = {} _type2cls: Dict[int, Type[_ConcreteHandleTypes]] = { simulator.MODULE: HierarchyObject, simulator.STRUCTURE: HierarchyObject, simulator.PACKED_STRUCTURE: LogicArrayObject, simulator.LOGIC: LogicObject, simulator.LOGIC_ARRAY: LogicArrayObject, simulator.NETARRAY: ArrayObject[Any, ValueObjectBase[Any, Any]], simulator.REAL: RealObject, simulator.INTEGER: IntegerObject, simulator.ENUM: EnumObject, simulator.STRING: StringObject, simulator.GENARRAY: HierarchyArrayObject[SimHandleBase], simulator.PACKAGE: HierarchyObject, } def _make_sim_object( handle: simulator.gpi_sim_hdl, path: Optional[str] = None ) -> SimHandleBase: """Factory function to create the correct type of `SimHandle` object. Args: handle: The GPI handle to the simulator object. path: Path to this handle. Returns: An appropriate :class:`SimHandleBase` object. Raises: NotImplementedError: If no matching object for GPI type could be found. """ # Enforce singletons since it's possible to retrieve handles avoiding # the hierarchy by getting driver/load information try: return _handle2obj[handle] except KeyError: pass t = handle.get_type() if t not in _type2cls: raise NotImplementedError( f"Couldn't find a matching object for GPI type {handle.get_type_string()}({t}) (path={path})" ) obj = _type2cls[t](handle, path) _handle2obj[handle] = obj return obj ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/logging.py0000644000175100017510000003235515106067236016507 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013, 2018 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """ Everything related to logging """ import logging import os import re import sys import time import warnings from functools import wraps from typing import Optional, Tuple, Union import cocotb.simtime from cocotb import simulator from cocotb._ANSI import ANSI from cocotb._deprecation import deprecated from cocotb.simtime import get_sim_time from cocotb.utils import get_time_from_sim_steps __all__ = ( "ANSI", "SimLog", "SimLogFormatter", "SimTimeContextFilter", "default_config", "strip_ansi", ) ANSI.__module__ = __name__ # Custom log level logging.TRACE = 5 # type: ignore[attr-defined] # type checkers don't like adding module attributes after the fact logging.addLevelName(5, "TRACE") strip_ansi: bool = False """Whether the default formatter should strip ANSI (color) escape codes from log messages. Defaults to ``True`` if ``stdout`` is not a TTY and ``False`` otherwise; but can be overridden with the :envvar:`NO_COLOR` or :envvar:`COCOTB_ANSI_OUTPUT` environment variable. """ def default_config( reduced_log_fmt: bool = True, strip_ansi: Optional[bool] = None, prefix_format: Optional[str] = None, ) -> None: """Apply the default cocotb log formatting to the root logger. This hooks up the logger to write to stdout, using :class:`SimLogFormatter` for formatting. It also adds a :class:`SimTimeContextFilter` filter so that the :attr:`~logging.LogRecord.created_sim_time` attribute on :class:`~logging.LogRecord` is available to the formatter. If desired, this logging configuration can be overwritten by calling ``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards), or by manually resetting the root logger instance. An example of this can be found in the section on :ref:`rotating-logger`. Args: reduced_log_fmt: If ``True``, use a reduced log format that does not include the filename, line number, and function name in the log prefix. .. versionadded:: 2.0 strip_ansi: If ``True``, strip ANSI (color) escape codes in log messages. If ``False``, do not strip ANSI escape codes in log messages. If ``None``, use the value of :data:`strip_ansi`. .. versionadded:: 2.0 prefix_format: An f-string to build a prefix for each log message. .. versionadded:: 2.0 .. versionadded:: 1.4 .. versionchanged:: 2.0 Now captures warnings and outputs them through the logging system using :func:`logging.captureWarnings`. """ logging.basicConfig() hdlr = logging.StreamHandler(sys.stdout) hdlr.addFilter(SimTimeContextFilter()) hdlr.setFormatter( SimLogFormatter( reduced_log_fmt=reduced_log_fmt, strip_ansi=strip_ansi, prefix_format=prefix_format, ) ) logging.getLogger().handlers = [hdlr] # overwrite default handlers logging.getLogger("cocotb").setLevel(logging.INFO) logging.getLogger("gpi").setLevel(logging.INFO) logging.captureWarnings(True) def _init() -> None: """cocotb-specific logging setup. - Decides whether ANSI escape code stripping is desired by checking :envvar:`NO_COLOR` and :envvar:`COCOTB_ANSI_OUTPUT`. - Initializes the GPI logger and sets up the GPI logging optimization. - Sets the log level of the ``"cocotb"`` and ``"gpi"`` loggers based on :envvar:`COCOTB_LOG_LEVEL` and :envvar:`GPI_LOG_LEVEL`, respectively. """ global strip_ansi strip_ansi = not sys.stdout.isatty() # default to color for TTYs if os.getenv("NO_COLOR", ""): strip_ansi = True ansi_output = os.getenv("COCOTB_ANSI_OUTPUT") if ansi_output is not None: strip_ansi = not int(ansi_output) in_gui = os.getenv("GUI") if in_gui is not None: strip_ansi = bool(int(in_gui)) # Monkeypatch "gpi" logger with function that also sets a PyGPI-local logger level # as an optimization. gpi_logger = logging.getLogger("gpi") old_setLevel = gpi_logger.setLevel @wraps(old_setLevel) def setLevel(level: Union[int, str]) -> None: old_setLevel(level) simulator.set_gpi_log_level(gpi_logger.getEffectiveLevel()) gpi_logger.setLevel = setLevel # type: ignore[method-assign] # Initialize PyGPI logging simulator.initialize_logger(_log_from_c, logging.getLogger) # Set "cocotb" and "gpi" logger based on environment variables def set_level(logger_name: str, envvar: str) -> None: log_level = os.environ.get(envvar) if log_level is None: return log_level = log_level.upper() logger = logging.getLogger(logger_name) try: logger.setLevel(log_level) except ValueError: valid_levels = ", ".join( ("CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE", "NOTSET") ) raise ValueError( f"Invalid log level {log_level!r} passed through the " f"{envvar} environment variable. Valid log " f"levels: {valid_levels}" ) from None set_level("gpi", "GPI_LOG_LEVEL") set_level("cocotb", "COCOTB_LOG_LEVEL") def _configure(_: object) -> None: """Configure basic logging.""" reduced_log_fmt = True try: reduced_log_fmt = bool(int(os.environ.get("COCOTB_REDUCED_LOG_FMT", "1"))) except ValueError: pass prefix_format = os.environ.get("COCOTB_LOG_PREFIX", None) default_config(reduced_log_fmt=reduced_log_fmt, prefix_format=prefix_format) @deprecated('Use `logging.getLogger(f"{name}.0x{ident:x}")` instead') def SimLog(name: str, ident: Union[int, None] = None) -> logging.Logger: """Like :func:`logging.getLogger`, but append a numeric identifier to the name. Args: name: Logger name. ident: Unique integer identifier. Returns: The Logger named ``{name}.0x{ident:x}``. .. deprecated:: 2.0 Use ``logging.getLogger(f"{name}.0x{ident:x}")`` instead. """ if ident is not None: name = f"{name}.0x{ident:x}" return logging.getLogger(name) class SimTimeContextFilter(logging.Filter): """ A filter to inject simulator times into the log records. This uses the approach described in the :ref:`Python logging cookbook ` which adds the :attr:`~logging.LogRecord.created_sim_time` attribute. .. versionadded:: 1.4 """ def filter(self, record: logging.LogRecord) -> bool: try: record.created_sim_time = get_sim_time() except RecursionError: # get_sim_time may try to log - if that happens, we can't # attach a simulator time to this message. record.created_sim_time = None return True class SimLogFormatter(logging.Formatter): """Log formatter to provide consistent log message handling. This will only add simulator timestamps if the handler object this formatter is attached to has a :class:`SimTimeContextFilter` filter attached, which cocotb ensures by default. See :func:`.default_config` for a description of the arguments. """ loglevel2colour = { logging.TRACE: "", # type: ignore[attr-defined] # type checkers don't like adding module attributes after the fact logging.DEBUG: "", logging.INFO: "", logging.WARNING: ANSI.YELLOW_FG, logging.ERROR: ANSI.RED_FG, logging.CRITICAL: ANSI.RED_BG + ANSI.BLACK_FG, } prefix_func_globals = { "time": time, "simtime": cocotb.simtime, "ANSI": ANSI, } def __init__( self, *, reduced_log_fmt: bool = True, strip_ansi: Union[bool, None] = None, prefix_format: Optional[str] = None, ) -> None: self._reduced_log_fmt = reduced_log_fmt self._strip_ansi = strip_ansi self._prefix_func = ( eval( f"lambda record: f'''{prefix_format}'''", type(self).prefix_func_globals, ) if prefix_format is not None else None ) self._ansi_escape_pattern = re.compile( r""" \x1B (?: # either 7-bit C1, two bytes, ESC Fe (omitting CSI) [@-Z\\-_] | # or 7-bit CSI (ESC [) + control codes \[ [0-?]* # Parameter bytes [ -/]* # Intermediate bytes [@-~] # Final byte ) """, re.VERBOSE, ) def strip_ansi(self) -> bool: return strip_ansi if self._strip_ansi is None else self._strip_ansi # Justify and truncate @staticmethod def ljust(string: str, chars: int) -> str: if len(string) > chars: return ".." + string[(chars - 2) * -1 :] return string.ljust(chars) @staticmethod def rjust(string: str, chars: int) -> str: if len(string) > chars: return ".." + string[(chars - 2) * -1 :] return string.rjust(chars) def formatPrefix(self, record: logging.LogRecord) -> Tuple[str, int]: sim_time = getattr(record, "created_sim_time", None) if sim_time is None: sim_time_str = " -.--ns" else: time_ns = get_time_from_sim_steps(sim_time, "ns") sim_time_str = f"{time_ns:6.2f}ns" if self.strip_ansi(): highlight_start = "" highlight_end = "" else: highlight_start = self.loglevel2colour.get(record.levelno, "") highlight_end = ANSI.DEFAULT if self._prefix_func is not None: prefix = self._prefix_func(record) stripped_prefix = self._ansi_escape_pattern.sub("", prefix) prefix_len = len(stripped_prefix) return prefix, prefix_len else: prefix = f"{sim_time_str:>11} {highlight_start}{record.levelname:<8}{highlight_end} {self.ljust(record.name, 34)} " if not self._reduced_log_fmt: prefix = f"{prefix}{self.rjust(record.filename, 20)}:{record.lineno:<4} in {self.ljust(str(record.funcName), 31)} " prefix_len = len(prefix) - len(highlight_start) - len(highlight_end) return prefix, prefix_len def formatMessage(self, record: logging.LogRecord) -> str: msg = record.getMessage() if self.strip_ansi(): highlight_start = "" highlight_end = "" msg = self._ansi_escape_pattern.sub("", msg) else: highlight_start = self.loglevel2colour.get(record.levelno, "") highlight_end = ANSI.DEFAULT msg = f"{highlight_start}{msg}{highlight_end}" return msg def formatExcInfo(self, record: logging.LogRecord) -> str: msg = "" # these lines are copied and updated from the built-in logger if record.exc_info: # Cache the traceback text to avoid converting it multiple times # (it's constant anyway) if not record.exc_text: record.exc_text = self.formatException(record.exc_info) if record.exc_text: msg += record.exc_text if record.stack_info: if not msg.endswith("\n"): msg += "\n" msg += self.formatStack(record.stack_info) return msg def format(self, record: logging.LogRecord) -> str: prefix, prefix_len = self.formatPrefix(record) msg = self.formatMessage(record) exc_info = self.formatExcInfo(record) lines = msg.splitlines() lines.extend(exc_info.splitlines()) # add prefix to first line of message lines[0] = prefix + lines[0] # add padding to each line of message pad = "\n" + " " * prefix_len return pad.join(lines) class SimColourLogFormatter(SimLogFormatter): """Log formatter similar to :class:`SimLogFormatter`, but with colored output by default. .. deprecated:: 2.0 Use :class:`!SimLogFormatter` with ``strip_ansi=False`` instead. """ def __init__( self, *, reduced_log_fmt: bool = True, strip_ansi: Union[bool, None] = False, prefix_format: Optional[str] = None, ) -> None: warnings.warn( "SimColourLogFormatter is deprecated and will be removed in a future release. " "Use SimLogFormatter with `strip_ansi=False` instead.", DeprecationWarning, stacklevel=2, ) super().__init__( reduced_log_fmt=reduced_log_fmt, strip_ansi=strip_ansi, prefix_format=prefix_format, ) def _log_from_c( logger: logging.Logger, level: int, filename: str, lineno: int, msg: str, function_name: str, ) -> None: """ This is for use from the C world, and allows us to insert C stack information. """ if logger.isEnabledFor(level): record = logger.makeRecord( logger.name, level, filename, lineno, msg, (), None, function_name ) logger.handle(record) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/py.typed0000644000175100017510000000000015106067236016164 0ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/queue.py0000644000175100017510000001554415106067236016206 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import asyncio.queues import collections import heapq from abc import abstractmethod from typing import TYPE_CHECKING, Deque, Generic, List, Tuple, TypeVar import cocotb from cocotb._utils import pointer_str from cocotb.task import Task from cocotb.triggers import Event if TYPE_CHECKING: from typing import Protocol, Self class SupportsRichComparison(Protocol): def __eq__(self, other: object) -> bool: ... def __lt__(self, other: Self) -> bool: ... def __le__(self, other: Self) -> bool: ... def __gt__(self, other: Self) -> bool: ... def __ge__(self, other: Self) -> bool: ... __all__ = ( "AbstractQueue", "LifoQueue", "PriorityQueue", "Queue", "QueueEmpty", "QueueFull", ) class QueueFull(asyncio.queues.QueueFull): """Raised when the :meth:`Queue.put_nowait()` method is called on a full :class:`Queue`.""" class QueueEmpty(asyncio.queues.QueueEmpty): """Raised when the :meth:`Queue.get_nowait()` method is called on an empty :class:`Queue`.""" T = TypeVar("T") class AbstractQueue(Generic[T]): """A queue, useful for coordinating producer and consumer coroutines. If *maxsize* is less than or equal to 0, the queue size is infinite. If it is an integer greater than 0, then :meth:`put` will block when the queue reaches *maxsize*, until an item is removed by :meth:`get`. """ def __init__(self, maxsize: int = 0) -> None: self._maxsize: int = maxsize self._getters: Deque[Tuple[Event, Task[object]]] = collections.deque() self._putters: Deque[Tuple[Event, Task[object]]] = collections.deque() @abstractmethod def _get(self) -> T: """Remove and return the next element from the queue.""" @abstractmethod def _put(self, item: T) -> None: """Place a new element on the queue.""" @abstractmethod def _size(self) -> int: """Return the number of elements in the queue.""" @abstractmethod def _repr(self) -> str: """Return a string representation of the state of the queue.""" def _wakeup_next(self, waiters: Deque[Tuple[Event, Task[object]]]) -> None: while waiters: event, task = waiters.popleft() if not task.done(): event.set() break def __repr__(self) -> str: return f"<{type(self).__name__} {self._format()} at {pointer_str(self)}>" def __str__(self) -> str: return f"<{type(self).__name__} {self._format()}>" def _format(self) -> str: result = f"maxsize={self._maxsize!r}" if getattr(self, "_queue", None): result += f" _queue={self._repr()}" if self._getters: result += f" _getters[{len(self._getters)}]" if self._putters: result += f" _putters[{len(self._putters)}]" return result def qsize(self) -> int: """Number of items in the queue.""" return self._size() @property def maxsize(self) -> int: """Number of items allowed in the queue.""" return self._maxsize def empty(self) -> bool: """Return ``True`` if the queue is empty, ``False`` otherwise.""" return self._size() == 0 def full(self) -> bool: """Return ``True`` if there are :meth:`maxsize` items in the queue. .. note:: If the Queue was initialized with ``maxsize=0`` (the default), then :meth:`full` is never ``True``. """ if self._maxsize <= 0: return False else: return self.qsize() >= self._maxsize async def put(self, item: T) -> None: """Put an *item* into the queue. If the queue is full, wait until a free slot is available before adding the item. """ while self.full(): event = Event() self._putters.append((event, cocotb.task.current_task())) await event.wait() self.put_nowait(item) def put_nowait(self, item: T) -> None: """Put an *item* into the queue without blocking. If no free slot is immediately available, raise :exc:`~cocotb.queue.QueueFull`. """ if self.full(): raise QueueFull() self._put(item) self._wakeup_next(self._getters) async def get(self) -> T: """Remove and return an item from the queue. If the queue is empty, wait until an item is available. """ while self.empty(): event = Event() self._getters.append((event, cocotb.task.current_task())) await event.wait() return self.get_nowait() def get_nowait(self) -> T: """Remove and return an item from the queue. Return an item if one is immediately available, else raise :exc:`~cocotb.queue.QueueEmpty`. """ if self.empty(): raise QueueEmpty() item = self._get() self._wakeup_next(self._putters) return item class Queue(AbstractQueue[T]): """A subclass of :class:`AbstractQueue`; retrieves oldest entries first (FIFO).""" def __init__(self, maxsize: int = 0) -> None: super().__init__(maxsize) self._queue: Deque[T] = collections.deque() def _put(self, item: T) -> None: self._queue.append(item) def _get(self) -> T: return self._queue.popleft() def _size(self) -> int: return len(self._queue) def _repr(self) -> str: return repr(self._queue) SupportsRichComparisonT = TypeVar( "SupportsRichComparisonT", bound="SupportsRichComparison" ) class PriorityQueue(AbstractQueue[SupportsRichComparisonT]): r"""A subclass of :class:`AbstractQueue`; retrieves entries in priority order (smallest item first). Entries are typically tuples of the form ``(priority number, data)``. """ def __init__(self, maxsize: int = 0) -> None: super().__init__(maxsize) self._queue: List[SupportsRichComparisonT] = [] def _put(self, item: SupportsRichComparisonT) -> None: heapq.heappush(self._queue, item) def _get(self) -> SupportsRichComparisonT: return heapq.heappop(self._queue) def _size(self) -> int: return len(self._queue) def _repr(self) -> str: return repr(self._queue) class LifoQueue(AbstractQueue[T]): """A subclass of :class:`AbstractQueue`; retrieves most recently added entries first (LIFO).""" def __init__(self, maxsize: int = 0) -> None: super().__init__(maxsize) self._queue: Deque[T] = collections.deque() def _put(self, item: T) -> None: self._queue.append(item) def _get(self) -> T: return self._queue.pop() def _size(self) -> int: return len(self._queue) def _repr(self) -> str: return repr(self._queue) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/regression.py0000644000175100017510000007101615106067236017236 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013, 2018 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """All things relating to regression capabilities.""" import functools import hashlib import inspect import logging import os import random import re import time import warnings from enum import auto from importlib import import_module from typing import TYPE_CHECKING, Any, Callable, Coroutine, List, Union import cocotb import cocotb._gpi_triggers import cocotb.handle from cocotb import logging as cocotb_logging from cocotb import simulator from cocotb._decorators import Parameterized, Test from cocotb._extended_awaitables import with_timeout from cocotb._gpi_triggers import GPITrigger, Timer from cocotb._outcomes import Error, Outcome from cocotb._test import RunningTest from cocotb._test_factory import TestFactory from cocotb._test_functions import Failed from cocotb._utils import ( DocEnum, remove_traceback_frames, safe_divide, ) from cocotb._xunit_reporter import XUnitReporter, bin_xml_escape from cocotb.logging import ANSI from cocotb.simtime import get_sim_time from cocotb.task import Task if TYPE_CHECKING: from cocotb._base_triggers import Trigger __all__ = ( "Parameterized", "RegressionManager", "RegressionMode", "SimFailure", "Test", "TestFactory", ) # Set __module__ on re-exports Parameterized.__module__ = __name__ Test.__module__ = __name__ TestFactory.__module__ = __name__ class SimFailure(BaseException): """A Test failure due to simulator failure. .. caution:: Not to be raised or caught within a test. Only used for marking expected failure with ``expect_error`` in :func:`cocotb.test`. """ _logger = logging.getLogger(__name__) def _format_doc(docstring: Union[str, None]) -> str: if docstring is None: return "" else: brief = docstring.split("\n")[0] return f"\n {brief}" class RegressionMode(DocEnum): """The mode of the :class:`RegressionManager`.""" REGRESSION = ( auto(), """Tests are run if included. Skipped tests are skipped, expected failures and errors are respected.""", ) TESTCASE = ( auto(), """Like :attr:`REGRESSION`, but skipped tests are *not* skipped if included.""", ) class _TestResults: # TODO Replace with dataclass in Python 3.7+ def __init__( self, test_fullname: str, passed: Union[None, bool], wall_time_s: float, sim_time_ns: float, ) -> None: self.test_fullname = test_fullname self.passed = passed self.wall_time_s = wall_time_s self.sim_time_ns = sim_time_ns @property def ratio(self) -> float: return safe_divide(self.sim_time_ns, self.wall_time_s) class RegressionManager: """Object which manages tests. This object uses the builder pattern to build up a regression. Tests are added using :meth:`register_test` or :meth:`discover_tests`. Inclusion filters for tests can be added using :meth:`add_filters`. The "mode" of the regression can be controlled using :meth:`set_mode`. These methods can be called in any order any number of times before :meth:`start_regression` is called, and should not be called again after that. Once all the tests, filters, and regression behavior configuration is done, the user starts the regression with :meth:`start_regression`. This method must be called exactly once. Until the regression is started, :attr:`total_tests`, :attr:`count`, :attr:`passed`, :attr:`skipped`, and :attr:`failures` hold placeholder values. """ COLOR_TEST = ANSI.BLUE_FG COLOR_PASSED = ANSI.GREEN_FG COLOR_SKIPPED = ANSI.YELLOW_FG COLOR_FAILED = ANSI.RED_FG _timer1 = Timer(1) def __init__(self) -> None: self._test: Test self._running_test: RunningTest self.log = _logger self._regression_start_time: float self._test_results: List[_TestResults] = [] self.total_tests = 0 """Total number of tests that will be run or skipped.""" self.count = 0 """The current test count.""" self.passed = 0 """The current number of passed tests.""" self.skipped = 0 """The current number of skipped tests.""" self.failures = 0 """The current number of failed tests.""" self._tearing_down = False self._test_queue: List[Test] = [] self._filters: List[re.Pattern[str]] = [] self._mode = RegressionMode.REGRESSION self._included: List[bool] self._sim_failure: Union[Error[None], None] = None self._regression_seed = cocotb.RANDOM_SEED self._random_state: Any # Setup XUnit ################### results_filename = os.getenv("COCOTB_RESULTS_FILE", "results.xml") suite_name = os.getenv("COCOTB_RESULT_TESTSUITE", "all") package_name = os.getenv("COCOTB_RESULT_TESTPACKAGE", "all") self.xunit = XUnitReporter(filename=results_filename) self.xunit.add_testsuite(name=suite_name, package=package_name) self.xunit.add_property(name="random_seed", value=str(cocotb.RANDOM_SEED)) def discover_tests(self, *modules: str) -> None: """Discover tests in files automatically. Should be called before :meth:`start_regression` is called. Args: modules: Each argument given is the name of a module where tests are found. """ for module_name in modules: mod = import_module(module_name) found_test: bool = False for obj_name, obj in vars(mod).items(): if isinstance(obj, Test): found_test = True self.register_test(obj) elif isinstance(obj, Parameterized): found_test = True generated_tests: bool = False for test in obj.generate_tests(): generated_tests = True self.register_test(test) if not generated_tests: warnings.warn( f"Parametrize object generated no tests: {module_name}.{obj_name}", stacklevel=2, ) if not found_test: warnings.warn( f"No tests were discovered in module: {module_name}", stacklevel=2 ) # error if no tests were discovered if not self._test_queue: modules_str = ", ".join(repr(m) for m in modules) raise RuntimeError(f"No tests were discovered in any module: {modules_str}") def add_filters(self, *filters: str) -> None: """Add regular expressions to filter-in registered tests. Only those tests which match at least one of the given filters are included; the rest are excluded. Should be called before :meth:`start_regression` is called. Args: filters: Each argument given is a regex pattern for test names. A match *includes* the test. """ for filter in filters: compiled_filter = re.compile(filter) self._filters.append(compiled_filter) def set_mode(self, mode: RegressionMode) -> None: """Set the regression mode. See :class:`RegressionMode` for more details on how each mode affects :class:`RegressionManager` behavior. Should be called before :meth:`start_regression` is called. Args: mode: The regression mode to set. """ self._mode = mode def register_test(self, test: Test) -> None: """Register a test with the :class:`RegressionManager`. Should be called before :meth:`start_regression` is called. Args: test: The test object to register. """ self.log.debug("Registered test %r", test.fullname) self._test_queue.append(test) @classmethod def setup_pytest_assertion_rewriting(cls) -> None: """Configure pytest to rewrite assertions for better failure messages. Must be called before all modules containing tests are imported. """ try: import pytest # noqa: PLC0415 except ImportError: _logger.info( "pytest not found, install it to enable better AssertionError messages" ) return try: # Install the assertion rewriting hook, which must be done before we # import the test modules. from _pytest.assertion import install_importhook # noqa: PLC0415 from _pytest.config import Config # noqa: PLC0415 python_files = os.getenv("COCOTB_REWRITE_ASSERTION_FILES", "*.py").strip() if not python_files: # Even running the hook causes exceptions in some cases, so if the user # selects nothing, don't install the hook at all. return pytest_conf = Config.fromdictargs( {}, ["--capture=no", "-o", f"python_files={python_files}"] ) install_importhook(pytest_conf) except Exception: _logger.exception( "Configuring the assertion rewrite hook using pytest %s failed. " "Please file a bug report!", pytest.__version__, ) def start_regression(self) -> None: """Start the regression.""" # sort tests into stages self._test_queue.sort(key=lambda test: test.stage) # mark tests for running if self._filters: self._included = [False] * len(self._test_queue) for i, test in enumerate(self._test_queue): for filter in self._filters: if filter.search(test.fullname): self._included[i] = True else: self._included = [True] * len(self._test_queue) # compute counts self.count = 1 self.total_tests = sum(self._included) if self.total_tests == 0: self.log.warning( "No tests left after filtering with: %s", ", ".join(f.pattern for f in self._filters), ) # start write scheduler cocotb.handle._start_write_scheduler() # start test loop self._regression_start_time = time.time() self._first_test = True self._execute() def _execute(self) -> None: """Run the main regression loop. Used by :meth:`start_regression` and :meth:`_test_complete` to continue to the main test running loop, and by :meth:`_fail_regression` to shutdown the regression when a simulation failure occurs. """ while self._test_queue: self._test = self._test_queue.pop(0) included = self._included.pop(0) # if the test is not included, record and continue if not included: self._record_test_excluded() continue # if the test is skipped, record and continue if self._test.skip and self._mode != RegressionMode.TESTCASE: self._record_test_skipped() continue # if the test should be run, but the simulator has failed, record and continue if self._sim_failure is not None: self._score_test( self._sim_failure, 0, 0, ) continue # initialize the test, if it fails, record and continue try: self._running_test = self._init_test() except Exception: self._record_test_init_failed() continue self._log_test_start() if self._first_test: self._first_test = False return self._schedule_next_test() else: return self._timer1._prime(self._schedule_next_test) return self._tear_down() def _init_test(self) -> RunningTest: # wrap test function in timeout func: Callable[..., Coroutine[Trigger, None, None]] timeout = self._test.timeout_time if timeout is not None: f = self._test.func @functools.wraps(f) async def func(*args: object, **kwargs: object) -> None: await with_timeout(f(*args, **kwargs), timeout, self._test.timeout_unit) else: func = self._test.func main_task = Task(func(cocotb.top), name=f"Test {self._test.name}") return RunningTest(self._test_complete, main_task) def _schedule_next_test(self, trigger: Union[GPITrigger, None] = None) -> None: if trigger is not None: # TODO move to Trigger object cocotb._gpi_triggers._current_gpi_trigger = trigger trigger._cleanup() # seed random number generator based on test module, name, and COCOTB_RANDOM_SEED hasher = hashlib.sha1() hasher.update(self._test.fullname.encode()) test_seed = self._regression_seed + int(hasher.hexdigest(), 16) cocotb.RANDOM_SEED = test_seed self._random_state = random.getstate() random.seed(test_seed) self._start_sim_time = get_sim_time("ns") self._start_time = time.time() self._running_test.start() def _tear_down(self) -> None: """Called by :meth:`_execute` when there are no more tests to run to finalize the regression.""" # prevent re-entering the tear down procedure if not self._tearing_down: self._tearing_down = True else: return assert not self._test_queue # stop the write scheduler cocotb.handle._stop_write_scheduler() # Write out final log messages self._log_test_summary() # Generate output reports self.xunit.write() # TODO refactor initialization and finalization into their own module # to prevent circular imports requiring local imports from cocotb._init import _shutdown_testbench # noqa: PLC0415 _shutdown_testbench() # Setup simulator finalization simulator.stop_simulator() def _test_complete(self) -> None: """Callback given to the test to be called when the test finished.""" # compute wall time wall_time = time.time() - self._start_time sim_time_ns = get_sim_time("ns") - self._start_sim_time cocotb.RANDOM_SEED = self._regression_seed random.setstate(self._random_state) # Judge and record pass/fail. self._score_test( self._running_test.result(), wall_time, sim_time_ns, ) # Run next test. return self._execute() def _score_test( self, outcome: Outcome[None], wall_time_s: float, sim_time_ns: float, ) -> None: test = self._test # score test passed: bool msg: Union[str, None] exc: Union[BaseException, None] try: outcome.get() except BaseException as e: passed, msg = False, None exc = remove_traceback_frames(e, ["_score_test", "get"]) else: passed, msg, exc = True, None, None if passed: if test.expect_error: self._record_test_failed( wall_time_s=wall_time_s, sim_time_ns=sim_time_ns, result=exc, msg="passed but we expected an error", ) passed = False elif test.expect_fail: self._record_test_failed( wall_time_s=wall_time_s, sim_time_ns=sim_time_ns, result=exc, msg="passed but we expected a failure", ) passed = False else: self._record_test_passed( wall_time_s=wall_time_s, sim_time_ns=sim_time_ns, result=None, msg=msg, ) elif test.expect_fail: if isinstance(exc, (AssertionError, Failed)): self._record_test_passed( wall_time_s=wall_time_s, sim_time_ns=sim_time_ns, result=None, msg="failed as expected", ) else: self._record_test_failed( wall_time_s=wall_time_s, sim_time_ns=sim_time_ns, result=exc, msg="expected failure, but errored with unexpected type", ) passed = False elif test.expect_error: if isinstance(exc, test.expect_error): self._record_test_passed( wall_time_s=wall_time_s, sim_time_ns=sim_time_ns, result=None, msg="errored as expected", ) else: self._record_test_failed( wall_time_s=wall_time_s, sim_time_ns=sim_time_ns, result=exc, msg="errored with unexpected type", ) passed = False else: self._record_test_failed( wall_time_s=wall_time_s, sim_time_ns=sim_time_ns, result=exc, msg=msg, ) def _get_lineno(self, test: Test) -> int: try: return inspect.getsourcelines(test.func)[1] except OSError: return 1 def _log_test_start(self) -> None: """Called by :meth:`_execute` to log that a test is starting.""" hilight_start = "" if cocotb_logging.strip_ansi else self.COLOR_TEST hilight_end = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT self.log.info( "%srunning%s %s (%d/%d)%s", hilight_start, hilight_end, self._test.fullname, self.count, self.total_tests, _format_doc(self._test.doc), ) def _record_test_excluded(self) -> None: """Called by :meth:`_execute` when a test is excluded by filters.""" # write out xunit results lineno = self._get_lineno(self._test) self.xunit.add_testcase( name=self._test.name, classname=self._test.module, file=inspect.getfile(self._test.func), lineno=repr(lineno), time=repr(0), sim_time_ns=repr(0), ratio_time=repr(0), ) self.xunit.add_skipped() # do not log anything, nor save details for the summary def _record_test_skipped(self) -> None: """Called by :meth:`_execute` when a test is skipped.""" # log test results hilight_start = "" if cocotb_logging.strip_ansi else self.COLOR_SKIPPED hilight_end = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT self.log.info( "%sskipping%s %s (%d/%d)%s", hilight_start, hilight_end, self._test.fullname, self.count, self.total_tests, _format_doc(self._test.doc), ) # write out xunit results lineno = self._get_lineno(self._test) self.xunit.add_testcase( name=self._test.name, classname=self._test.module, file=inspect.getfile(self._test.func), lineno=repr(lineno), time=repr(0), sim_time_ns=repr(0), ratio_time=repr(0), ) self.xunit.add_skipped() # save details for summary self._test_results.append( _TestResults( test_fullname=self._test.fullname, passed=None, sim_time_ns=0, wall_time_s=0, ) ) # update running passed/failed/skipped counts self.skipped += 1 self.count += 1 def _record_test_init_failed(self) -> None: """Called by :meth:`_execute` when a test initialization fails.""" # log test results hilight_start = "" if cocotb_logging.strip_ansi else self.COLOR_FAILED hilight_end = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT self.log.exception( "%sFailed to initialize%s %s! (%d/%d)%s", hilight_start, hilight_end, self._test.fullname, self.count, self.total_tests, _format_doc(self._test.doc), ) # write out xunit results lineno = self._get_lineno(self._test) self.xunit.add_testcase( name=self._test.name, classname=self._test.module, file=inspect.getfile(self._test.func), lineno=repr(lineno), time=repr(0), sim_time_ns=repr(0), ratio_time=repr(0), ) self.xunit.add_failure(msg="Test initialization failed") # save details for summary self._test_results.append( _TestResults( test_fullname=self._test.fullname, passed=False, sim_time_ns=0, wall_time_s=0, ) ) # update running passed/failed/skipped counts self.failures += 1 self.count += 1 def _record_test_passed( self, wall_time_s: float, sim_time_ns: float, result: Union[Exception, None], msg: Union[str, None], ) -> None: start_hilight = "" if cocotb_logging.strip_ansi else self.COLOR_PASSED stop_hilight = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT if msg is None: rest = "" else: rest = f": {msg}" if result is None: result_was = "" else: result_was = f" (result was {type(result).__qualname__})" self.log.info( "%s %spassed%s%s%s", self._test.fullname, start_hilight, stop_hilight, rest, result_was, ) # write out xunit results ratio_time = safe_divide(sim_time_ns, wall_time_s) lineno = self._get_lineno(self._test) self.xunit.add_testcase( name=self._test.name, classname=self._test.module, file=inspect.getfile(self._test.func), lineno=repr(lineno), time=repr(wall_time_s), sim_time_ns=repr(sim_time_ns), ratio_time=repr(ratio_time), ) # update running passed/failed/skipped counts self.passed += 1 self.count += 1 # save details for summary self._test_results.append( _TestResults( test_fullname=self._test.fullname, passed=True, sim_time_ns=sim_time_ns, wall_time_s=wall_time_s, ) ) def _record_test_failed( self, wall_time_s: float, sim_time_ns: float, result: Union[BaseException, None], msg: Union[str, None], ) -> None: start_hilight = "" if cocotb_logging.strip_ansi else self.COLOR_FAILED stop_hilight = "" if cocotb_logging.strip_ansi else ANSI.DEFAULT if msg is None: rest = "" else: rest = f": {msg}" self.log.warning( "%s%s %sfailed%s%s", stop_hilight, self._test.fullname, start_hilight, stop_hilight, rest, ) # write out xunit results ratio_time = safe_divide(sim_time_ns, wall_time_s) lineno = self._get_lineno(self._test) self.xunit.add_testcase( name=self._test.name, classname=self._test.module, file=inspect.getfile(self._test.func), lineno=repr(lineno), time=repr(wall_time_s), sim_time_ns=repr(sim_time_ns), ratio_time=repr(ratio_time), ) self.xunit.add_failure( error_type=type(result).__name__, error_msg=bin_xml_escape(result) ) # update running passed/failed/skipped counts self.failures += 1 self.count += 1 # save details for summary self._test_results.append( _TestResults( test_fullname=self._test.fullname, passed=False, sim_time_ns=sim_time_ns, wall_time_s=wall_time_s, ) ) def _log_test_summary(self) -> None: """Called by :meth:`_tear_down` to log the test summary.""" real_time = time.time() - self._regression_start_time sim_time_ns = get_sim_time("ns") ratio_time = safe_divide(sim_time_ns, real_time) if len(self._test_results) == 0: return TEST_FIELD = "TEST" RESULT_FIELD = "STATUS" SIM_FIELD = "SIM TIME (ns)" REAL_FIELD = "REAL TIME (s)" RATIO_FIELD = "RATIO (ns/s)" TOTAL_NAME = f"TESTS={self.total_tests} PASS={self.passed} FAIL={self.failures} SKIP={self.skipped}" TEST_FIELD_LEN = max( len(TEST_FIELD), len(TOTAL_NAME), len(max([x.test_fullname for x in self._test_results], key=len)), ) RESULT_FIELD_LEN = len(RESULT_FIELD) SIM_FIELD_LEN = len(SIM_FIELD) REAL_FIELD_LEN = len(REAL_FIELD) RATIO_FIELD_LEN = len(RATIO_FIELD) header_dict = { "a": TEST_FIELD, "b": RESULT_FIELD, "c": SIM_FIELD, "d": REAL_FIELD, "e": RATIO_FIELD, "a_len": TEST_FIELD_LEN, "b_len": RESULT_FIELD_LEN, "c_len": SIM_FIELD_LEN, "d_len": REAL_FIELD_LEN, "e_len": RATIO_FIELD_LEN, } LINE_LEN = ( 3 + TEST_FIELD_LEN + 2 + RESULT_FIELD_LEN + 2 + SIM_FIELD_LEN + 2 + REAL_FIELD_LEN + 2 + RATIO_FIELD_LEN + 3 ) LINE_SEP = "*" * LINE_LEN + "\n" summary = "" summary += LINE_SEP summary += "** {a:<{a_len}} {b:^{b_len}} {c:>{c_len}} {d:>{d_len}} {e:>{e_len}} **\n".format( **header_dict ) summary += LINE_SEP test_line = "** {a:<{a_len}} {start}{b:^{b_len}}{end} {c:>{c_len}.2f} {d:>{d_len}.2f} {e:>{e_len}} **\n" hilite: str lolite: str for result in self._test_results: if result.passed is None: ratio = "-.--" pass_fail_str = "SKIP" hilite = self.COLOR_SKIPPED lolite = ANSI.DEFAULT elif result.passed: ratio = format(result.ratio, "0.2f") pass_fail_str = "PASS" hilite = self.COLOR_PASSED lolite = ANSI.DEFAULT else: ratio = format(result.ratio, "0.2f") pass_fail_str = "FAIL" hilite = self.COLOR_FAILED lolite = ANSI.DEFAULT if cocotb_logging.strip_ansi: hilite = "" lolite = "" test_dict = { "a": result.test_fullname, "b": pass_fail_str, "c": result.sim_time_ns, "d": result.wall_time_s, "e": ratio, "a_len": TEST_FIELD_LEN, "b_len": RESULT_FIELD_LEN, "c_len": SIM_FIELD_LEN - 1, "d_len": REAL_FIELD_LEN - 1, "e_len": RATIO_FIELD_LEN - 1, "start": hilite, "end": lolite, } summary += test_line.format(**test_dict) summary += LINE_SEP summary += test_line.format( a=TOTAL_NAME, b="", c=sim_time_ns, d=real_time, e=format(ratio_time, "0.2f"), a_len=TEST_FIELD_LEN, b_len=RESULT_FIELD_LEN, c_len=SIM_FIELD_LEN - 1, d_len=REAL_FIELD_LEN - 1, e_len=RATIO_FIELD_LEN - 1, start="", end="", ) summary += LINE_SEP self.log.info(summary) def _fail_simulation(self, msg: str) -> None: self._sim_failure = Error(SimFailure(msg)) self._running_test.abort(self._sim_failure) cocotb._scheduler_inst._event_loop() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/result.py0000644000175100017510000000221515106067236016367 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import warnings def __getattr__(name: str) -> object: if name == "TestSuccess": warnings.warn( "`raise TestSuccess` is deprecated. Use `cocotb.pass_test()` instead.", DeprecationWarning, stacklevel=2, ) from cocotb._test_functions import TestSuccess # noqa: PLC0415 return TestSuccess elif name == "SimFailure": warnings.warn( "SimFailure was moved to `cocotb.regression`.", DeprecationWarning, stacklevel=2, ) from cocotb.regression import SimFailure # noqa: PLC0415 return SimFailure elif name == "SimTimeoutError": warnings.warn( "SimTimeoutError was moved from `cocotb.result` to `cocotb.triggers`.", DeprecationWarning, stacklevel=2, ) from cocotb.triggers import SimTimeoutError # noqa: PLC0415 return SimTimeoutError raise AttributeError(f"module {__name__!r} has no attribute {name!r}") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3327022 cocotb-2.0.1/src/cocotb/share/0000755000175100017510000000000015106070715015575 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3457024 cocotb-2.0.1/src/cocotb/share/def/0000755000175100017510000000000015106070715016333 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/def/.gitignore0000644000175100017510000000005415106067236020326 0ustar00runnerrunner# Generated import libraries on Windows *.a ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/def/README.md0000644000175100017510000000057015106067236017620 0ustar00runnerrunnerThis directory contains module-definition files (`.def`). On Windows these are used to generate import libraries (`.a`, but not regular static libraries), which means we can compile our libraries without having the simulator binaries available. They are not needed on other platforms. More details on `.def` files can be found at http://www.mingw.org/wiki/msvc_and_mingw_dlls ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/def/aldec.def0000644000175100017510000000164215106067236020072 0ustar00runnerrunnerLIBRARY "aldecpli.dll" EXPORTS vpi_chk_error vpi_compare_objects vpi_control vpi_flush vpi_fopen vpi_free_object vpi_get vpi_get_delays vpi_get_file vpi_get_str vpi_get_systf_info vpi_get_time vpi_get_userdata vpi_get_value vpi_get_vlog_info vpi_handle vpi_handle_by_index vpi_handle_by_name vpi_iterate vpi_mcd_close vpi_mcd_flush vpi_mcd_name vpi_mcd_open vpi_mcd_printf vpi_mcd_vprintf vpi_printf vpi_put_delays vpi_put_userdata vpi_put_value vpi_register_cb vpi_register_systf vpi_remove_cb vpi_scan vpi_sim_control vpi_sim_vcontrol vpi_vprintf vpip_count_drivers vpip_format_strength vpip_make_systf_system_defined vpip_mcd_rawwrite vpip_set_return_value vhpi_check_error vhpi_control vhpi_disable_cb vhpi_enable_cb vhpi_get vhpi_get_phys vhpi_get_str vhpi_get_time vhpi_get_value vhpi_handle vhpi_handle_by_index vhpi_handle_by_name vhpi_iterator vhpi_put_value vhpi_register_cb vhpi_release_handle vhpi_remove_cb vhpi_scan ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/def/ghdl.def0000644000175100017510000000122615106067236017736 0ustar00runnerrunnerLIBRARY "libghdlvpi.dll" EXPORTS vpi_compare_objects vpi_control vpi_flush vpi_fopen vpi_free_object vpi_get vpi_get_delays vpi_get_file vpi_get_str vpi_get_systf_info vpi_get_time vpi_get_userdata vpi_get_value vpi_get_vlog_info vpi_handle vpi_handle_by_index vpi_handle_by_name vpi_iterate vpi_mcd_close vpi_mcd_flush vpi_mcd_name vpi_mcd_printf vpi_mcd_vprintf vpi_printf vpi_put_delays vpi_put_userdata vpi_put_value vpi_register_cb vpi_register_systf vpi_remove_cb vpi_scan vpi_sim_control vpi_sim_vcontrol vpi_mcd_open vpi_vprintf vpip_count_drivers vpip_format_strength vpip_make_systf_system_defined vpip_mcd_rawwrite vpip_set_return_value vpi_chk_error ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/def/icarus.def0000644000175100017510000000121715106067236020306 0ustar00runnerrunnerLIBRARY "vvp.exe" EXPORTS vpi_compare_objects vpi_control vpi_flush vpi_fopen vpi_free_object vpi_get vpi_get_delays vpi_get_file vpi_get_str vpi_get_systf_info vpi_get_time vpi_get_userdata vpi_get_value vpi_get_vlog_info vpi_handle vpi_handle_by_index vpi_handle_by_name vpi_iterate vpi_mcd_close vpi_mcd_flush vpi_mcd_name vpi_mcd_printf vpi_mcd_vprintf vpi_printf vpi_put_delays vpi_put_userdata vpi_put_value vpi_register_cb vpi_register_systf vpi_remove_cb vpi_scan vpi_sim_control vpi_sim_vcontrol vpi_mcd_open vpi_vprintf vpip_count_drivers vpip_format_strength vpip_make_systf_system_defined vpip_mcd_rawwrite vpip_set_return_value vpi_chk_error ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/def/modelsim.def0000644000175100017510000000433015106067236020630 0ustar00runnerrunnerLIBRARY "mtipli.dll" EXPORTS vpi_chk_error vpi_compare_objects vpi_control vpi_flush vpi_fopen vpi_free_object vpi_get vpi_get_delays vpi_get_file vpi_get_str vpi_get_systf_info vpi_get_time vpi_get_userdata vpi_get_value vpi_get_vlog_info vpi_handle vpi_handle_by_index vpi_handle_by_name vpi_iterate vpi_mcd_close vpi_mcd_flush vpi_mcd_name vpi_mcd_open vpi_mcd_printf vpi_mcd_vprintf vpi_printf vpi_put_delays vpi_put_userdata vpi_put_value vpi_register_cb vpi_register_systf vpi_remove_cb vpi_scan vpi_sim_control vpi_sim_vcontrol vpi_vprintf vpip_count_drivers vpip_format_strength vpip_make_systf_system_defined vpip_mcd_rawwrite vpip_set_return_value acc_fetch_fullname acc_fetch_fulltype acc_fetch_name acc_fetch_type acc_fetch_type_str mti_AddLoadDoneCB mti_AddQuitCB mti_Break mti_CreateProcess mti_CreateProcessWithPriority mti_Delta mti_Desensitize mti_FindRegion mti_FindSignal mti_FindVar mti_FirstLowerRegion mti_FirstLowerRegion mti_FirstSignal mti_FirstVarByRegion mti_ForceSignal mti_GetArrayElementType mti_GetArraySignalValue mti_GetArrayVarValue mti_GetEnumValues mti_GetNumRecordElements mti_GetPrimaryName mti_GetProductVersion mti_GetRegionFullName mti_GetRegionName mti_GetRegionSourceName mti_GetResolutionLimit mti_GetSignalName mti_GetSignalNameIndirect mti_GetSignalSubelements mti_GetSignalType mti_GetSignalValue mti_GetSignalValueIndirect mti_GetTopRegion mti_GetTypeKind mti_GetVarKind mti_GetVarName mti_GetVarSubelements mti_GetVarType mti_GetVarValue mti_GetVarValueIndirect mti_NextRegion mti_NextSignal mti_NextVar mti_Now mti_NowUpper mti_Quit mti_ReleaseSignal mti_RemoveLoadDoneCB mti_RemoveQuitCB mti_ScheduleWakeup mti_ScheduleWakeup64 mti_Sensitize mti_SetSignalValue mti_SetVarValue mti_TickDir mti_TickLeft mti_TickLength mti_TickRight mti_VsimFree mti_Interp mti_Cmd Tcl_GetStringResult Tcl_ResetResult Tcl_GetObjResult Tcl_ResetResult Tcl_ListObjGetElements Tcl_GetStringResult TclFreeObj Tcl_ResetResult Tcl_ResetResult Tcl_GetString TclFreeObj vhpi_check_error vhpi_control vhpi_disable_cb vhpi_enable_cb vhpi_get vhpi_get_phys vhpi_get_str vhpi_get_time vhpi_get_value vhpi_handle vhpi_handle_by_index vhpi_handle_by_name vhpi_iterator vhpi_put_value vhpi_register_cb vhpi_release_handle vhpi_remove_cb vhpi_scan ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/def/nvcvhpi.def0000644000175100017510000000041115106067236020470 0ustar00runnerrunnerLIBRARY "nvc.exe" EXPORTS vhpi_handle vhpi_register_cb vhpi_iterator vhpi_get_value vhpi_get_str vhpi_scan vhpi_put_value vhpi_remove_cb vhpi_check_error vhpi_release_handle vhpi_get vhpi_handle_by_name vhpi_handle_by_index vhpi_get_phys vhpi_get_time vhpi_control ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3467026 cocotb-2.0.1/src/cocotb/share/include/0000755000175100017510000000000015106070715017220 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/include/cocotb_utils.h0000644000175100017510000000454715106067236022100 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef COCOTB_UTILS_H_ #define COCOTB_UTILS_H_ #include #ifdef COCOTBUTILS_EXPORTS #define COCOTBUTILS_EXPORT COCOTB_EXPORT #else #define COCOTBUTILS_EXPORT COCOTB_IMPORT #endif #include #define xstr(a) str(a) #define str(a) #a extern "C" COCOTBUTILS_EXPORT void *utils_dyn_open(const char *lib_name); extern "C" COCOTBUTILS_EXPORT void *utils_dyn_sym(void *handle, const char *sym_name); extern "C" COCOTBUTILS_EXPORT int is_python_context; // to_python and to_simulator are implemented as macros instead of functions so // that the logs reference the user's lineno and filename #define to_python() \ do { \ if (is_python_context) { \ LOG_ERROR("FATAL: We are calling up again"); \ exit(1); \ } \ ++is_python_context; \ LOG_TRACE("Returning to Python"); \ } while (0) #define to_simulator() \ do { \ if (!is_python_context) { \ LOG_ERROR("FATAL: We have returned twice from Python"); \ exit(1); \ } \ --is_python_context; \ LOG_TRACE("Returning to simulator"); \ } while (0) template class Deferable { public: constexpr Deferable(F f) : f_(f) {}; ~Deferable() { f_(); } private: F f_; }; template constexpr Deferable make_deferable(F f) { return Deferable(f); } #define DEFER1(a, b) a##b #define DEFER0(a, b) DEFER1(a, b) #define DEFER(statement) \ auto DEFER0(_defer, __COUNTER__) = make_deferable([&]() { statement; }); #endif /* COCOTB_UTILS_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/include/embed.h0000644000175100017510000000153515106067236020455 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef COCOTB_EMBED_H_ #define COCOTB_EMBED_H_ #include #ifdef COCOTB_EMBED_EXPORTS #define COCOTB_EMBED_EXPORT COCOTB_EXPORT #else #define COCOTB_EMBED_EXPORT COCOTB_IMPORT #endif #include #ifdef __cplusplus extern "C" { #endif extern COCOTB_EMBED_EXPORT void embed_init_python(void); extern COCOTB_EMBED_EXPORT void embed_sim_cleanup(void); extern COCOTB_EMBED_EXPORT int embed_sim_init(int argc, char const *const *argv); extern COCOTB_EMBED_EXPORT void embed_sim_event(const char *msg); #ifdef __cplusplus } #endif #endif /* COCOTB_EMBED_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/include/exports.h0000644000175100017510000000122115106067236021075 0ustar00runnerrunner// Copyright cocotb contributors // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef COCOTB_EXPORTS_H_ #define COCOTB_EXPORTS_H_ // Make cocotb work correctly when the default visibility is changed to hidden // Changing the default visibility to hidden has the advantage of significantly // reducing the code size and load times, as well as letting the optimizer // produce better code. #if _WIN32 #define COCOTB_EXPORT __declspec(dllexport) #define COCOTB_IMPORT __declspec(dllimport) #else #define COCOTB_EXPORT __attribute__((visibility("default"))) #define COCOTB_IMPORT #endif #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/include/gpi.h0000644000175100017510000003541515106067236020164 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef COCOTB_GPI_H_ #define COCOTB_GPI_H_ /** @file gpi.h Generic Procedural Interface ============================ This header file defines the GPI to interface with any simulator that supports VPI, VHPI, or FLI. Implementations need to implement the underlying functions in `gpi_priv.h`. The functions are essentially a limited subset of VPI/VHPI/FLI. Implementation-specific notes ----------------------------- By amazing coincidence, VPI and VHPI are strikingly similar which is obviously reflected by this header file. Unfortunately, this means that proprietary, non-standard, less featured language interfaces (for example Mentor FLI) may have to resort to some hackery. Because of the lack of ability to register a callback on event change using the FLI, we have to create a process with the signal on the sensitivity list to imitate a callback. */ #include #ifdef GPI_EXPORTS #define GPI_EXPORT COCOTB_EXPORT #else #define GPI_EXPORT COCOTB_IMPORT #endif #include #include #include /* * Declare the handle types. * * We want these handles to be opaque pointers, since their layout is not * exposed to C. We do this by using incomplete types. The assumption being * made here is that `sizeof(some_cpp_class*) == sizeof(some_c_struct*)`, which * is true on all reasonable platforms. */ #ifdef __cplusplus /* In C++, we use forward-declarations of the types in gpi_priv.h as our * incomplete types, as this avoids the need for any casting in GpiCommon.cpp. */ class GpiObjHdl; class GpiCbHdl; class GpiIterator; typedef GpiObjHdl *gpi_sim_hdl; typedef GpiCbHdl *gpi_cb_hdl; typedef GpiIterator *gpi_iterator_hdl; #else /* In C, we declare some incomplete struct types that we never complete. * The names of these are irrelevant, but for simplicity they match the C++ * names. */ struct GpiObjHdl; struct GpiCbHdl; struct GpiIterator; typedef struct GpiObjHdl *gpi_sim_hdl; typedef struct GpiCbHdl *gpi_cb_hdl; typedef struct GpiIterator *gpi_iterator_hdl; #endif #ifdef __cplusplus extern "C" { #endif /** Object discovery method when searching by name. */ typedef enum gpi_discovery_e { GPI_AUTO = 0, GPI_NATIVE = 1, } gpi_discovery; /** GPI simulation object types. */ // Note these are strikingly similar to the VPI types... typedef enum gpi_objtype_e { GPI_UNKNOWN = 0, GPI_MEMORY = 1, GPI_MODULE = 2, // GPI_NET = 3, // Deprecated // GPI_PARAMETER = 4, // Deprecated // GPI_REGISTER = 5, // Deprecated GPI_ARRAY = 6, GPI_ENUM = 7, GPI_STRUCTURE = 8, GPI_REAL = 9, GPI_INTEGER = 10, GPI_STRING = 11, GPI_GENARRAY = 12, GPI_PACKAGE = 13, GPI_PACKED_STRUCTURE = 14, GPI_LOGIC = 15, GPI_LOGIC_ARRAY = 16, } gpi_objtype; /** Types of child objects to search for when iterating. */ typedef enum gpi_iterator_sel_e { GPI_OBJECTS = 1, GPI_DRIVERS = 2, GPI_LOADS = 3, GPI_PACKAGE_SCOPES = 4, } gpi_iterator_sel; /** Action to use when setting object value. */ typedef enum gpi_set_action_e { GPI_DEPOSIT = 0, GPI_FORCE = 1, GPI_RELEASE = 2, GPI_NO_DELAY = 3, } gpi_set_action; /** Direction of range constraint of an object. */ typedef enum gpi_range_dir_e { GPI_RANGE_DOWN = -1, GPI_RANGE_NO_DIR = 0, GPI_RANGE_UP = 1, } gpi_range_dir; /** Type of value change to match when registering for callback. */ typedef enum gpi_edge_e { GPI_RISING, GPI_FALLING, GPI_VALUE_CHANGE, } gpi_edge; /** @defgroup SimIntf Simulator Control and Interrogation * These functions are for controlling and querying * simulator state and information. * @{ */ /** Check if there is a registered GPI implementation. * * Useful for checking if a simulator is running. * * @return `1` if there is a registered GPI implementation, `0` otherwise. */ GPI_EXPORT bool gpi_has_registered_impl(void); /** Stop the simulation after control returns to the GPI. */ GPI_EXPORT void gpi_sim_end(void); /** Get the simulation time as two 32-bit uints. * * The value is in default simulation time units, * which can be retrieved with @ref gpi_get_sim_precision. * * @param high Location to return high bits of current simulation time. * @param low Location to return low bits of current simulation time. */ GPI_EXPORT void gpi_get_sim_time(uint32_t *high, uint32_t *low); /** Get the simulation time precision. * * @param precision Location to return time precision. * The value is scientific notation in terms of seconds. * So a value of `-9` is nanosecond precision. */ GPI_EXPORT void gpi_get_sim_precision(int32_t *precision); /** Get the running simulator product information. * * @return The simulator product string. */ GPI_EXPORT const char *gpi_get_simulator_product(void); /** Get the running simulator version string. * * @return The simulator version string. */ GPI_EXPORT const char *gpi_get_simulator_version(void); /** @} */ // End of group SimIntf /** @defgroup ObjQuery Simulation Object Query * These functions are for getting handles to simulation objects. * @{ */ /** Get a handle to the root simulation object. * * @param name Name of the root object, or `NULL`. * @return Handle to simulation object or `NULL` if not found. */ GPI_EXPORT gpi_sim_hdl gpi_get_root_handle(const char *name); /** Get a handle to a child simulation object by its name. * * @param parent Parent object handle. * @param name Name of the child object. * This should not be a path, * but only the name of a direct child object. * @param discovery_method Object discovery method. * @return Handle to simulation object or `NULL` if not found. */ GPI_EXPORT gpi_sim_hdl gpi_get_handle_by_name(gpi_sim_hdl parent, const char *name, gpi_discovery discovery_method); /** Get a handle to a child simulation object by its index. * * @param parent Parent indexable object handle. * @param index Index of the child object. * @return Handle to simulation object or `NULL` if not found. */ GPI_EXPORT gpi_sim_hdl gpi_get_handle_by_index(gpi_sim_hdl parent, int32_t index); /** @} */ // End of group ObjQuery /** @defgroup ObjProps General Object Properties * These functions are for getting and setting properties of a simulation * object. * @{ */ /** @return The @ref gpi_objtype "type" of the simulation object. */ GPI_EXPORT gpi_objtype gpi_get_object_type(gpi_sim_hdl gpi_hdl); /** @return Definition name of the simulation object. */ GPI_EXPORT const char *gpi_get_definition_name(gpi_sim_hdl gpi_hdl); /** @return Definition file of the simulation object. */ GPI_EXPORT const char *gpi_get_definition_file(gpi_sim_hdl gpi_hdl); /** @return The number of objects in the collection of the handle. */ GPI_EXPORT int gpi_get_num_elems(gpi_sim_hdl gpi_sim_hdl); /** @return The left side of the range constraint. */ GPI_EXPORT int gpi_get_range_left(gpi_sim_hdl gpi_sim_hdl); /** @return The right side of the range constraint. */ GPI_EXPORT int gpi_get_range_right(gpi_sim_hdl gpi_sim_hdl); /** @return The direction of the range constraint: * `+1` for ascending, `-1` for descending, `0` for undefined. */ GPI_EXPORT gpi_range_dir gpi_get_range_dir(gpi_sim_hdl gpi_sim_hdl); /** Determine whether an object value is constant (parameters / generics etc). * * @return `1` if the object value is constant, `0` otherwise. */ GPI_EXPORT int gpi_is_constant(gpi_sim_hdl gpi_hdl); /** Determine whether an object is indexable. * * @return `1` if the object value is indexable, `0` otherwise. */ GPI_EXPORT int gpi_is_indexable(gpi_sim_hdl gpi_hdl); /** @} */ // End of group ObjProps /** @defgroup SigProps Signal Object Properties * These functions are for getting and setting properties of a signal object. * @{ */ // Getting properties /** Get signal object value as a binary string. * @param gpi_hdl Signal object handle. * @return Object value. */ GPI_EXPORT const char *gpi_get_signal_value_binstr(gpi_sim_hdl gpi_hdl); /** Get signal object value as a byte array. * @param gpi_hdl Signal object handle. * @return Object value. Null-terminated byte array. */ GPI_EXPORT const char *gpi_get_signal_value_str(gpi_sim_hdl gpi_hdl); /** Get signal object value as a real. * @param gpi_hdl Signal object handle. * @return Object value. */ GPI_EXPORT double gpi_get_signal_value_real(gpi_sim_hdl gpi_hdl); /** Get signal object value as a long. * @param gpi_hdl Signal object handle. * @return Object value. */ GPI_EXPORT long gpi_get_signal_value_long(gpi_sim_hdl gpi_hdl); /** Get signal object name. * @param gpi_hdl Signal object handle. * @return Object name. */ GPI_EXPORT const char *gpi_get_signal_name_str(gpi_sim_hdl gpi_hdl); /** Get signal object type as a string. * @param gpi_hdl Signal object handle. * @return Object type as a string. */ GPI_EXPORT const char *gpi_get_signal_type_str(gpi_sim_hdl gpi_hdl); // Setting properties /** Set signal object value with a real. * @param gpi_hdl Signal object handle. * @param value Object value. * @param action Action to use. */ GPI_EXPORT void gpi_set_signal_value_real(gpi_sim_hdl gpi_hdl, double value, gpi_set_action action); /** Set signal object value with an int. * @param gpi_hdl Signal object handle. * @param value Object value. * @param action Action to use. */ GPI_EXPORT void gpi_set_signal_value_int(gpi_sim_hdl gpi_hdl, int32_t value, gpi_set_action action); /** Set signal object value with a binary string. * @param gpi_hdl Signal object handle. * @param str Object value. Null-terminated string of binary characters * in [`1`, `0`, `x`, `z`]. * @param action Action to use. */ GPI_EXPORT void gpi_set_signal_value_binstr(gpi_sim_hdl gpi_hdl, const char *str, gpi_set_action action); /** Set signal object value with a byte array. * @param gpi_hdl Signal object handle. * @param str Object value. Null-terminated byte array. * @param action Action to use. */ GPI_EXPORT void gpi_set_signal_value_str(gpi_sim_hdl gpi_hdl, const char *str, gpi_set_action action); /** @} */ // End of group SigProps /** @defgroup HandleIteration Simulation Object Iteration * These functions are for iterating over simulation object handles * to discover child objects. * @{ */ /** Start iteration on a simulation object. * * Unlike `vpi_iterate()` the iterator handle may only be `NULL` if the `type` * is not supported. If no objects of the requested type are found, an empty * iterator is returned. * @param base Simulation object to iterate over. * @param type Iteration type. * @return An iterator handle which can then be used with @ref gpi_next. */ GPI_EXPORT gpi_iterator_hdl gpi_iterate(gpi_sim_hdl base, gpi_iterator_sel type); /** Get next object in iteration. * * @param iterator Iterator handle. * @return Object handle, or `NULL` when there are no more objects. */ GPI_EXPORT gpi_sim_hdl gpi_next(gpi_iterator_hdl iterator); /** @} */ // End of group HandleIteration /** @defgroup SimCallbacks Simulation Callbacks * These functions are for registering and controlling callbacks. * @{ */ /** Register a timed callback. * * @param gpi_function Callback function pointer. * @param gpi_cb_data Pointer to user data to be passed to callback function. * @param time Time delay in simulation time units. * @return Handle to callback object. */ GPI_EXPORT gpi_cb_hdl gpi_register_timed_callback(int (*gpi_function)(void *), void *gpi_cb_data, uint64_t time); /** Register a value change callback. * * @param gpi_function Callback function pointer. * @param gpi_cb_data Pointer to user data to be passed to callback function. * @param gpi_hdl Simulation object to monitor for value change. * @param edge Type of value change to monitor for. * @return Handle to callback object. */ GPI_EXPORT gpi_cb_hdl gpi_register_value_change_callback( int (*gpi_function)(void *), void *gpi_cb_data, gpi_sim_hdl gpi_hdl, gpi_edge edge); /** Register a readonly simulation phase callback. * * Callback will be called when simulation next enters the readonly phase. * @param gpi_function Callback function pointer. * @param gpi_cb_data Pointer to user data to be passed to callback function. * @return Handle to callback object. */ GPI_EXPORT gpi_cb_hdl gpi_register_readonly_callback(int (*gpi_function)(void *), void *gpi_cb_data); /** Register a next timestep simulation phase callback. * * Callback will be called when simulation next enters the next timestep. * @param gpi_function Callback function pointer. * @param gpi_cb_data Pointer to user data to be passed to callback function. * @return Handle to callback object. */ GPI_EXPORT gpi_cb_hdl gpi_register_nexttime_callback(int (*gpi_function)(void *), void *gpi_cb_data); /** Register a readwrite simulation phase callback. * * Callback will be called when simulation next enters the readwrite phase. * @param gpi_function Callback function pointer. * @param gpi_cb_data Pointer to user data to be passed to callback function. * @return Handle to callback object. */ GPI_EXPORT gpi_cb_hdl gpi_register_readwrite_callback(int (*gpi_function)(void *), void *gpi_cb_data); /** Remove callback. * * The callback will not fire after this function is called. * The argument is no longer valid if this function succeeds. * * @param cb_hdl The handle to the callback to remove. * @returns `0` on successful removal, `1` otherwise. */ GPI_EXPORT int gpi_remove_cb(gpi_cb_hdl cb_hdl); /** Retrieve user callback information from callback handle. * * This function cannot fail. * * @param cb_hdl The handle to the callback. * @param cb_func Where the user callback function should be placed. * @param cb_data Where the user callback function data should be placed. */ GPI_EXPORT void gpi_get_cb_info(gpi_cb_hdl cb_hdl, int (**cb_func)(void *), void **cb_data); /** @} */ // End of group SimCallbacks #ifdef __cplusplus } #endif #endif /* COCOTB_GPI_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/include/gpi_logging.h0000644000175100017510000003172515106067236021672 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef COCOTB_GPI_LOGGING_H_ #define COCOTB_GPI_LOGGING_H_ #include // va_list #include // strlen #include "exports.h" #ifdef GPILOG_EXPORTS #define GPILOG_EXPORT COCOTB_EXPORT #else #define GPILOG_EXPORT COCOTB_IMPORT #endif #ifdef __cplusplus extern "C" { #endif /** Named logging level * * The native logger only logs level names at these log level values. * They were specifically chosen to align with the default level values in the * Python logging module. Implementers of custom loggers should emit human * readable level names for these value, but may support other values. */ enum gpi_log_level { GPI_NOTSET = 0, ///< Lets the parent logger in the hierarchy decide the ///< effective log level. By default this behaves like ///< `INFO`. GPI_TRACE = 5, ///< Prints `TRACE` by default. Information about execution ///< of simulator callbacks and Python/simulator contexts. GPI_DEBUG = 10, ///< Prints `DEBUG` by default. Verbose information, useful ///< for debugging. GPI_INFO = 20, ///< Prints `INFO` by default. Information about major ///< events in the current program. GPI_WARNING = 30, ///< Prints `WARN` by default. Encountered a recoverable ///< bug, or information about surprising behavior. GPI_ERROR = 40, ///< Prints `ERROR` by default. An unrecoverable error GPI_CRITICAL = 50 ///< Prints `CRITICAL` by default. An unrecoverable ///< error, to be followed by immediate simulator ///< shutdown. }; #define LOG_EXPLICIT(logger, level, file, func, lineno, ...) \ gpi_log_(logger, level, file, func, lineno, __VA_ARGS__) #define LOG_(level, ...) \ gpi_log_("gpi", level, __FILE__, __func__, __LINE__, __VA_ARGS__) /** Logs a message at TRACE log level using the current log handler. Automatically populates arguments using information in the called context. */ #define LOG_TRACE(...) LOG_(GPI_TRACE, __VA_ARGS__) /** Logs a message at DEBUG log level using the current log handler. Automatically populates arguments using information in the called context. */ #define LOG_DEBUG(...) LOG_(GPI_DEBUG, __VA_ARGS__) /** Logs a message at INFO log level using the current log handler. Automatically populates arguments using information in the called context. */ #define LOG_INFO(...) LOG_(GPI_INFO, __VA_ARGS__) /** Logs a message at WARN log level using the current log handler. Automatically populates arguments using information in the called context. */ #define LOG_WARN(...) LOG_(GPI_WARNING, __VA_ARGS__) /** Logs a message at ERROR log level using the current log handler. Automatically populates arguments using information in the called context. */ #define LOG_ERROR(...) LOG_(GPI_ERROR, __VA_ARGS__) /** Logs a message at CRITICAL log level using the current log handler. Automatically populates arguments using information in the called context. */ #define LOG_CRITICAL(...) LOG_(GPI_CRITICAL, __VA_ARGS__) #define MAKE_LOG_NAME_(extra_name) \ (extra_name[0] == '\0' ? "gpi" : "gpi." extra_name) /** Type of a logger handler function. * @param userdata private implementation data registered with this function * @param name Name of the logger * @param level Level at which to log the message * @param pathname Name of the file where the call site is located * @param funcname Name of the function where the call site is located * @param lineno Line number of the call site * @param msg The message to log, uses C-sprintf-style format specifier * @param args Additional arguments; formatted and inserted in message * according to format specifier in msg argument */ typedef void (*gpi_log_handler_ftype)(void *userdata, const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, va_list args); /** Type of a logger filter function. * * Log filter functions test to see if a message would be emitted if logged at * the given log level. * * @param userdata Private implementation data registered with this function. * @param logger Name of the logger. * @param level Level at which to test if the logger would emit a message. * @return `true` if the *logger* is enabled at *level*. */ typedef bool (*gpi_log_filter_ftype)(void *userdata, const char *logger, int level); /** Type of a logger set level function. * * Log filter functions test to see if a message would be emitted if logged at * the given log level. * * @param userdata Private implementation data registered with this function. * @param logger Name of the logger. * @param level Level at which to test if the logger would emit a message. * @return `true` if the *logger* is enabled at *level*. */ typedef bool (*gpi_log_set_level_ftype)(void *userdata, const char *logger, int level); /** Log a message using the currently registered log handler. * * @param extra_name Name of the "gpi" child logger, "" for the root logger * @param level Level at which to log the message * @param pathname Name of the file where the call site is located * @param funcname Name of the function where the call site is located * @param lineno Line number of the call site * @param msg The message to log, uses C-sprintf-style format specifier * @param ... Additional arguments; formatted and inserted in message * according to format specifier in msg argument */ #define gpi_log(extra_name, level, pathname, funcname, lineno, ...) \ gpi_log_(MAKE_LOG_NAME_(extra_name), level, pathname, funcname, lineno, \ __VA_ARGS__) // Don't call this function directly unless the name is "gpi" or starts with // "gpi." GPILOG_EXPORT void gpi_log_(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, ...); /** Log a message using the currently registered log handler. * * @param extra_name Name of the "gpi" child logger, "" for the root logger * @param level Level at which to log the message * @param pathname Name of the file where the call site is located * @param funcname Name of the function where the call site is located * @param lineno Line number of the call site * @param msg The message to log, uses C-sprintf-style format specifier * @param args Additional arguments; formatted and inserted in message * according to format specifier in msg argument */ #define gpi_vlog(extra_name, level, pathname, funcname, lineno, msg, args) \ gpi_vlog_(MAKE_LOG_NAME_(extra_name), level, pathname, funcname, lineno, \ msg, args) // Don't call this function directly unless the name is "gpi" or starts with // "gpi." GPILOG_EXPORT void gpi_vlog_(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, va_list args); /** Check if a log would be filtered. * * @param logger Name of the logger. * @param level Level at which to test if the logger would emit a message. * @return `true` if the *logger* is enabled at *level*. */ GPILOG_EXPORT bool gpi_log_filtered(const char *logger, int level); /** Set the log level of a logger. * * @param logger Name of the logger. * @param level Level to set the logger to. * @return The old log level. */ GPILOG_EXPORT int gpi_log_set_level(const char *logger, int level); /** @return The string representation of the GPI log level. */ GPILOG_EXPORT const char *gpi_log_level_to_str(int level); /** Retrieve the current log handler. * @param handler Location to return current log handler function. If no * custom logger is registered this will be `NULL`. * @param filter Location to return current log filter function. If no * custom logger is registered this will be `NULL`. * @param set_level Location to return current log set level function. If no * custom logger is registered this will be `NULL`. * @param userdata Location to return log handler userdata. If no custom * logger is registered this will be `NULL`. */ GPILOG_EXPORT void gpi_get_log_handler(gpi_log_handler_ftype *handler, gpi_log_filter_ftype *filter, gpi_log_set_level_ftype *set_level, void **userdata); /** Set custom log handler * @param handler Logger handler function. * @param filter Logger level filter function. * @param set_level Logger set level function. * @param userdata Data passed to the above functions. */ GPILOG_EXPORT void gpi_set_log_handler(gpi_log_handler_ftype handler, gpi_log_filter_ftype filter, gpi_log_set_level_ftype set_level, void *userdata); /** Clear the current custom log handler and use native logger. */ GPILOG_EXPORT void gpi_clear_log_handler(void); /******************************************************************************* * GPI Native Logger *******************************************************************************/ /** Log a message using the native log handler. * User is expected to populate all arguments to this function. * @param extra_name Name of the "gpi" child logger, "" for the root logger * @param level Level at which to log the message * @param pathname Name of the file where the call site is located * @param funcname Name of the function where the call site is located * @param lineno Line number of the call site * @param msg The message to log, uses C-sprintf-style format specifier * @param ... Additional arguments; formatted and inserted in message * according to format specifier in msg argument */ #define gpi_native_logger_log(extra_name, level, pathname, funcname, lineno, \ ...) \ gpi_native_logger_log_(MAKE_LOG_NAME_(extra_name), level, pathname, \ funcname, lineno, __VA_ARGS__) // Don't call this function directly unless the name is "gpi" or starts with // "gpi." GPILOG_EXPORT void gpi_native_logger_log_(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, ...); /** Log a message using the native log handler. * User is expected to populate all arguments to this function. * @param extra_name Name of the "gpi" child logger, "" for the root logger * @param level Level at which to log the message * @param pathname Name of the file where the call site is located * @param funcname Name of the function where the call site is located * @param lineno Line number of the call site * @param msg The message to log, uses C-sprintf-style format specifier * @param args Additional arguments; formatted and inserted in message * according to format specifier in msg argument */ #define gpi_native_logger_vlog(extra_name, level, pathname, funcname, lineno, \ msg, args) \ gpi_native_logger_vlog_(MAKE_LOG_NAME_(extra_name), level, pathname, \ funcname, lineno, msg, args) // Don't call this function directly unless the name is "gpi" or starts with // "gpi." GPILOG_EXPORT void gpi_native_logger_vlog_(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, va_list args); /** Check if a message would be filtered by the native logger. * * @param level Level at which to test if the logger would emit a message. * @return `true` if the *logger* is enabled at *level*. */ GPILOG_EXPORT bool gpi_native_logger_filtered(int level); /** Set minimum logging level of the native logger. * * If a logging request occurs where the logging level is lower than the level * set by this function, it is not logged. Only affects the native logger. * @param level Logging level * @return Previous logging level */ GPILOG_EXPORT int gpi_native_logger_set_level(int level); #ifdef __cplusplus } #endif #endif /* COCOTB_GPI_LOGGING_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/include/py_gpi_logging.h0000644000175100017510000000126115106067236022372 0ustar00runnerrunner// Copyright cocotb contributors // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef PY_GPI_LOGGING_H #define PY_GPI_LOGGING_H #include #include "exports.h" #ifdef PYGPILOG_EXPORTS #define PYGPILOG_EXPORT COCOTB_EXPORT #else #define PYGPILOG_EXPORT COCOTB_IMPORT #endif #ifdef __cplusplus extern "C" { #endif PYGPILOG_EXPORT void py_gpi_logger_initialize(PyObject *handler, PyObject *get_logger); PYGPILOG_EXPORT void py_gpi_logger_finalize(); extern PYGPILOG_EXPORT PyObject *pEventFn; // This is gross but I don't care #ifdef __cplusplus } #endif #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/include/vhpi_user_ext.h0000644000175100017510000000116415106067236022263 0ustar00runnerrunner// Copyright cocotb contributors // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause /* extensions to vhpi_user.h */ #ifndef VHPI_USER_EXT_H #define VHPI_USER_EXT_H #ifdef __cplusplus extern "C" { #endif /* arguments for vhpiStop or vhpiFinish */ typedef enum { vhpiDiagNone = 0, /* prints nothing */ vhpiDiagTimeLoc = 1, /* prints simulation time and location */ vhpiDiagTimeLocCPUMem = 2 /* prints simulation time, location and statistics about CPU and memory usage */ } vhpiDiagT; #ifdef __cplusplus } #endif #endif /* VHPI_USER_EXT_H */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/include/vpi_user_ext.h0000644000175100017510000000165115106067236022114 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2019 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause /* extensions to vpi_user.h */ #ifndef VPI_USER_EXT_H #define VPI_USER_EXT_H #ifdef __cplusplus extern "C" { #endif /* used by Cadence Xcelium for packed unions */ #define vpiUnionNet 525 /* used by Cadence Xcelium for Verilog-AMS */ #define vpiRealNet 526 #define vpiInterconnectNet 533 #define vpiInterconnectArray 534 /* arguments for vpiStop or vpiFinish */ #define vpiDiagNone 0 /* prints nothing */ #define vpiDiagTimeLoc 1 /* prints simulation time and location */ #define vpiDiagTimeLocCPUMem 2 /* prints simulation time, location and statistics about CPU and memory usage */ #ifdef __cplusplus } #endif #endif /* VPI_USER_EXT_H */ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3337023 cocotb-2.0.1/src/cocotb/share/lib/0000755000175100017510000000000015106070715016343 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3477025 cocotb-2.0.1/src/cocotb/share/lib/embed/0000755000175100017510000000000015106070715017417 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/embed/embed.cpp0000644000175100017510000001043115106067236021202 0ustar00runnerrunner// Copyright cocotb contributors // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include // xstr, utils_dyn_open, utils_dyn_sym #include #include // gpi_event_t #include // getenv #ifdef _WIN32 #include // Win32 API for loading the embed impl library #include // string #endif #ifndef PYTHON_LIB #error "Name of Python library required" #else #define PYTHON_LIB_STR xstr(PYTHON_LIB) #endif #ifndef EMBED_IMPL_LIB #error "Name of embed implementation library required" #else #define EMBED_IMPL_LIB_STR xstr(EMBED_IMPL_LIB) #endif static void (*_embed_init_python)(); static void (*_embed_sim_cleanup)(); static int (*_embed_sim_init)(int argc, char const *const *argv); static void (*_embed_sim_event)(const char *msg); static bool init_failed = false; #ifdef _WIN32 static ACTCTX act_ctx = { /* cbSize */ sizeof(ACTCTX), /* dwFlags */ ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID, /* lpSource */ NULL, /* wProcessorArchitecture */ 0, /* wLangId */ 0, /* lpAssemblyDirectory */ NULL, /* lpResourceName */ MAKEINTRESOURCE(1000), /* lpApplicationName */ NULL, /* hModule */ 0}; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID) { if (fdwReason == DLL_PROCESS_ATTACH) { act_ctx.hModule = hinstDLL; } return TRUE; } #endif extern "C" void embed_init_python(void) { // preload python library char const *libpython_path = getenv("LIBPYTHON_LOC"); if (!libpython_path) { // default to libpythonX.X.so libpython_path = PYTHON_LIB_STR; } auto loaded = utils_dyn_open(libpython_path); if (!loaded) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } #ifdef _WIN32 if (!act_ctx.hModule) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } HANDLE hact_ctx = CreateActCtx(&act_ctx); if (hact_ctx == INVALID_HANDLE_VALUE) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } ULONG_PTR Cookie; if (!ActivateActCtx(hact_ctx, &Cookie)) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } #endif // load embed implementation library and functions void *embed_impl_lib_handle; if (!(embed_impl_lib_handle = utils_dyn_open(EMBED_IMPL_LIB_STR))) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } if (!(_embed_init_python = reinterpret_cast( utils_dyn_sym(embed_impl_lib_handle, "_embed_init_python")))) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } if (!(_embed_sim_cleanup = reinterpret_cast( utils_dyn_sym(embed_impl_lib_handle, "_embed_sim_cleanup")))) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } if (!(_embed_sim_init = reinterpret_cast( utils_dyn_sym(embed_impl_lib_handle, "_embed_sim_init")))) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } if (!(_embed_sim_event = reinterpret_cast( utils_dyn_sym(embed_impl_lib_handle, "_embed_sim_event")))) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } #ifdef _WIN32 if (!DeactivateActCtx(0, Cookie)) { // LCOV_EXCL_START init_failed = true; return; // LCOV_EXCL_STOP } ReleaseActCtx(hact_ctx); #endif // call to embed library impl _embed_init_python(); } extern "C" void embed_sim_cleanup(void) { if (!init_failed) { _embed_sim_cleanup(); } } extern "C" int embed_sim_init(int argc, char const *const *argv) { if (init_failed) { // LCOV_EXCL_START return -1; // LCOV_EXCL_STOP } else { return _embed_sim_init(argc, argv); } } extern "C" void embed_sim_event(const char *msg) { if (!init_failed) { _embed_sim_event(msg); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/embed/gpi_embed.cpp0000644000175100017510000002266515106067236022055 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause // Embed Python into the simulator using GPI #include #include #include #include #include "cocotb_utils.h" // DEFER #include "exports.h" // COCOTB_EXPORT #include "gpi_logging.h" // LOG_* macros #include "py_gpi_logging.h" // py_gpi_logger_set_level, py_gpi_logger_initialize, py_gpi_logger_finalize #if defined(_WIN32) #include #define sleep(n) Sleep(1000 * n) #define getpid() GetCurrentProcessId() #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif #else #include #endif static bool python_init_called = 0; static bool embed_init_called = 0; static wchar_t progname[] = L"cocotb"; static wchar_t *argv[] = {progname}; static int get_interpreter_path(wchar_t *path, size_t path_size) { const char *path_c = getenv("PYGPI_PYTHON_BIN"); if (!path_c) { // LCOV_EXCL_START LOG_ERROR( "PYGPI_PYTHON_BIN variable not set. Can't initialize Python " "interpreter!"); return -1; // LCOV_EXCL_STOP } auto path_temp = Py_DecodeLocale(path_c, NULL); if (path_temp == NULL) { // LCOV_EXCL_START LOG_ERROR( "Unable to set Python Program Name. " "Decoding error in Python executable path."); LOG_INFO("Python executable path: %s", path_c); return -1; // LCOV_EXCL_STOP } DEFER(PyMem_RawFree(path_temp)); wcsncpy(path, path_temp, path_size / sizeof(wchar_t)); if (path[(path_size / sizeof(wchar_t)) - 1]) { // LCOV_EXCL_START LOG_ERROR( "Unable to set Python Program Name. Path to interpreter too long"); LOG_INFO("Python executable path: %s", path_c); return -1; // LCOV_EXCL_STOP } return 0; } /** Initialize the Python interpreter */ extern "C" COCOTB_EXPORT void _embed_init_python(void) { if (python_init_called) { // LCOV_EXCL_START LOG_ERROR("PyGPI library initialized again!"); return; // LCOV_EXCL_STOP } python_init_called = 1; // must set program name to Python executable before initialization, so // initialization can determine path from executable static wchar_t interpreter_path[PATH_MAX], sys_executable[PATH_MAX]; if (get_interpreter_path(interpreter_path, sizeof(interpreter_path))) { // LCOV_EXCL_START return; // LCOV_EXCL_STOP } LOG_INFO("Using Python %s interpreter at %ls", PY_VERSION, interpreter_path); #if PY_VERSION_HEX >= 0x3080000 /* Use the new Python Initialization Configuration from Python 3.8. */ PyConfig config; PyStatus status; PyConfig_InitPythonConfig(&config); DEFER(PyConfig_Clear(&config)); PyConfig_SetString(&config, &config.program_name, interpreter_path); status = PyConfig_SetArgv(&config, 1, argv); if (PyStatus_Exception(status)) { // LCOV_EXCL_START LOG_ERROR("Failed to set ARGV during the Python initialization"); if (status.err_msg != NULL) { LOG_ERROR("\terror: %s", status.err_msg); } if (status.func != NULL) { LOG_ERROR("\tfunction: %s", status.func); } return; // LCOV_EXCL_STOP } status = Py_InitializeFromConfig(&config); if (PyStatus_Exception(status)) { // LCOV_EXCL_START LOG_ERROR("Failed to initialize Python"); if (status.err_msg != NULL) { LOG_ERROR("\terror: %s", status.err_msg); } if (status.func != NULL) { LOG_ERROR("\tfunction: %s", status.func); } return; // LCOV_EXCL_STOP } #else /* Use the old API. */ Py_SetProgramName(interpreter_path); Py_Initialize(); PySys_SetArgvEx(1, argv, 0); #endif /* Sanity check: make sure sys.executable was initialized to * interpreter_path. */ PyObject *sys_executable_obj = PySys_GetObject("executable"); if (sys_executable_obj == NULL) { // LCOV_EXCL_START LOG_ERROR("Failed to load sys.executable"); // LCOV_EXCL_STOP } else if (PyUnicode_AsWideChar(sys_executable_obj, sys_executable, sizeof(sys_executable)) == -1) { // LCOV_EXCL_START LOG_ERROR("Failed to convert sys.executable to wide string"); // LCOV_EXCL_STOP } else if (wcscmp(interpreter_path, sys_executable) != 0) { // LCOV_EXCL_START LOG_ERROR("Unexpected sys.executable value (expected '%ls', got '%ls')", interpreter_path, sys_executable); // LCOV_EXCL_STOP } /* Before returning we check if the user wants pause the simulator thread such that they can attach */ const char *pause = getenv("COCOTB_ATTACH"); if (pause) { unsigned long sleep_time = strtoul(pause, NULL, 10); /* This should check for out-of-range parses which returns ULONG_MAX and sets errno, as well as correct parses that would be sliced by the narrowing cast */ if (errno == ERANGE || sleep_time >= UINT_MAX) { // LCOV_EXCL_START LOG_ERROR("COCOTB_ATTACH only needs to be set to ~30 seconds"); return; // LCOV_EXCL_STOP } if ((errno != 0 && sleep_time == 0) || (sleep_time <= 0)) { // LCOV_EXCL_START LOG_ERROR( "COCOTB_ATTACH must be set to an integer base 10 or omitted"); return; // LCOV_EXCL_STOP } LOG_INFO( "Waiting for %lu seconds - attach to PID %d with your debugger", sleep_time, getpid()); sleep((unsigned int)sleep_time); } } /** * @name Simulator cleanup * @brief Called by the simulator on shutdown. * @ingroup python_c_api * * GILState before calling: Not held * * GILState after calling: Not held * * Makes one call to PyGILState_Ensure and one call to Py_Finalize. * * Cleans up reference counts for Python objects and calls Py_Finalize function. */ extern "C" COCOTB_EXPORT void _embed_sim_cleanup(void) { // If initialization fails, this may be called twice: // Before the initial callback returns and in the final callback. // So we check if Python is still initialized before doing cleanup. if (Py_IsInitialized()) { to_python(); PyGILState_Ensure(); // Don't save state as we are calling Py_Finalize Py_XDECREF(pEventFn); pEventFn = NULL; py_gpi_logger_finalize(); Py_Finalize(); to_simulator(); } } extern "C" COCOTB_EXPORT int _embed_sim_init(int argc, char const *const *_argv) { // Check that we are not already initialized if (embed_init_called) { // LCOV_EXCL_START LOG_ERROR("PyGPI library initialized again!"); return -1; // LCOV_EXCL_STOP } embed_init_called = 1; // Ensure that the current thread is ready to call the Python C API auto gstate = PyGILState_Ensure(); DEFER(PyGILState_Release(gstate)); to_python(); DEFER(to_simulator()); auto entry_utility_module = PyImport_ImportModule("pygpi.entry"); if (!entry_utility_module) { // LCOV_EXCL_START PyErr_Print(); return -1; // LCOV_EXCL_STOP } DEFER(Py_DECREF(entry_utility_module)); // Build argv for cocotb module auto argv_list = PyList_New(argc); if (argv_list == NULL) { // LCOV_EXCL_START PyErr_Print(); return -1; // LCOV_EXCL_STOP } for (int i = 0; i < argc; i++) { // Decode, embedding non-decodable bytes using PEP-383. This can only // fail with MemoryError or similar. auto argv_item = PyUnicode_DecodeLocale(_argv[i], "surrogateescape"); if (!argv_item) { // LCOV_EXCL_START PyErr_Print(); return -1; // LCOV_EXCL_STOP } PyList_SetItem(argv_list, i, argv_item); } DEFER(Py_DECREF(argv_list)) auto cocotb_retval = PyObject_CallMethod(entry_utility_module, "load_entry", "O", argv_list); if (!cocotb_retval) { // Printing a SystemExit calls exit(1), which we don't want. if (!PyErr_ExceptionMatches(PyExc_SystemExit)) { PyErr_Print(); } // Clear error so re-entering Python doesn't fail. PyErr_Clear(); return -1; } Py_DECREF(cocotb_retval); return 0; } extern "C" COCOTB_EXPORT void _embed_sim_event(const char *msg) { /* Indicate to the upper layer that a sim event occurred */ if (pEventFn) { PyGILState_STATE gstate; to_python(); gstate = PyGILState_Ensure(); if (msg == NULL) { msg = "No message provided"; } PyObject *pValue = PyObject_CallFunction(pEventFn, "s", msg); if (pValue == NULL) { // Printing a SystemExit calls exit(1), which we don't want. if (!PyErr_ExceptionMatches(PyExc_SystemExit)) { PyErr_Print(); } // Clear error so re-entering Python doesn't fail. PyErr_Clear(); LOG_ERROR("Passing event to upper layer failed"); } Py_XDECREF(pValue); PyGILState_Release(gstate); to_simulator(); } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3487027 cocotb-2.0.1/src/cocotb/share/lib/fli/0000755000175100017510000000000015106070715017115 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/fli/FliCbHdl.cpp0000644000175100017510000001137215106067236021240 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2015/16 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include #include "FliImpl.h" #include "_vendor/fli/mti.h" // Main re-entry point for callbacks from simulator void handle_fli_callback(void *data) { gpi_to_user(); // TODO Add why? fflush(stderr); FliCbHdl *cb_hdl = (FliCbHdl *)data; // LCOV_EXCL_START if (!cb_hdl) { LOG_CRITICAL("FLI: Callback data corrupted: ABORTING"); gpi_embed_end(); return; } // LCOV_EXCL_STOP if (cb_hdl->run()) { // sim failed, so call shutdown gpi_embed_end(); } gpi_to_simulator(); } int FliTimedCbHdl::arm() { // These are reused, so we need to reset m_removed. m_removed = false; #if defined(__LP64__) || defined(_WIN64) mti_ScheduleWakeup64(m_proc_hdl, static_cast(m_time)); #else mtiTime64T m_time_union_ps; MTI_TIME64_ASGN(m_time_union_ps, (mtiInt32T)((m_time) >> 32), (mtiUInt32T)(m_time)); mti_ScheduleWakeup64(m_proc_hdl, m_time_union_ps); #endif return 0; } int FliTimedCbHdl::run() { int res = 0; if (!m_removed) { // Prevent the callback from calling up if it's been removed. res = m_cb_func(m_cb_data); } // Don't delete, but release back to the appropriate cache to be reused. release(); return res; } int FliTimedCbHdl::remove() { // mti_ScheduleWakeup callbacks can't be cancelled, so we mark the callback // as removed and let it fire. When it fires, this flag prevents it from // calling up and then releases the callback back to the appropriate cache // to be reused. m_removed = true; return 0; } int FliSignalCbHdl::arm() { mti_Sensitize(m_proc_hdl, m_signal->get_handle(), MTI_EVENT); return 0; } int FliSignalCbHdl::run() { bool pass = false; switch (m_edge) { case GPI_RISING: { pass = !strcmp(m_signal->get_signal_value_binstr(), "1"); break; } case GPI_FALLING: { pass = !strcmp(m_signal->get_signal_value_binstr(), "0"); break; } case GPI_VALUE_CHANGE: { pass = true; break; } } int res = 0; if (pass) { res = m_cb_func(m_cb_data); // Don't delete, but desensitize the process from the signal change and // release back to the appropriate cache to be reused. mti_Desensitize(m_proc_hdl); release(); } // else don't remove and let it fire again. return res; } int FliSignalCbHdl::remove() { // Don't delete, but desensitize the process from the signal change and // release back to the appropriate cache to be reused. mti_Desensitize(m_proc_hdl); release(); return 0; } int FliSimPhaseCbHdl::arm() { mti_ScheduleWakeup(m_proc_hdl, 0); m_removed = false; return 0; } int FliSimPhaseCbHdl::run() { int res = 0; if (!m_removed) { // Prevent the callback from calling up if it's been removed. res = m_cb_func(m_cb_data); } // Don't delete, but release back to the appropriate cache to be reused. release(); return res; } int FliSimPhaseCbHdl::remove() { // mti_ScheduleWakeup callbacks can't be cancelled, so we mark the callback // as removed and let it fire. When it fires, this flag prevents it from // calling up and then releases the callback back to the appropriate cache // to be reused. m_removed = true; return 0; } void FliSignalCbHdl::release() { dynamic_cast(m_impl)->m_value_change_cache.release(this); } void FliTimedCbHdl::release() { dynamic_cast(m_impl)->m_timer_cache.release(this); } void FliReadOnlyCbHdl::release() { dynamic_cast(m_impl)->m_read_only_cache.release(this); } void FliReadWriteCbHdl::release() { dynamic_cast(m_impl)->m_read_write_cache.release(this); } void FliNextPhaseCbHdl::release() { dynamic_cast(m_impl)->m_next_phase_cache.release(this); } int FliStartupCbHdl::arm() { mti_AddLoadDoneCB(handle_fli_callback, (void *)this); return 0; } int FliStartupCbHdl::run() { int res = m_cb_func(m_cb_data); delete this; return res; } int FliStartupCbHdl::remove() { mti_RemoveLoadDoneCB(handle_fli_callback, (void *)this); delete this; return 0; } int FliShutdownCbHdl::arm() { mti_AddQuitCB(handle_fli_callback, (void *)this); return 0; } int FliShutdownCbHdl::run() { int res = m_cb_func(m_cb_data); delete this; return res; } int FliShutdownCbHdl::remove() { mti_RemoveQuitCB(handle_fli_callback, (void *)this); delete this; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/fli/FliImpl.cpp0000644000175100017510000011613115106067236021164 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2014, 2018 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include "FliImpl.h" #include #include #include #include #include #include "_vendor/fli/acc_user.h" #include "_vendor/fli/acc_vhdl.h" #include "_vendor/fli/mti.h" #include "_vendor/tcl/tcl.h" void FliImpl::sim_end() { m_sim_finish_cb->remove(); if (mti_NowUpper() == 0 && mti_Now() == 0 && mti_Delta() == 0) { mti_Quit(); } else { mti_Break(); } } bool FliImpl::isValueConst(int kind) { return (kind == accGeneric || kind == accVHDLConstant); } bool FliImpl::isValueLogic(mtiTypeIdT type) { mtiInt32T numEnums = mti_TickLength(type); if (numEnums == 2) { char **enum_values = mti_GetEnumValues(type); std::string str0 = enum_values[0]; std::string str1 = enum_values[1]; if (str0.compare("'0'") == 0 && str1.compare("'1'") == 0) { return true; } } else if (numEnums == 9) { const char enums[9][4] = {"'U'", "'X'", "'0'", "'1'", "'Z'", "'W'", "'L'", "'H'", "'-'"}; char **enum_values = mti_GetEnumValues(type); for (int i = 0; i < 9; i++) { std::string str = enum_values[i]; if (str.compare(enums[i]) != 0) { return false; } } return true; } return false; } bool FliImpl::isValueChar(mtiTypeIdT type) { const int NUM_ENUMS_IN_CHAR_TYPE = 256; return (mti_TickLength(type) == NUM_ENUMS_IN_CHAR_TYPE); } bool FliImpl::isValueBoolean(mtiTypeIdT type) { if (mti_TickLength(type) == 2) { char **enum_values = mti_GetEnumValues(type); std::string strFalse = enum_values[0]; std::string strTrue = enum_values[1]; if (strFalse.compare("FALSE") == 0 && strTrue.compare("TRUE") == 0) { return true; } } return false; } bool FliImpl::isTypeValue(int type) { return (type == accAlias || type == accVHDLConstant || type == accGeneric || type == accVariable || type == accSignal); } bool FliImpl::isTypeSignal(int type, int full_type) { return (type == accSignal || full_type == accAliasSignal); } GpiObjHdl *FliImpl::create_gpi_obj_from_handle(void *hdl, const std::string &name, const std::string &fq_name, int accType, int accFullType) { GpiObjHdl *new_obj = NULL; LOG_DEBUG( "Attempting to create GPI object from handle (Type=%d, FullType=%d).", accType, accFullType); if (!VS_TYPE_IS_VHDL(accFullType)) { LOG_DEBUG("Handle is not a VHDL type."); return NULL; } if (!isTypeValue(accType)) { /* Need a Pseudo-region to handle generate loops in a consistent manner * across interfaces and across the different methods of accessing data. */ std::string rgn_name = mti_GetRegionName(static_cast(hdl)); if (name != rgn_name) { LOG_DEBUG("Found pseudo-region %s -> %p", fq_name.c_str(), hdl); new_obj = new FliObjHdl(this, hdl, GPI_GENARRAY, accType, accFullType); } else { LOG_DEBUG("Found region %s -> %p", fq_name.c_str(), hdl); new_obj = new FliObjHdl(this, hdl, GPI_MODULE, accType, accFullType); } } else { bool is_var; bool is_const; mtiTypeIdT valType; mtiTypeKindT typeKind; if (isTypeSignal(accType, accFullType)) { LOG_DEBUG("Found a signal %s -> %p", fq_name.c_str(), hdl); is_var = false; is_const = false; valType = mti_GetSignalType(static_cast(hdl)); } else { LOG_DEBUG("Found a variable %s -> %p", fq_name.c_str(), hdl); is_var = true; is_const = isValueConst(accFullType); valType = mti_GetVarType(static_cast(hdl)); } typeKind = mti_GetTypeKind(valType); switch (typeKind) { case MTI_TYPE_ENUM: if (isValueLogic(valType)) { new_obj = new FliLogicObjHdl(this, hdl, GPI_LOGIC, is_const, accType, accFullType, is_var, valType, typeKind); } else if (isValueBoolean(valType) || isValueChar(valType)) { new_obj = new FliIntObjHdl(this, hdl, GPI_INTEGER, is_const, accType, accFullType, is_var, valType, typeKind); } else { new_obj = new FliEnumObjHdl(this, hdl, GPI_ENUM, is_const, accType, accFullType, is_var, valType, typeKind); } break; case MTI_TYPE_SCALAR: case MTI_TYPE_PHYSICAL: new_obj = new FliIntObjHdl(this, hdl, GPI_INTEGER, is_const, accType, accFullType, is_var, valType, typeKind); break; case MTI_TYPE_REAL: new_obj = new FliRealObjHdl(this, hdl, GPI_REAL, is_const, accType, accFullType, is_var, valType, typeKind); break; case MTI_TYPE_ARRAY: { mtiTypeIdT elemType = mti_GetArrayElementType(valType); mtiTypeKindT elemTypeKind = mti_GetTypeKind(elemType); switch (elemTypeKind) { case MTI_TYPE_ENUM: if (isValueLogic(elemType)) { new_obj = new FliLogicObjHdl( this, hdl, GPI_LOGIC_ARRAY, is_const, accType, accFullType, is_var, valType, typeKind); // std_logic_vector } else if (isValueChar(elemType)) { new_obj = new FliStringObjHdl( this, hdl, GPI_STRING, is_const, accType, accFullType, is_var, valType, typeKind); } else { new_obj = new FliValueObjHdl( this, hdl, GPI_ARRAY, false, accType, accFullType, is_var, valType, typeKind); // array of enums } break; default: new_obj = new FliValueObjHdl( this, hdl, GPI_ARRAY, false, accType, accFullType, is_var, valType, typeKind); // array of (array, Integer, Real, // Record, etc.) } } break; case MTI_TYPE_RECORD: new_obj = new FliValueObjHdl(this, hdl, GPI_STRUCTURE, false, accType, accFullType, is_var, valType, typeKind); break; default: LOG_ERROR("Unable to handle object type for %s (%d)", name.c_str(), typeKind); return NULL; } } if (NULL == new_obj) { LOG_DEBUG("Didn't find anything named %s", fq_name.c_str()); return NULL; } if (new_obj->initialise(name, fq_name) < 0) { LOG_ERROR("Failed to initialize the handle %s", name.c_str()); delete new_obj; return NULL; } return new_obj; } GpiObjHdl *FliImpl::get_child_from_handle(void *raw_hdl, GpiObjHdl *) { LOG_DEBUG("Trying to convert a raw handle to an FLI Handle."); const char *c_name = acc_fetch_name(raw_hdl); const char *c_fullname = acc_fetch_fullname(raw_hdl); if (!c_name) { LOG_DEBUG("Unable to query the name of the raw handle."); return NULL; } std::string name = c_name; std::string fq_name = c_fullname; PLI_INT32 accType = acc_fetch_type(raw_hdl); PLI_INT32 accFullType = acc_fetch_fulltype(raw_hdl); return create_gpi_obj_from_handle(raw_hdl, name, fq_name, accType, accFullType); } /** * @name Get Child By Name * @brief Attempt to get child handle by name with FLI and create * a handle if it exists */ GpiObjHdl *FliImpl::get_child_by_name(const std::string &name, GpiObjHdl *parent) { bool search_rgn = false; bool search_sig = false; bool search_var = false; std::string fq_name = parent->get_fullname(); gpi_objtype obj_type = parent->get_type(); if (fq_name == "/") { fq_name += name; search_rgn = true; search_sig = true; search_var = true; } else if (obj_type == GPI_MODULE) { fq_name += "/" + name; search_rgn = true; search_sig = true; search_var = true; } else if (obj_type == GPI_STRUCTURE) { FliValueObjHdl *fli_obj = reinterpret_cast(parent); fq_name += "." + name; search_rgn = false; search_var = fli_obj->is_variable(); search_sig = !search_var; } else { LOG_ERROR( "FLI: Parent of type %d must be of type GPI_MODULE or " "GPI_STRUCTURE to have a child.", obj_type); return NULL; } LOG_DEBUG("Looking for child %s from %s", name.c_str(), parent->get_name_str()); std::vector writable(fq_name.begin(), fq_name.end()); writable.push_back('\0'); HANDLE hdl = NULL; PLI_INT32 accType; PLI_INT32 accFullType; if (search_rgn && (hdl = mti_FindRegion(&writable[0])) != NULL) { accType = acc_fetch_type(hdl); accFullType = acc_fetch_fulltype(hdl); LOG_DEBUG("Found region %s -> %p", fq_name.c_str(), hdl); LOG_DEBUG(" Type: %d", accType); LOG_DEBUG(" Full Type: %d", accFullType); } else if (search_sig && (hdl = mti_FindSignal(&writable[0])) != NULL) { accType = acc_fetch_type(hdl); accFullType = acc_fetch_fulltype(hdl); LOG_DEBUG("Found a signal %s -> %p", fq_name.c_str(), hdl); LOG_DEBUG(" Type: %d", accType); LOG_DEBUG(" Full Type: %d", accFullType); } else if (search_var && (hdl = mti_FindVar(&writable[0])) != NULL) { accFullType = accType = mti_GetVarKind(static_cast(hdl)); LOG_DEBUG("Found a variable %s -> %p", fq_name.c_str(), hdl); LOG_DEBUG(" Type: %d", accType); LOG_DEBUG(" Full Type: %d", accFullType); } else if (search_rgn) { mtiRegionIdT rgn; // Looking for generates should only occur if the parent is from this // implementation if (!parent->is_this_impl(this)) { return NULL; } /* If not found, check to see if the name of a generate loop and create * a pseudo-region */ for (rgn = mti_FirstLowerRegion(parent->get_handle()); rgn != NULL; rgn = mti_NextRegion(rgn)) { if (acc_fetch_fulltype(rgn) == accForGenerate) { std::string rgn_name = mti_GetRegionName(static_cast(rgn)); if (compare_generate_labels(rgn_name, name)) { FliObj *fli_obj = dynamic_cast(parent); return create_gpi_obj_from_handle( parent->get_handle(), name, fq_name, fli_obj->get_acc_type(), fli_obj->get_acc_full_type()); } } } } if (NULL == hdl) { LOG_DEBUG("Didn't find anything named %s", &writable[0]); return NULL; } /* Generate Loops have inconsistent behavior across fli. A "name" * without an index, i.e. dut.loop vs dut.loop(0), will attempt to map * to index 0, if index 0 exists. If it doesn't then it won't find * anything. * * If this unique case is hit, we need to create the Pseudo-region, with the * handle being equivalent to the parent handle. */ if (accFullType == accForGenerate) { FliObj *fli_obj = dynamic_cast(parent); return create_gpi_obj_from_handle(parent->get_handle(), name, fq_name, fli_obj->get_acc_type(), fli_obj->get_acc_full_type()); } return create_gpi_obj_from_handle(hdl, name, fq_name, accType, accFullType); } /** * @name Get Child By Index * @brief Attempt to get child handle by index with FLI and create * a handle if it exists */ GpiObjHdl *FliImpl::get_child_by_index(int32_t index, GpiObjHdl *parent) { gpi_objtype obj_type = parent->get_type(); HANDLE hdl; PLI_INT32 accType; PLI_INT32 accFullType; char buff[14]; if (obj_type == GPI_GENARRAY) { LOG_DEBUG("Looking for index %d from %s", index, parent->get_name_str()); snprintf(buff, 14, "(%d)", index); std::string idx = buff; std::string name = parent->get_name() + idx; std::string fq_name = parent->get_fullname() + idx; std::vector writable(fq_name.begin(), fq_name.end()); writable.push_back('\0'); if ((hdl = mti_FindRegion(&writable[0])) != NULL) { accType = acc_fetch_type(hdl); accFullType = acc_fetch_fulltype(hdl); LOG_DEBUG("Found region %s -> %p", fq_name.c_str(), hdl); LOG_DEBUG(" Type: %d", accType); LOG_DEBUG(" Full Type: %d", accFullType); } else { LOG_DEBUG("Didn't find anything named %s", &writable[0]); return NULL; } return create_gpi_obj_from_handle(hdl, name, fq_name, accType, accFullType); } else if (obj_type == GPI_LOGIC || obj_type == GPI_LOGIC_ARRAY || obj_type == GPI_ARRAY || obj_type == GPI_STRING) { FliValueObjHdl *fli_obj = reinterpret_cast(parent); LOG_DEBUG("Looking for index %u from %s", index, parent->get_name_str()); if ((hdl = fli_obj->get_sub_hdl(index)) == NULL) { LOG_DEBUG("Didn't find the index %d", index); return NULL; } snprintf(buff, 14, "(%d)", index); std::string idx = buff; std::string name = parent->get_name() + idx; std::string fq_name = parent->get_fullname() + idx; if (!(fli_obj->is_variable())) { accType = acc_fetch_type(hdl); accFullType = acc_fetch_fulltype(hdl); LOG_DEBUG("Found a signal %s -> %p", fq_name.c_str(), hdl); LOG_DEBUG(" Type: %d", accType); LOG_DEBUG(" Full Type: %d", accFullType); } else { accFullType = accType = mti_GetVarKind(static_cast(hdl)); LOG_DEBUG("Found a variable %s -> %p", fq_name.c_str(), hdl); LOG_DEBUG(" Type: %d", accType); LOG_DEBUG(" Full Type: %d", accFullType); } return create_gpi_obj_from_handle(hdl, name, fq_name, accType, accFullType); } else { LOG_ERROR( "FLI: Parent of type %d must be of type GPI_GENARRAY, " "GPI_LOGIC, GPI_ARRAY, or GPI_STRING to have an index.", obj_type); return NULL; } } const char *FliImpl::reason_to_string(int) { return "Who can explain it, who can tell you why?"; } /** * @name Get current simulation time * @brief Get current simulation time * * NB units depend on the simulation configuration */ void FliImpl::get_sim_time(uint32_t *high, uint32_t *low) { *high = static_cast( mti_NowUpper()); // these functions return a int32_t for some reason *low = static_cast(mti_Now()); } void FliImpl::get_sim_precision(int32_t *precision) { *precision = mti_GetResolutionLimit(); } const char *FliImpl::get_simulator_product() { if (m_product.empty() && m_version.empty()) { const std::string info = mti_GetProductVersion(); // Returned pointer must not be freed, // does not fail const std::string search = " Version "; const std::size_t found = info.find(search); if (found != std::string::npos) { m_product = info.substr(0, found); m_version = info.substr(found + search.length()); } else { m_product = info; m_version = "UNKNOWN"; } } return m_product.c_str(); } const char *FliImpl::get_simulator_version() { get_simulator_product(); return m_version.c_str(); } /** * @name Find the root handle * @brief Find the root handle using an optional name * * Get a handle to the root simulator object. This is usually the toplevel. * * If no name is provided, we return the first root instance. * * If name is provided, we check the name against the available objects until * we find a match. If no match is found we return NULL */ GpiObjHdl *FliImpl::get_root_handle(const char *name) { mtiRegionIdT root; char *rgn_name; char *rgn_fullname; std::string root_name; std::string root_fullname; PLI_INT32 accType; PLI_INT32 accFullType; for (root = mti_GetTopRegion(); root != NULL; root = mti_NextRegion(root)) { LOG_DEBUG("Iterating over: %s", mti_GetRegionName(root)); if (name == NULL || !strcmp(name, mti_GetRegionName(root))) break; } if (!root) { goto error; } rgn_name = mti_GetRegionName(root); rgn_fullname = mti_GetRegionFullName(root); root_name = rgn_name; root_fullname = rgn_fullname; mti_VsimFree(rgn_fullname); LOG_DEBUG("Found toplevel: %s, creating handle....", root_name.c_str()); accType = acc_fetch_type(root); accFullType = acc_fetch_fulltype(root); return create_gpi_obj_from_handle(root, root_name, root_fullname, accType, accFullType); error: LOG_ERROR("FLI: Couldn't find root handle %s", name); for (root = mti_GetTopRegion(); root != NULL; root = mti_NextRegion(root)) { if (name == NULL) break; LOG_ERROR("FLI: Toplevel instances: %s != %s...", name, mti_GetRegionName(root)); } return NULL; } GpiCbHdl *FliImpl::register_timed_callback(uint64_t time, int (*cb_func)(void *), void *cb_data) { // get timer from cache auto cb_hdl = m_timer_cache.acquire(); cb_hdl->set_time(time); int err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { m_timer_cache.release(cb_hdl); return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiCbHdl *FliImpl::register_readonly_callback(int (*cb_func)(void *), void *cb_data) { auto cb_hdl = m_read_only_cache.acquire(); int err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { m_read_only_cache.release(cb_hdl); return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiCbHdl *FliImpl::register_readwrite_callback(int (*cb_func)(void *), void *cb_data) { auto cb_hdl = m_read_write_cache.acquire(); int err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { m_read_write_cache.release(cb_hdl); return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiCbHdl *FliImpl::register_nexttime_callback(int (*cb_func)(void *), void *cb_data) { auto cb_hdl = m_next_phase_cache.acquire(); int err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { m_next_phase_cache.release(cb_hdl); return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiIterator *FliImpl::iterate_handle(GpiObjHdl *obj_hdl, gpi_iterator_sel type) { GpiIterator *new_iter = NULL; switch (type) { case GPI_OBJECTS: new_iter = new FliIterator(this, obj_hdl); break; case GPI_DRIVERS: LOG_WARN("FLI: Drivers iterator not implemented yet"); break; case GPI_LOADS: LOG_WARN("FLI: Loads iterator not implemented yet"); break; default: LOG_WARN("FLI: Other iterator types not implemented yet"); break; } return new_iter; } bool FliImpl::compare_generate_labels(const std::string &a, const std::string &b) { /* Compare two generate labels for equality ignoring any suffixed index. */ std::size_t a_idx = a.rfind("("); std::size_t b_idx = b.rfind("("); return a.substr(0, a_idx) == b.substr(0, b_idx); } decltype(FliIterator::iterate_over) FliIterator::iterate_over = [] { std::initializer_list region_options = { FliIterator::OTM_CONSTANTS, FliIterator::OTM_SIGNALS, FliIterator::OTM_REGIONS, }; std::initializer_list signal_options = { FliIterator::OTM_SIGNAL_SUB_ELEMENTS, }; std::initializer_list variable_options = { FliIterator::OTM_VARIABLE_SUB_ELEMENTS, }; return decltype(FliIterator::iterate_over){ {accArchitecture, region_options}, {accEntityVitalLevel0, region_options}, {accArchVitalLevel0, region_options}, {accArchVitalLevel1, region_options}, {accBlock, region_options}, {accCompInst, region_options}, {accDirectInst, region_options}, {accinlinedBlock, region_options}, {accinlinedinnerBlock, region_options}, {accGenerate, region_options}, {accIfGenerate, region_options}, #ifdef accElsifGenerate {accElsifGenerate, region_options}, #endif #ifdef accElseGenerate {accElseGenerate, region_options}, #endif #ifdef accCaseGenerate {accCaseGenerate, region_options}, #endif #ifdef accCaseOTHERSGenerate {accCaseOTHERSGenerate, region_options}, #endif {accForGenerate, region_options}, {accConfiguration, region_options}, {accSignal, signal_options}, {accSignalBit, signal_options}, {accSignalSubComposite, signal_options}, {accAliasSignal, signal_options}, {accVariable, variable_options}, {accGeneric, variable_options}, {accGenericConstant, variable_options}, {accAliasConstant, variable_options}, {accAliasGeneric, variable_options}, {accAliasVariable, variable_options}, {accVHDLConstant, variable_options}, }; }(); FliIterator::FliIterator(GpiImplInterface *impl, GpiObjHdl *hdl) : GpiIterator(impl, hdl), m_vars(), m_sigs(), m_regs(), m_currentHandles(NULL) { FliObj *fli_obj = dynamic_cast(m_parent); int type = fli_obj->get_acc_full_type(); LOG_DEBUG("fli_iterator::Create iterator for %s of type %d:%s", m_parent->get_fullname().c_str(), type, acc_fetch_type_str(type)); try { selected = &iterate_over.at(type); } catch (std::out_of_range const &) { LOG_WARN("FLI: Implementation does not know how to iterate over %s(%d)", acc_fetch_type_str(type), type); selected = nullptr; return; } /* Find the first mapping type that yields a valid iterator */ for (one2many = selected->begin(); one2many != selected->end(); one2many++) { /* GPI_GENARRAY are pseudo-regions and all that should be searched for * are the sub-regions */ if (m_parent->get_type() == GPI_GENARRAY && *one2many != FliIterator::OTM_REGIONS) { LOG_DEBUG("fli_iterator OneToMany=%d skipped for GPI_GENARRAY type", *one2many); continue; } populate_handle_list(*one2many); switch (*one2many) { case FliIterator::OTM_CONSTANTS: case FliIterator::OTM_VARIABLE_SUB_ELEMENTS: m_currentHandles = &m_vars; m_iterator = m_vars.begin(); break; case FliIterator::OTM_SIGNALS: case FliIterator::OTM_SIGNAL_SUB_ELEMENTS: m_currentHandles = &m_sigs; m_iterator = m_sigs.begin(); break; case FliIterator::OTM_REGIONS: m_currentHandles = &m_regs; m_iterator = m_regs.begin(); break; default: LOG_WARN("Unhandled OneToMany Type (%d)", *one2many); } if (m_iterator != m_currentHandles->end()) break; LOG_DEBUG("fli_iterator OneToMany=%d returned NULL", *one2many); } if (m_iterator == m_currentHandles->end()) { LOG_DEBUG( "fli_iterator return NULL for all relationships on %s (%d) kind:%s", m_parent->get_name_str(), type, acc_fetch_type_str(type)); selected = NULL; return; } LOG_DEBUG("Created iterator working from scope %d", *one2many); } GpiIterator::Status FliIterator::next_handle(std::string &name, GpiObjHdl **hdl, void **raw_hdl) { HANDLE obj; GpiObjHdl *new_obj; if (!selected) return GpiIterator::END; gpi_objtype obj_type = m_parent->get_type(); std::string parent_name = m_parent->get_name(); /* We want the next object in the current mapping. * If the end of mapping is reached then we want to * try next one until a new object is found */ do { obj = NULL; if (m_iterator != m_currentHandles->end()) { obj = *m_iterator++; /* For GPI_GENARRAY, only allow the generate statements through that * match the name of the generate block. */ if (obj_type == GPI_GENARRAY) { if (acc_fetch_fulltype(obj) == accForGenerate) { std::string rgn_name = mti_GetRegionName(static_cast(obj)); if (!FliImpl::compare_generate_labels(rgn_name, parent_name)) { obj = NULL; continue; } } else { obj = NULL; continue; } } break; } else { LOG_DEBUG( "No more valid handles in the current OneToMany=%d iterator", *one2many); } if (++one2many >= selected->end()) { obj = NULL; break; } /* GPI_GENARRAY are pseudo-regions and all that should be searched for * are the sub-regions */ if (obj_type == GPI_GENARRAY && *one2many != FliIterator::OTM_REGIONS) { LOG_DEBUG("fli_iterator OneToMany=%d skipped for GPI_GENARRAY type", *one2many); continue; } populate_handle_list(*one2many); switch (*one2many) { case FliIterator::OTM_CONSTANTS: case FliIterator::OTM_VARIABLE_SUB_ELEMENTS: m_currentHandles = &m_vars; m_iterator = m_vars.begin(); break; case FliIterator::OTM_SIGNALS: case FliIterator::OTM_SIGNAL_SUB_ELEMENTS: m_currentHandles = &m_sigs; m_iterator = m_sigs.begin(); break; case FliIterator::OTM_REGIONS: m_currentHandles = &m_regs; m_iterator = m_regs.begin(); break; default: LOG_WARN("Unhandled OneToMany Type (%d)", *one2many); } } while (!obj); if (NULL == obj) { LOG_DEBUG("No more children, all relationships tested"); return GpiIterator::END; } char *c_name; PLI_INT32 accType; PLI_INT32 accFullType; switch (*one2many) { case FliIterator::OTM_CONSTANTS: case FliIterator::OTM_VARIABLE_SUB_ELEMENTS: c_name = mti_GetVarName(static_cast(obj)); accFullType = accType = mti_GetVarKind(static_cast(obj)); break; case FliIterator::OTM_SIGNALS: c_name = mti_GetSignalName(static_cast(obj)); accType = acc_fetch_type(obj); accFullType = acc_fetch_fulltype(obj); break; case FliIterator::OTM_SIGNAL_SUB_ELEMENTS: c_name = mti_GetSignalNameIndirect(static_cast(obj), NULL, 0); accType = acc_fetch_type(obj); accFullType = acc_fetch_fulltype(obj); break; case FliIterator::OTM_REGIONS: c_name = mti_GetRegionName(static_cast(obj)); accType = acc_fetch_type(obj); accFullType = acc_fetch_fulltype(obj); break; default: c_name = NULL; accType = 0; accFullType = 0; LOG_WARN("Unhandled OneToMany Type (%d)", *one2many); } if (!c_name) { if (!VS_TYPE_IS_VHDL(accFullType)) { *raw_hdl = (void *)obj; return GpiIterator::NOT_NATIVE_NO_NAME; } return GpiIterator::NATIVE_NO_NAME; } /* * If the parent is not a generate loop, then watch for generate handles and * create the pseudo-region. * * NOTE: Taking advantage of the "caching" to only create one pseudo-region * object. Otherwise a list would be required and checked while iterating */ if (*one2many == FliIterator::OTM_REGIONS && obj_type != GPI_GENARRAY && accFullType == accForGenerate) { std::string idx_str = c_name; std::size_t found = idx_str.find_last_of("("); if (found != std::string::npos && found != 0) { FliObj *fli_obj = dynamic_cast(m_parent); name = idx_str.substr(0, found); obj = m_parent->get_handle(); accType = fli_obj->get_acc_type(); accFullType = fli_obj->get_acc_full_type(); } else { LOG_WARN("Unhandled Generate Loop Format - %s", name.c_str()); name = c_name; } } else { name = c_name; } if (*one2many == FliIterator::OTM_SIGNAL_SUB_ELEMENTS) { mti_VsimFree(c_name); } std::string fq_name = m_parent->get_fullname(); if (fq_name == "/") { fq_name += name; } else if (*one2many == FliIterator::OTM_SIGNAL_SUB_ELEMENTS || *one2many == FliIterator::OTM_VARIABLE_SUB_ELEMENTS || obj_type == GPI_GENARRAY) { std::size_t found; if (obj_type == GPI_STRUCTURE) { found = name.find_last_of("."); } else { found = name.find_last_of("("); } if (found != std::string::npos) { fq_name += name.substr(found); if (obj_type != GPI_GENARRAY) { name = name.substr(found + 1); } } else { LOG_WARN("Unhandled Sub-Element Format - %s", name.c_str()); fq_name += "/" + name; } } else { fq_name += "/" + name; } FliImpl *fli_impl = reinterpret_cast(m_impl); new_obj = fli_impl->create_gpi_obj_from_handle(obj, name, fq_name, accType, accFullType); if (new_obj) { *hdl = new_obj; return GpiIterator::NATIVE; } else { return GpiIterator::NOT_NATIVE; } } void FliIterator::populate_handle_list(FliIterator::OneToMany childType) { switch (childType) { case FliIterator::OTM_CONSTANTS: { mtiRegionIdT parent = m_parent->get_handle(); mtiVariableIdT id; for (id = mti_FirstVarByRegion(parent); id; id = mti_NextVar()) { if (id) { m_vars.push_back(id); } } } break; case FliIterator::OTM_SIGNALS: { mtiRegionIdT parent = m_parent->get_handle(); mtiSignalIdT id; for (id = mti_FirstSignal(parent); id; id = mti_NextSignal()) { if (id) { m_sigs.push_back(id); } } } break; case FliIterator::OTM_REGIONS: { mtiRegionIdT parent = m_parent->get_handle(); mtiRegionIdT id; for (id = mti_FirstLowerRegion(parent); id; id = mti_NextRegion(id)) { if (id) { m_regs.push_back(id); } } } break; case FliIterator::OTM_SIGNAL_SUB_ELEMENTS: if (m_parent->get_type() == GPI_STRUCTURE) { mtiSignalIdT parent = m_parent->get_handle(); mtiTypeIdT type = mti_GetSignalType(parent); mtiSignalIdT *ids = mti_GetSignalSubelements(parent, NULL); LOG_DEBUG("GPI_STRUCTURE: %d fields", mti_TickLength(type)); for (int i = 0; i < mti_TickLength(type); i++) { m_sigs.push_back(ids[i]); } mti_VsimFree(ids); } else if (m_parent->get_indexable()) { FliValueObjHdl *fli_obj = reinterpret_cast(m_parent); int left = m_parent->get_range_left(); int right = m_parent->get_range_right(); if (left > right) { for (int i = left; i >= right; i--) { m_sigs.push_back( static_cast(fli_obj->get_sub_hdl(i))); } } else { for (int i = left; i <= right; i++) { m_sigs.push_back( static_cast(fli_obj->get_sub_hdl(i))); } } } break; case FliIterator::OTM_VARIABLE_SUB_ELEMENTS: if (m_parent->get_type() == GPI_STRUCTURE) { mtiVariableIdT parent = m_parent->get_handle(); mtiTypeIdT type = mti_GetVarType(parent); mtiVariableIdT *ids = mti_GetVarSubelements(parent, NULL); LOG_DEBUG("GPI_STRUCTURE: %d fields", mti_TickLength(type)); for (int i = 0; i < mti_TickLength(type); i++) { m_vars.push_back(ids[i]); } mti_VsimFree(ids); } else if (m_parent->get_indexable()) { FliValueObjHdl *fli_obj = reinterpret_cast(m_parent); int left = m_parent->get_range_left(); int right = m_parent->get_range_right(); if (left > right) { for (int i = left; i >= right; i--) { m_vars.push_back(static_cast( fli_obj->get_sub_hdl(i))); } } else { for (int i = left; i <= right; i++) { m_vars.push_back(static_cast( fli_obj->get_sub_hdl(i))); } } } break; default: LOG_WARN("Unhandled OneToMany Type (%d)", childType); } } static std::vector get_argv() { /* Necessary to implement PLUSARGS There is no function available on the FLI to obtain argc+argv directly from the simulator. To work around this we use the TCL interpreter that ships with Questa, some TCL commands, and the TCL variable `argv` to obtain the simulator argc+argv. */ std::vector argv; // obtain a reference to TCL interpreter Tcl_Interp *interp = reinterpret_cast(mti_Interp()); // get argv TCL variable auto err = mti_Cmd("return -level 0 $argv") != TCL_OK; // LCOV_EXCL_START if (err) { const char *errmsg = Tcl_GetStringResult(interp); LOG_WARN("Failed to get reference to argv: %s", errmsg); Tcl_ResetResult(interp); return argv; } // LCOV_EXCL_STOP Tcl_Obj *result = Tcl_GetObjResult(interp); Tcl_IncrRefCount(result); Tcl_ResetResult(interp); // split TCL list into length and element array int argc; Tcl_Obj **tcl_argv; err = Tcl_ListObjGetElements(interp, result, &argc, &tcl_argv) != TCL_OK; // LCOV_EXCL_START if (err) { const char *errmsg = Tcl_GetStringResult(interp); LOG_WARN("Failed to get argv elements: %s", errmsg); Tcl_DecrRefCount(result); Tcl_ResetResult(interp); return argv; } // LCOV_EXCL_STOP Tcl_ResetResult(interp); // get each argv arg and copy into internal storage for (int i = 0; i < argc; i++) { const char *arg = Tcl_GetString(tcl_argv[i]); argv.push_back(arg); } Tcl_DecrRefCount(result); return argv; } static int startup_callback(void *) { std::vector const argv_storage = get_argv(); std::vector argv_cstr; for (const auto &arg : argv_storage) { argv_cstr.push_back(arg.c_str()); } int argc = static_cast(argv_storage.size()); const char **argv = argv_cstr.data(); gpi_embed_init(argc, argv); return 0; } static int shutdown_callback(void *) { gpi_embed_end(); return 0; } void FliImpl::main() noexcept { auto startup_cb = new FliStartupCbHdl(this); auto err = startup_cb->arm(); // LCOV_EXCL_START if (err) { LOG_CRITICAL( "VHPI: Unable to register startup callback! Simulation will end."); delete startup_cb; exit(1); } // LCOV_EXCL_STOP startup_cb->set_cb_info(startup_callback, nullptr); auto shutdown_cb = new FliShutdownCbHdl(this); err = shutdown_cb->arm(); // LCOV_EXCL_START if (err) { LOG_CRITICAL( "VHPI: Unable to register shutdown callback! Simulation will end."); startup_cb->remove(); delete shutdown_cb; exit(1); } // LCOV_EXCL_STOP shutdown_cb->set_cb_info(shutdown_callback, nullptr); m_sim_finish_cb = shutdown_cb; gpi_register_impl(this); gpi_entry_point(); } static void register_impl() { auto fli_table = new FliImpl("FLI"); gpi_register_impl(fli_table); } extern "C" { COCOTBFLI_EXPORT void cocotb_init() { auto fli_table = new FliImpl("FLI"); fli_table->main(); } } GPI_ENTRY_POINT(cocotbfli, register_impl); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/fli/FliImpl.h0000644000175100017510000003723515106067236020640 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2014 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef COCOTB_FLI_IMPL_H_ #define COCOTB_FLI_IMPL_H_ #include #include #include "../gpi/gpi_priv.h" #include "_vendor/fli/mti.h" #include "exports.h" #include "gpi.h" #ifdef COCOTBFLI_EXPORTS #define COCOTBFLI_EXPORT COCOTB_EXPORT #else #define COCOTBFLI_EXPORT COCOTB_IMPORT #endif class FliImpl; class FliSignalObjHdl; class FliCbHdl : public GpiCbHdl { public: using GpiCbHdl::GpiCbHdl; }; // In FLI some callbacks require us to register a process // We use a subclass to track the process state related to the callback class FliProcessCbHdl : public FliCbHdl { public: FliProcessCbHdl(GpiImplInterface *impl) : FliCbHdl(impl) {} void set_mti_proc(mtiProcessIdT mti_proc) noexcept { m_proc_hdl = mti_proc; } virtual void release() = 0; protected: mtiProcessIdT m_proc_hdl; }; /** Maintains a cache of FliProcessCbHdl objects which can be reused. * * MTI Processes cannot be destroyed. So we never delete FliProcessCbHdl objects * and their MTI Processes and instead reuse them to prevent runaway leaks. * * We use the queue with LIFO behavior so recently used objects are reused first * leveraging cache locality. */ template class FliProcessCbHdlCache { public: FliProcessCbHdlCache(FliImpl *impl) : m_impl(impl) {} FliProcessCbHdlType *acquire() { void handle_fli_callback(void *); if (!free_list.empty()) { FliProcessCbHdlType *cb_hdl = free_list.back(); free_list.pop_back(); return cb_hdl; } else { auto cb_hdl = new FliProcessCbHdlType(m_impl); auto mti_proc = mti_CreateProcessWithPriority( nullptr, handle_fli_callback, cb_hdl, (mtiProcessPriorityT)priority); cb_hdl->set_mti_proc(mti_proc); return cb_hdl; } } void release(FliProcessCbHdlType *cb_hdl) { free_list.push_back(cb_hdl); } private: FliImpl *m_impl; std::vector free_list; }; class FliSignalCbHdl : public FliProcessCbHdl { public: using FliProcessCbHdl::FliProcessCbHdl; /** Set the signal and edge used by arm() * * MUST BE CALLED BEFORE arm()! */ void set_signal_and_edge(FliSignalObjHdl *signal, gpi_edge edge) noexcept { m_signal = signal; m_edge = edge; }; int arm() override; int run() override; int remove() override; void release() override; private: FliSignalObjHdl *m_signal; gpi_edge m_edge; }; class FliSimPhaseCbHdl : public FliProcessCbHdl { public: using FliProcessCbHdl::FliProcessCbHdl; int arm() override; int run() override; int remove() override; private: bool m_removed; }; class FliReadWriteCbHdl : public FliSimPhaseCbHdl { public: using FliSimPhaseCbHdl::FliSimPhaseCbHdl; void release() override; }; class FliNextPhaseCbHdl : public FliSimPhaseCbHdl { public: using FliSimPhaseCbHdl::FliSimPhaseCbHdl; void release() override; }; class FliReadOnlyCbHdl : public FliSimPhaseCbHdl { public: using FliSimPhaseCbHdl::FliSimPhaseCbHdl; void release() override; }; class FliStartupCbHdl : public FliCbHdl { public: FliStartupCbHdl(GpiImplInterface *impl) : FliCbHdl(impl) {} int arm() override; int run() override; int remove() override; }; class FliShutdownCbHdl : public FliCbHdl { public: FliShutdownCbHdl(GpiImplInterface *impl) : FliCbHdl(impl) {} int arm() override; int run() override; int remove() override; }; class FliTimedCbHdl : public FliProcessCbHdl { public: using FliProcessCbHdl::FliProcessCbHdl; /** Set the time used by arm() * * MUST BE CALLED BEFORE arm()! */ void set_time(uint64_t time) noexcept { m_time = time; } int arm() override; int run() override; int remove() override; void release() override; private: uint64_t m_time; bool m_removed; }; // Object Handles class FliObj { public: FliObj(int acc_type, int acc_full_type) : m_acc_type(acc_type), m_acc_full_type(acc_full_type) {} virtual ~FliObj() = default; int get_acc_type() { return m_acc_type; } int get_acc_full_type() { return m_acc_full_type; } protected: int m_acc_type; int m_acc_full_type; }; class FliObjHdl : public GpiObjHdl, public FliObj { public: FliObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype, int acc_type, int acc_full_type, bool is_const = false) : GpiObjHdl(impl, hdl, objtype, is_const), FliObj(acc_type, acc_full_type) {} int initialise(const std::string &name, const std::string &fq_name) override; }; class FliSignalObjHdl : public GpiSignalObjHdl, public FliObj { public: FliSignalObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype, bool is_const, int acc_type, int acc_full_type, bool is_var) : GpiSignalObjHdl(impl, hdl, objtype, is_const), FliObj(acc_type, acc_full_type), m_is_var(is_var) {} int initialise(const std::string &name, const std::string &fq_name) override; GpiCbHdl *register_value_change_callback(gpi_edge edge, int (*function)(void *), void *cb_data) override; bool is_variable() { return m_is_var; } protected: bool m_is_var; }; class FliValueObjHdl : public FliSignalObjHdl { public: FliValueObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype, bool is_const, int acc_type, int acc_full_type, bool is_var, mtiTypeIdT valType, mtiTypeKindT typeKind) : FliSignalObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type, is_var), m_fli_type(typeKind), m_val_type(valType) {} ~FliValueObjHdl() override { if (m_val_buff != NULL) delete[] m_val_buff; if (m_sub_hdls != NULL) mti_VsimFree(m_sub_hdls); } const char *get_signal_value_binstr() override; const char *get_signal_value_str() override; double get_signal_value_real() override; long get_signal_value_long() override; int set_signal_value(int32_t value, gpi_set_action action) override; int set_signal_value(double value, gpi_set_action action) override; int set_signal_value_str(std::string &value, gpi_set_action action) override; int set_signal_value_binstr(std::string &value, gpi_set_action action) override; void *get_sub_hdl(int index); int initialise(const std::string &name, const std::string &fq_name) override; mtiTypeKindT get_fli_typekind() { return m_fli_type; } mtiTypeIdT get_fli_typeid() { return m_val_type; } protected: mtiTypeKindT m_fli_type; mtiTypeIdT m_val_type; char *m_val_buff = nullptr; void **m_sub_hdls = nullptr; }; class FliEnumObjHdl : public FliValueObjHdl { public: FliEnumObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype, bool is_const, int acc_type, int acc_full_type, bool is_var, mtiTypeIdT valType, mtiTypeKindT typeKind) : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type, is_var, valType, typeKind) {} const char *get_signal_value_str() override; long get_signal_value_long() override; using FliValueObjHdl::set_signal_value; int set_signal_value(int32_t value, gpi_set_action action) override; int initialise(const std::string &name, const std::string &fq_name) override; private: char **m_value_enum = nullptr; // Do Not Free mtiInt32T m_num_enum = 0; }; class FliLogicObjHdl : public FliValueObjHdl { public: FliLogicObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype, bool is_const, int acc_type, int acc_full_type, bool is_var, mtiTypeIdT valType, mtiTypeKindT typeKind) : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type, is_var, valType, typeKind) {} ~FliLogicObjHdl() override { if (m_mti_buff != NULL) delete[] m_mti_buff; } const char *get_signal_value_binstr() override; using FliValueObjHdl::set_signal_value; int set_signal_value(int32_t value, gpi_set_action action) override; int set_signal_value_binstr(std::string &value, gpi_set_action action) override; int initialise(const std::string &name, const std::string &fq_name) override; private: char *m_mti_buff = nullptr; char **m_value_enum = nullptr; // Do Not Free mtiInt32T m_num_enum = 0; std::map m_enum_map; }; class FliIntObjHdl : public FliValueObjHdl { public: FliIntObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype, bool is_const, int acc_type, int acc_full_type, bool is_var, mtiTypeIdT valType, mtiTypeKindT typeKind) : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type, is_var, valType, typeKind) {} const char *get_signal_value_binstr() override; long get_signal_value_long() override; using FliValueObjHdl::set_signal_value; int set_signal_value(int32_t value, gpi_set_action action) override; int initialise(const std::string &name, const std::string &fq_name) override; }; class FliRealObjHdl : public FliValueObjHdl { public: FliRealObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype, bool is_const, int acc_type, int acc_full_type, bool is_var, mtiTypeIdT valType, mtiTypeKindT typeKind) : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type, is_var, valType, typeKind) {} ~FliRealObjHdl() override { if (m_mti_buff != NULL) delete m_mti_buff; } double get_signal_value_real() override; using FliValueObjHdl::set_signal_value; int set_signal_value(double value, gpi_set_action action) override; int initialise(const std::string &name, const std::string &fq_name) override; private: double *m_mti_buff = nullptr; }; class FliStringObjHdl : public FliValueObjHdl { public: FliStringObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype, bool is_const, int acc_type, int acc_full_type, bool is_var, mtiTypeIdT valType, mtiTypeKindT typeKind) : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type, is_var, valType, typeKind) {} ~FliStringObjHdl() override { if (m_mti_buff != NULL) delete[] m_mti_buff; } const char *get_signal_value_str() override; using FliValueObjHdl::set_signal_value; int set_signal_value_str(std::string &value, gpi_set_action action) override; int initialise(const std::string &name, const std::string &fq_name) override; private: char *m_mti_buff = nullptr; }; class FliIterator : public GpiIterator { public: enum OneToMany { OTM_CONSTANTS, // include Generics OTM_SIGNALS, OTM_REGIONS, OTM_SIGNAL_SUB_ELEMENTS, OTM_VARIABLE_SUB_ELEMENTS }; FliIterator(GpiImplInterface *impl, GpiObjHdl *hdl); Status next_handle(std::string &name, GpiObjHdl **hdl, void **raw_hdl) override; private: void populate_handle_list(OneToMany childType); private: static std::map> iterate_over; /* Possible mappings */ std::vector *selected; /* Mapping currently in use */ std::vector::iterator one2many; std::vector m_vars; std::vector m_sigs; std::vector m_regs; std::vector *m_currentHandles; std::vector::iterator m_iterator; }; class FliImpl : public GpiImplInterface { public: FliImpl(const std::string &name) : GpiImplInterface(name), m_timer_cache(this), m_value_change_cache(this), m_read_write_cache(this), m_read_only_cache(this), m_next_phase_cache(this) {} /* Sim related */ void sim_end() override; void get_sim_time(uint32_t *high, uint32_t *low) override; void get_sim_precision(int32_t *precision) override; const char *get_simulator_product() override; const char *get_simulator_version() override; /* Hierarchy related */ GpiObjHdl *get_child_by_name(const std::string &name, GpiObjHdl *parent) override; GpiObjHdl *get_child_by_index(int32_t index, GpiObjHdl *parent) override; GpiObjHdl *get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) override; GpiObjHdl *get_root_handle(const char *name) override; GpiIterator *iterate_handle(GpiObjHdl *obj_hdl, gpi_iterator_sel type) override; /* Callback related, these may (will) return the same handle*/ GpiCbHdl *register_timed_callback(uint64_t time, int (*function)(void *), void *cb_data) override; GpiCbHdl *register_readonly_callback(int (*function)(void *), void *cb_data) override; GpiCbHdl *register_nexttime_callback(int (*function)(void *), void *cb_data) override; GpiCbHdl *register_readwrite_callback(int (*function)(void *), void *cb_data) override; /* Method to provide strings from operation types */ const char *reason_to_string(int reason) override; /* Method to provide strings from operation types */ GpiObjHdl *create_gpi_obj_from_handle(void *hdl, const std::string &name, const std::string &fq_name, int accType, int accFullType); static bool compare_generate_labels(const std::string &a, const std::string &b); void main() noexcept; private: bool isValueConst(int kind); bool isValueLogic(mtiTypeIdT type); bool isValueChar(mtiTypeIdT type); bool isValueBoolean(mtiTypeIdT type); bool isTypeValue(int type); bool isTypeSignal(int type, int full_type); private: // We store the shutdown callback handle here so sim_end() can remove() it // if it's called. FliShutdownCbHdl *m_sim_finish_cb; // Caches for each type of callback handle. This must be associated with the // FliImpl rather than be static member of the callback handle type because // each callback handle is associated with an FliImpl. // TODO remove the FliImpl association from the callback handle types then // move these to static fields in the callback handle types. FliProcessCbHdlCache m_timer_cache; FliProcessCbHdlCache m_value_change_cache; FliProcessCbHdlCache m_read_write_cache; FliProcessCbHdlCache m_read_only_cache; FliProcessCbHdlCache m_next_phase_cache; friend FliSignalObjHdl; friend FliTimedCbHdl; friend FliSignalCbHdl; friend FliReadWriteCbHdl; friend FliReadOnlyCbHdl; friend FliNextPhaseCbHdl; }; #endif /*COCOTB_FLI_IMPL_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/fli/FliObjHdl.cpp0000644000175100017510000006272715106067236021440 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2015/16 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include #include #include #include #include "FliImpl.h" #include "_vendor/fli/acc_vhdl.h" #include "gpi.h" using std::abs; using std::to_string; GpiCbHdl *FliSignalObjHdl::register_value_change_callback( gpi_edge edge, int (*cb_func)(void *), void *cb_data) { if (m_is_var) { return NULL; } // TODO The dynamic cast here is a good reason to not declare members in // base classes. auto &cache = dynamic_cast(m_impl)->m_value_change_cache; auto cb = cache.acquire(); cb->set_signal_and_edge(this, edge); auto err = cb->arm(); // LCOV_EXCL_START if (err) { cache.release(cb); return NULL; } // LCOV_EXCL_STOP cb->set_cb_info(cb_func, cb_data); return cb; } int FliObjHdl::initialise(const std::string &name, const std::string &fq_name) { bool is_signal = (get_acc_type() == accSignal || get_acc_full_type() == accAliasSignal); mtiTypeIdT typeId; char *str; switch (get_type()) { case GPI_STRUCTURE: if (is_signal) { typeId = mti_GetSignalType(get_handle()); } else { typeId = mti_GetVarType(get_handle()); } m_num_elems = mti_GetNumRecordElements(typeId); break; case GPI_GENARRAY: m_indexable = true; // fall through case GPI_MODULE: m_num_elems = 1; break; default: LOG_ERROR("Invalid object type for FliObjHdl. (%s (%s))", name.c_str(), get_type_str()); return -1; } str = mti_GetPrimaryName(get_handle()); if (str != NULL) m_definition_name = str; str = mti_GetRegionSourceName(get_handle()); if (str != NULL) m_definition_file = str; return GpiObjHdl::initialise(name, fq_name); } int FliSignalObjHdl::initialise(const std::string &name, const std::string &fq_name) { return GpiObjHdl::initialise(name, fq_name); } int FliValueObjHdl::initialise(const std::string &name, const std::string &fq_name) { if (get_type() == GPI_ARRAY) { m_range_left = mti_TickLeft(m_val_type); m_range_right = mti_TickRight(m_val_type); m_range_dir = static_cast(mti_TickDir(m_val_type)); m_num_elems = mti_TickLength(m_val_type); m_indexable = true; } return FliSignalObjHdl::initialise(name, fq_name); } const char *FliValueObjHdl::get_signal_value_binstr() { LOG_ERROR( "Getting signal/variable value as binstr not supported for %s of type " "%d", m_fullname.c_str(), m_type); return NULL; } const char *FliValueObjHdl::get_signal_value_str() { LOG_ERROR( "Getting signal/variable value as str not supported for %s of type %d", m_fullname.c_str(), m_type); return NULL; } double FliValueObjHdl::get_signal_value_real() { LOG_ERROR( "Getting signal/variable value as double not supported for %s of type " "%d", m_fullname.c_str(), m_type); return -1; } long FliValueObjHdl::get_signal_value_long() { LOG_ERROR( "Getting signal/variable value as long not supported for %s of type %d", m_fullname.c_str(), m_type); return -1; } int FliValueObjHdl::set_signal_value(int32_t, gpi_set_action) { LOG_ERROR( "Setting signal/variable value via int32_t not supported for %s of " "type %d", m_fullname.c_str(), m_type); return -1; } int FliValueObjHdl::set_signal_value_binstr(std::string &, gpi_set_action) { LOG_ERROR( "Setting signal/variable value via string not supported for %s of type " "%d", m_fullname.c_str(), m_type); return -1; } int FliValueObjHdl::set_signal_value_str(std::string &, gpi_set_action) { LOG_ERROR( "Setting signal/variable value via string not supported for %s of type " "%d", m_fullname.c_str(), m_type); return -1; } int FliValueObjHdl::set_signal_value(double, gpi_set_action) { LOG_ERROR( "Setting signal/variable value via double not supported for %s of type " "%d", m_fullname.c_str(), m_type); return -1; } void *FliValueObjHdl::get_sub_hdl(int index) { if (!m_indexable) return NULL; if (m_sub_hdls == NULL) { if (m_is_var) { m_sub_hdls = (void **)mti_GetVarSubelements( get_handle(), NULL); } else { m_sub_hdls = (void **)mti_GetSignalSubelements( get_handle(), NULL); } } int idx; if (m_range_left > m_range_right) { idx = m_range_left - index; } else { idx = index - m_range_left; } if (idx < 0 || idx >= m_num_elems) return NULL; else return m_sub_hdls[idx]; } int FliEnumObjHdl::initialise(const std::string &name, const std::string &fq_name) { m_num_elems = 1; m_value_enum = mti_GetEnumValues(m_val_type); m_num_enum = mti_TickLength(m_val_type); return FliValueObjHdl::initialise(name, fq_name); } const char *FliEnumObjHdl::get_signal_value_str() { if (m_is_var) { return m_value_enum[mti_GetVarValue(get_handle())]; } else { return m_value_enum[mti_GetSignalValue(get_handle())]; } } long FliEnumObjHdl::get_signal_value_long() { if (m_is_var) { return (long)mti_GetVarValue(get_handle()); } else { return (long)mti_GetSignalValue(get_handle()); } } int FliEnumObjHdl::set_signal_value(const int32_t value, const gpi_set_action action) { if (value > m_num_enum || value < 0) { LOG_ERROR( "Attempted to set an enum with range [0,%d] with invalid value %d!", m_num_enum, value); return -1; } if (m_is_var) { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetVarValue(get_handle(), static_cast(value)); return 0; case GPI_FORCE: LOG_ERROR("Forcing VHDL variables is not supported by the FLI"); return -1; case GPI_RELEASE: LOG_ERROR( "Releasing VHDL variables is not supported by the FLI"); return -1; default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } else { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetSignalValue(get_handle(), static_cast(value)); return 0; case GPI_FORCE: { std::string value_str = "10#"; value_str.append(to_string(abs(value))); return !mti_ForceSignal(get_handle(), const_cast(value_str.c_str()), 0, MTI_FORCE_FREEZE, -1, -1); } case GPI_RELEASE: return !mti_ReleaseSignal(get_handle()); default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } } int FliLogicObjHdl::initialise(const std::string &name, const std::string &fq_name) { switch (m_fli_type) { case MTI_TYPE_ENUM: m_num_elems = 1; m_value_enum = mti_GetEnumValues(m_val_type); m_num_enum = mti_TickLength(m_val_type); break; case MTI_TYPE_ARRAY: { mtiTypeIdT elemType = mti_GetArrayElementType(m_val_type); m_range_left = mti_TickLeft(m_val_type); m_range_right = mti_TickRight(m_val_type); m_range_dir = static_cast(mti_TickDir(m_val_type)); m_num_elems = mti_TickLength(m_val_type); m_indexable = true; m_value_enum = mti_GetEnumValues(elemType); m_num_enum = mti_TickLength(elemType); m_mti_buff = new char[m_num_elems + 1]; } break; default: LOG_ERROR("Object type is not 'logic' for %s (%d)", name.c_str(), m_fli_type); return -1; } for (mtiInt32T i = 0; i < m_num_enum; i++) { m_enum_map[m_value_enum[i][1]] = i; // enum is of the format 'U' or '0', etc. } m_val_buff = new char[m_num_elems + 1]; m_val_buff[m_num_elems] = '\0'; return FliValueObjHdl::initialise(name, fq_name); } const char *FliLogicObjHdl::get_signal_value_binstr() { switch (m_fli_type) { case MTI_TYPE_ENUM: if (m_is_var) { m_val_buff[0] = m_value_enum[mti_GetVarValue(get_handle())] [1]; } else { m_val_buff[0] = m_value_enum[mti_GetSignalValue(get_handle())] [1]; } break; case MTI_TYPE_ARRAY: { if (m_is_var) { mti_GetArrayVarValue(get_handle(), m_mti_buff); } else { mti_GetArraySignalValue(get_handle(), m_mti_buff); } for (int i = 0; i < m_num_elems; i++) { m_val_buff[i] = m_value_enum[(int)m_mti_buff[i]][1]; } } break; default: LOG_ERROR("Object type is not 'logic' for %s (%d)", m_name.c_str(), m_fli_type); return NULL; } LOG_DEBUG("Retrieved \"%s\" for value object %s", m_val_buff, m_name.c_str()); return m_val_buff; } int FliLogicObjHdl::set_signal_value(const int32_t value, const gpi_set_action action) { if (m_fli_type == MTI_TYPE_ENUM) { mtiInt32T enumVal = value ? m_enum_map['1'] : m_enum_map['0']; if (m_is_var) { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetVarValue(get_handle(), enumVal); return 0; case GPI_FORCE: LOG_ERROR( "Forcing VHDL variables is not supported by the FLI"); return -1; case GPI_RELEASE: LOG_ERROR( "Releasing VHDL variables is not supported by the FLI"); return -1; default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } else { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetSignalValue(get_handle(), enumVal); return 0; case GPI_FORCE: { char const *value_str = (value ? "2#1" : "2#0"); return !mti_ForceSignal(get_handle(), const_cast(value_str), 0, MTI_FORCE_FREEZE, -1, -1); } case GPI_RELEASE: return !mti_ReleaseSignal(get_handle()); default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } } else { for (int i = 0, idx = m_num_elems - 1; i < m_num_elems; i++, idx--) { mtiInt32T enumVal = value & (1 << i) ? m_enum_map['1'] : m_enum_map['0']; m_mti_buff[idx] = (char)enumVal; } if (m_is_var) { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetVarValue(get_handle(), (mtiLongT)m_mti_buff); return 0; case GPI_FORCE: LOG_ERROR( "Forcing VHDL variables is not supported by the FLI"); return -1; case GPI_RELEASE: LOG_ERROR( "Releasing VHDL variables is not supported by the FLI"); return -1; default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } else { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetSignalValue(get_handle(), (mtiLongT)m_mti_buff); return 0; case GPI_FORCE: { std::string value_str = "2#"; for (int idx = m_num_elems - 1; idx >= 0; idx--) { value_str.append((value & (1 << idx)) ? "1" : "0"); } return !mti_ForceSignal( get_handle(), const_cast(value_str.c_str()), 0, MTI_FORCE_FREEZE, -1, -1); } case GPI_RELEASE: return !mti_ReleaseSignal(get_handle()); default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } } } int FliLogicObjHdl::set_signal_value_binstr(std::string &value, const gpi_set_action action) { if (m_fli_type == MTI_TYPE_ENUM) { if (value.length() != 1) { LOG_ERROR( "FLI: Unable to set logic vector due to the string having " "incorrect length. Length of %d needs to be 1", value.length()); return -1; } mtiInt32T enumVal = m_enum_map[value.c_str()[0]]; if (m_is_var) { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetVarValue(get_handle(), enumVal); return 0; case GPI_FORCE: LOG_ERROR( "Forcing VHDL variables is not supported by the FLI"); return -1; case GPI_RELEASE: LOG_ERROR( "Releasing VHDL variables is not supported by the FLI"); return -1; default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } else { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetSignalValue(get_handle(), enumVal); return 0; case GPI_FORCE: { std::string value_str = "2#"; value_str.append(value); return !mti_ForceSignal( get_handle(), const_cast(value_str.c_str()), 0, MTI_FORCE_FREEZE, -1, -1); } case GPI_RELEASE: return !mti_ReleaseSignal(get_handle()); default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } } else { if ((int)value.length() != m_num_elems) { LOG_ERROR( "FLI: Unable to set logic vector due to the string having " "incorrect length. Length of %d needs to be %d", value.length(), m_num_elems); return -1; } int i = 0; for (auto valIter = value.begin(); (valIter != value.end()) && (i < m_num_elems); valIter++, i++) { auto enumVal = m_enum_map[*valIter]; m_mti_buff[i] = (char)enumVal; } if (m_is_var) { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetVarValue(get_handle(), (mtiLongT)m_mti_buff); return 0; case GPI_FORCE: LOG_ERROR( "Forcing VHDL variables is not supported by the FLI"); return -1; case GPI_RELEASE: LOG_ERROR( "Releasing VHDL variables is not supported by the FLI"); return -1; default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } else { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetSignalValue(get_handle(), (mtiLongT)m_mti_buff); return 0; case GPI_FORCE: { std::string value_str = "2#"; value_str.append(value); return !mti_ForceSignal( get_handle(), const_cast(value_str.c_str()), 0, MTI_FORCE_FREEZE, -1, -1); } case GPI_RELEASE: return !mti_ReleaseSignal(get_handle()); default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } } } int FliIntObjHdl::initialise(const std::string &name, const std::string &fq_name) { m_num_elems = 1; m_val_buff = new char[33]; // Integers are always 32-bits m_val_buff[m_num_elems] = '\0'; return FliValueObjHdl::initialise(name, fq_name); } const char *FliIntObjHdl::get_signal_value_binstr() { mtiInt32T val; if (m_is_var) { val = mti_GetVarValue(get_handle()); } else { val = mti_GetSignalValue(get_handle()); } unsigned long tmp = static_cast( val); // only way to keep next line from warning std::bitset<32> value{tmp}; std::string bin_str = value.to_string(); snprintf(m_val_buff, 33, "%s", bin_str.c_str()); return m_val_buff; } long FliIntObjHdl::get_signal_value_long() { mtiInt32T value; if (m_is_var) { value = mti_GetVarValue(get_handle()); } else { value = mti_GetSignalValue(get_handle()); } return (long)value; } int FliIntObjHdl::set_signal_value(const int32_t value, const gpi_set_action action) { if (m_is_var) { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetVarValue(get_handle(), static_cast(value)); return 0; case GPI_FORCE: LOG_ERROR("Forcing VHDL variables is not supported by the FLI"); return -1; case GPI_RELEASE: LOG_ERROR( "Releasing VHDL variables is not supported by the FLI"); return -1; default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } else { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetSignalValue(get_handle(), static_cast(value)); return 0; case GPI_FORCE: { std::string value_str; if (value < 0) { value_str.append("-"); } value_str.append("10#"); value_str.append(to_string(abs(value))); return !mti_ForceSignal(get_handle(), const_cast(value_str.c_str()), 0, MTI_FORCE_FREEZE, -1, -1); } case GPI_RELEASE: return !mti_ReleaseSignal(get_handle()); default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } } int FliRealObjHdl::initialise(const std::string &name, const std::string &fq_name) { m_num_elems = 1; m_mti_buff = new double; return FliValueObjHdl::initialise(name, fq_name); } double FliRealObjHdl::get_signal_value_real() { if (m_is_var) { mti_GetVarValueIndirect(get_handle(), m_mti_buff); } else { mti_GetSignalValueIndirect(get_handle(), m_mti_buff); } LOG_DEBUG("Retrieved \"%f\" for value object %s", m_mti_buff[0], m_name.c_str()); return m_mti_buff[0]; } int FliRealObjHdl::set_signal_value(const double value, const gpi_set_action action) { m_mti_buff[0] = value; if (m_is_var) { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetVarValue(get_handle(), (mtiLongT)m_mti_buff); return 0; case GPI_FORCE: LOG_ERROR("Forcing VHDL variables is not supported by the FLI"); return -1; case GPI_RELEASE: LOG_ERROR( "Releasing VHDL variables is not supported by the FLI"); return -1; default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } else { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetSignalValue(get_handle(), (mtiLongT)m_mti_buff); return 0; case GPI_FORCE: { LOG_ERROR("Cannot force a real signal with the FLI"); return -1; } case GPI_RELEASE: mti_ReleaseSignal(get_handle()); return 0; default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } } int FliStringObjHdl::initialise(const std::string &name, const std::string &fq_name) { m_range_left = mti_TickLeft(m_val_type); m_range_right = mti_TickRight(m_val_type); m_range_dir = static_cast(mti_TickDir(m_val_type)); m_num_elems = mti_TickLength(m_val_type); m_indexable = true; m_mti_buff = new char[m_num_elems]; m_val_buff = new char[m_num_elems + 1]; m_val_buff[m_num_elems] = '\0'; return FliValueObjHdl::initialise(name, fq_name); } const char *FliStringObjHdl::get_signal_value_str() { if (m_is_var) { mti_GetArrayVarValue(get_handle(), m_mti_buff); } else { mti_GetArraySignalValue(get_handle(), m_mti_buff); } strncpy(m_val_buff, m_mti_buff, static_cast(m_num_elems)); LOG_DEBUG("Retrieved \"%s\" for value object %s", m_val_buff, m_name.c_str()); return m_val_buff; } int FliStringObjHdl::set_signal_value_str(std::string &value, const gpi_set_action action) { strncpy(m_mti_buff, value.c_str(), static_cast(m_num_elems)); if (m_is_var) { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetVarValue(get_handle(), (mtiLongT)m_mti_buff); return 0; case GPI_FORCE: LOG_ERROR("Forcing VHDL variables is not supported by the FLI"); return -1; case GPI_RELEASE: LOG_ERROR( "Releasing VHDL variables is not supported by the FLI"); return -1; default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } else { switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: mti_SetSignalValue(get_handle(), (mtiLongT)m_mti_buff); return 0; case GPI_FORCE: { return !mti_ForceSignal(get_handle(), const_cast(value.c_str()), 0, MTI_FORCE_FREEZE, -1, -1); } case GPI_RELEASE: return !mti_ReleaseSignal(get_handle()); default: LOG_ERROR("Unknown set value action (%d)", action); return -1; } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3487027 cocotb-2.0.1/src/cocotb/share/lib/gpi/0000755000175100017510000000000015106070715017122 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/gpi/GpiCbHdl.cpp0000644000175100017510000000265615106067236021257 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include "gpi.h" #include "gpi_priv.h" const char *GpiObjHdl::get_name_str() { return m_name.c_str(); } const char *GpiObjHdl::get_fullname_str() { return m_fullname.c_str(); } const std::string &GpiObjHdl::get_fullname() { return m_fullname; } const char *GpiObjHdl::get_type_str() { #define CASE_OPTION(_X) \ case _X: \ ret = #_X; \ break const char *ret; switch (m_type) { CASE_OPTION(GPI_UNKNOWN); CASE_OPTION(GPI_MEMORY); CASE_OPTION(GPI_MODULE); CASE_OPTION(GPI_ARRAY); CASE_OPTION(GPI_ENUM); CASE_OPTION(GPI_STRUCTURE); CASE_OPTION(GPI_REAL); CASE_OPTION(GPI_INTEGER); CASE_OPTION(GPI_STRING); CASE_OPTION(GPI_GENARRAY); CASE_OPTION(GPI_PACKAGE); CASE_OPTION(GPI_LOGIC); CASE_OPTION(GPI_LOGIC_ARRAY); default: ret = "unknown"; } return ret; } const std::string &GpiObjHdl::get_name() { return m_name; } /* Genertic base clss implementations */ bool GpiHdl::is_this_impl(GpiImplInterface *impl) { return impl == this->m_impl; } int GpiObjHdl::initialise(const std::string &name, const std::string &fq_name) { m_name = name; m_fullname = fq_name; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/gpi/GpiCommon.cpp0000644000175100017510000004773715106067236021544 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include #include #include #include #include #include #include "gpi.h" #include "gpi_priv.h" using namespace std; static vector registered_impls; #ifdef SINGLETON_HANDLES class GpiHandleStore { public: GpiObjHdl *check_and_store(GpiObjHdl *hdl) { std::map::iterator it; const std::string &name = hdl->get_fullname(); LOG_DEBUG("Checking %s exists", name.c_str()); it = handle_map.find(name); if (it == handle_map.end()) { handle_map[name] = hdl; return hdl; } else { LOG_DEBUG("Found duplicate %s", name.c_str()); delete hdl; return it->second; } } uint64_t handle_count() { return handle_map.size(); } void clear() { std::map::iterator it; // Delete the object handles before clearing the map for (it = handle_map.begin(); it != handle_map.end(); it++) { delete (it->second); } handle_map.clear(); } private: std::map handle_map; }; static GpiHandleStore unique_handles; #define CHECK_AND_STORE(_x) unique_handles.check_and_store(_x) #define CLEAR_STORE() unique_handles.clear() #else #define CHECK_AND_STORE(_x) _x #define CLEAR_STORE() (void)0 // No-op #endif static bool sim_ending = false; static size_t gpi_print_registered_impl() { vector::iterator iter; for (iter = registered_impls.begin(); iter != registered_impls.end(); iter++) { LOG_INFO("%s registered", (*iter)->get_name_c()); } return registered_impls.size(); } int gpi_register_impl(GpiImplInterface *func_tbl) { vector::iterator iter; for (iter = registered_impls.begin(); iter != registered_impls.end(); iter++) { if ((*iter)->get_name_s() == func_tbl->get_name_s()) { LOG_WARN("%s already registered, check GPI_EXTRA", func_tbl->get_name_c()); return -1; } } registered_impls.push_back(func_tbl); return 0; } bool gpi_has_registered_impl() { return registered_impls.size() > 0; } void gpi_embed_init(int argc, char const *const *argv) { if (embed_sim_init(argc, argv)) { gpi_embed_end(); } } void gpi_embed_end() { embed_sim_event("Simulator shut down prematurely"); gpi_sim_end(); } void gpi_sim_end() { if (!sim_ending) { registered_impls[0]->sim_end(); sim_ending = true; } } void gpi_cleanup(void) { CLEAR_STORE(); embed_sim_cleanup(); } static void gpi_load_libs(std::vector to_load) { std::vector::iterator iter; for (iter = to_load.begin(); iter != to_load.end(); iter++) { std::string arg = *iter; auto const idx = arg.rfind( ':'); // find from right since path could contain colons (Windows) if (idx == std::string::npos) { // no colon in the string printf("cocotb: Error parsing GPI_EXTRA %s\n", arg.c_str()); exit(1); } std::string const lib_name = arg.substr(0, idx); std::string const func_name = arg.substr(idx + 1, std::string::npos); void *lib_handle = utils_dyn_open(lib_name.c_str()); if (!lib_handle) { printf("cocotb: Error loading shared library %s\n", lib_name.c_str()); exit(1); } void *entry_point = utils_dyn_sym(lib_handle, func_name.c_str()); if (!entry_point) { char const *fmt = "cocotb: Unable to find entry point %s for shared library " "%s\n%s"; char const *msg = " Perhaps you meant to use `,` instead of `:` to " "separate library names, as this changed in cocotb 1.4?\n"; printf(fmt, func_name.c_str(), lib_name.c_str(), msg); exit(1); } layer_entry_func new_lib_entry = (layer_entry_func)entry_point; new_lib_entry(); } } void gpi_entry_point() { const char *log_level = getenv("GPI_LOG_LEVEL"); if (log_level) { static const std::map log_level_str_table = { {"CRITICAL", GPI_CRITICAL}, {"ERROR", GPI_ERROR}, {"WARNING", GPI_WARNING}, {"INFO", GPI_INFO}, {"DEBUG", GPI_DEBUG}, {"TRACE", GPI_TRACE}}; auto it = log_level_str_table.find(log_level); if (it != log_level_str_table.end()) { gpi_native_logger_set_level(it->second); } else { // LCOV_EXCL_START LOG_ERROR("Invalid log level: %s", log_level); // LCOV_EXCL_STOP } } /* Lets look at what other libs we were asked to load too */ char *lib_env = getenv("GPI_EXTRA"); if (lib_env) { std::string lib_list = lib_env; std::string const delim = ","; std::vector to_load; size_t e_pos = 0; while (std::string::npos != (e_pos = lib_list.find(delim))) { std::string lib = lib_list.substr(0, e_pos); lib_list.erase(0, e_pos + delim.length()); to_load.push_back(lib); } if (lib_list.length()) { to_load.push_back(lib_list); } gpi_load_libs(to_load); } /* Finally embed Python */ embed_init_python(); gpi_print_registered_impl(); } void gpi_get_sim_time(uint32_t *high, uint32_t *low) { registered_impls[0]->get_sim_time(high, low); } void gpi_get_sim_precision(int32_t *precision) { /* We clamp to sensible values here, 1e-15 min and 1e3 max */ int32_t val; registered_impls[0]->get_sim_precision(&val); if (val > 2) val = 2; if (val < -15) val = -15; *precision = val; } const char *gpi_get_simulator_product() { return registered_impls[0]->get_simulator_product(); } const char *gpi_get_simulator_version() { return registered_impls[0]->get_simulator_version(); } gpi_sim_hdl gpi_get_root_handle(const char *name) { /* May need to look over all the implementations that are registered to find this handle */ vector::iterator iter; GpiObjHdl *hdl = NULL; LOG_DEBUG("Looking for root handle '%s' over %d implementations", name, registered_impls.size()); for (iter = registered_impls.begin(); iter != registered_impls.end(); iter++) { if ((hdl = (*iter)->get_root_handle(name))) { LOG_DEBUG("Got a Root handle (%s) back from %s", hdl->get_name_str(), (*iter)->get_name_c()); break; } } if (hdl) return CHECK_AND_STORE(hdl); else { LOG_ERROR("No root handle found"); return hdl; } } static GpiObjHdl *gpi_get_child_by_name(GpiObjHdl *parent, const std::string &name, GpiImplInterface *skip_impl) { LOG_DEBUG("Searching for %s", name.c_str()); // check parent impl *first* if it's not skipped if (!skip_impl || (skip_impl != parent->m_impl)) { auto hdl = parent->m_impl->get_child_by_name(name, parent); if (hdl) { return CHECK_AND_STORE(hdl); } } // iterate over all registered impls to see if we can get the signal for (auto iter = registered_impls.begin(); iter != registered_impls.end(); iter++) { // check if impl is skipped if (skip_impl && (skip_impl == (*iter))) { LOG_DEBUG("Skipping %s implementation", (*iter)->get_name_c()); continue; } // already checked parent implementation if ((*iter) == parent->m_impl) { LOG_DEBUG("Already checked %s implementation", (*iter)->get_name_c()); continue; } LOG_DEBUG("Checking if %s is native through implementation %s", name.c_str(), (*iter)->get_name_c()); /* If the current interface is not the same as the one that we are going to query then append the name we are looking for to the parent, such as .name. This is so that its entity can be seen discovered even if the parents implementation is not the same as the one that we are querying through */ auto hdl = (*iter)->get_child_by_name(name, parent); if (hdl) { LOG_DEBUG("Found %s via %s", name.c_str(), (*iter)->get_name_c()); return CHECK_AND_STORE(hdl); } } return NULL; } static GpiObjHdl *gpi_get_child_from_handle(GpiObjHdl *parent, void *raw_hdl, GpiImplInterface *skip_impl) { vector::iterator iter; GpiObjHdl *hdl = NULL; for (iter = registered_impls.begin(); iter != registered_impls.end(); iter++) { if (skip_impl && (skip_impl == (*iter))) { LOG_DEBUG("Skipping %s implementation", (*iter)->get_name_c()); continue; } if ((hdl = (*iter)->get_child_from_handle(raw_hdl, parent))) { LOG_DEBUG("Found %s via %s", hdl->get_name_str(), (*iter)->get_name_c()); break; } } if (hdl) return CHECK_AND_STORE(hdl); else { LOG_WARN( "Failed to convert a raw handle to valid object via any registered " "implementation"); return hdl; } } gpi_sim_hdl gpi_get_handle_by_name(gpi_sim_hdl base, const char *name, gpi_discovery discovery_method = GPI_AUTO) { std::string s_name = name; GpiObjHdl *hdl = NULL; if (discovery_method == GPI_AUTO) { hdl = gpi_get_child_by_name(base, s_name, NULL); if (!hdl) { LOG_DEBUG( "Failed to find a handle named %s via any registered " "implementation", name); } } else if (discovery_method == GPI_NATIVE) { /* Explicitly does not try to cross language boundaries. * This can be useful when interfacing with * simulators that misbehave during (optional) signal discovery. */ hdl = base->m_impl->get_child_by_name(name, base); if (!hdl) { LOG_DEBUG( "Failed to find a handle named %s via native implementation", name); } } return hdl; } gpi_sim_hdl gpi_get_handle_by_index(gpi_sim_hdl base, int32_t index) { GpiObjHdl *hdl = NULL; GpiImplInterface *intf = base->m_impl; /* Shouldn't need to iterate over interfaces because indexing into a handle * shouldn't cross the interface boundaries. * * NOTE: IUS's VPI interface returned valid VHDL handles, but then couldn't * use the handle properly. */ LOG_DEBUG("Checking if index %d native through implementation %s ", index, intf->get_name_c()); hdl = intf->get_child_by_index(index, base); if (hdl) return CHECK_AND_STORE(hdl); else { LOG_WARN( "Failed to find a handle at index %d via any registered " "implementation", index); return hdl; } } gpi_iterator_hdl gpi_iterate(gpi_sim_hdl obj_hdl, gpi_iterator_sel type) { if (type == GPI_PACKAGE_SCOPES) { if (obj_hdl != NULL) { LOG_ERROR("Cannot iterate over package from non-NULL handles"); return NULL; } vector::iterator implIter; LOG_DEBUG("Looking for packages over %d implementations", registered_impls.size()); for (implIter = registered_impls.begin(); implIter != registered_impls.end(); implIter++) { GpiIterator *iter = (*implIter)->iterate_handle(NULL, GPI_PACKAGE_SCOPES); if (iter != NULL) return iter; } return NULL; } GpiIterator *iter = obj_hdl->m_impl->iterate_handle(obj_hdl, type); if (!iter) { return NULL; } return iter; } gpi_sim_hdl gpi_next(gpi_iterator_hdl iter) { std::string name; GpiObjHdl *parent = iter->get_parent(); while (true) { GpiObjHdl *next = NULL; void *raw_hdl = NULL; GpiIterator::Status ret = iter->next_handle(name, &next, &raw_hdl); switch (ret) { case GpiIterator::NATIVE: LOG_DEBUG("Create a native handle"); return CHECK_AND_STORE(next); case GpiIterator::NATIVE_NO_NAME: LOG_DEBUG("Unable to fully setup handle, skipping"); continue; case GpiIterator::NOT_NATIVE: LOG_DEBUG( "Found a name but unable to create via native " "implementation, trying others"); next = gpi_get_child_by_name(parent, name, iter->m_impl); if (next) { return next; } LOG_WARN( "Unable to create %s via any registered implementation", name.c_str()); continue; case GpiIterator::NOT_NATIVE_NO_NAME: LOG_DEBUG( "Found an object but not accessible via %s, trying others", iter->m_impl->get_name_c()); next = gpi_get_child_from_handle(parent, raw_hdl, iter->m_impl); if (next) { return next; } continue; case GpiIterator::END: LOG_DEBUG("Reached end of iterator"); delete iter; return NULL; } } } const char *gpi_get_definition_name(gpi_sim_hdl obj_hdl) { return obj_hdl->get_definition_name(); } const char *gpi_get_definition_file(gpi_sim_hdl obj_hdl) { return obj_hdl->get_definition_file(); } static std::string g_binstr; const char *gpi_get_signal_value_binstr(gpi_sim_hdl sig_hdl) { GpiSignalObjHdl *obj_hdl = static_cast(sig_hdl); g_binstr = obj_hdl->get_signal_value_binstr(); std::transform(g_binstr.begin(), g_binstr.end(), g_binstr.begin(), ::toupper); return g_binstr.c_str(); } const char *gpi_get_signal_value_str(gpi_sim_hdl sig_hdl) { GpiSignalObjHdl *obj_hdl = static_cast(sig_hdl); return obj_hdl->get_signal_value_str(); } double gpi_get_signal_value_real(gpi_sim_hdl sig_hdl) { GpiSignalObjHdl *obj_hdl = static_cast(sig_hdl); return obj_hdl->get_signal_value_real(); } long gpi_get_signal_value_long(gpi_sim_hdl sig_hdl) { GpiSignalObjHdl *obj_hdl = static_cast(sig_hdl); return obj_hdl->get_signal_value_long(); } const char *gpi_get_signal_name_str(gpi_sim_hdl sig_hdl) { GpiSignalObjHdl *obj_hdl = static_cast(sig_hdl); return obj_hdl->get_name_str(); } const char *gpi_get_signal_type_str(gpi_sim_hdl obj_hdl) { return obj_hdl->get_type_str(); } gpi_objtype gpi_get_object_type(gpi_sim_hdl obj_hdl) { return obj_hdl->get_type(); } int gpi_is_constant(gpi_sim_hdl obj_hdl) { if (obj_hdl->get_const()) return 1; return 0; } int gpi_is_indexable(gpi_sim_hdl obj_hdl) { if (obj_hdl->get_indexable()) return 1; return 0; } void gpi_set_signal_value_int(gpi_sim_hdl sig_hdl, int32_t value, gpi_set_action action) { GpiSignalObjHdl *obj_hdl = static_cast(sig_hdl); obj_hdl->set_signal_value(value, action); } void gpi_set_signal_value_binstr(gpi_sim_hdl sig_hdl, const char *binstr, gpi_set_action action) { std::string value = binstr; GpiSignalObjHdl *obj_hdl = static_cast(sig_hdl); obj_hdl->set_signal_value_binstr(value, action); } void gpi_set_signal_value_str(gpi_sim_hdl sig_hdl, const char *str, gpi_set_action action) { std::string value = str; GpiSignalObjHdl *obj_hdl = static_cast(sig_hdl); obj_hdl->set_signal_value_str(value, action); } void gpi_set_signal_value_real(gpi_sim_hdl sig_hdl, double value, gpi_set_action action) { GpiSignalObjHdl *obj_hdl = static_cast(sig_hdl); obj_hdl->set_signal_value(value, action); } int gpi_get_num_elems(gpi_sim_hdl obj_hdl) { return obj_hdl->get_num_elems(); } int gpi_get_range_left(gpi_sim_hdl obj_hdl) { return obj_hdl->get_range_left(); } int gpi_get_range_right(gpi_sim_hdl obj_hdl) { return obj_hdl->get_range_right(); } gpi_range_dir gpi_get_range_dir(gpi_sim_hdl obj_hdl) { return obj_hdl->get_range_dir(); } gpi_cb_hdl gpi_register_value_change_callback(int (*gpi_function)(void *), void *gpi_cb_data, gpi_sim_hdl sig_hdl, gpi_edge edge) { GpiSignalObjHdl *signal_hdl = static_cast(sig_hdl); /* Do something based on int & GPI_RISING | GPI_FALLING */ GpiCbHdl *gpi_hdl = signal_hdl->register_value_change_callback( edge, gpi_function, gpi_cb_data); if (!gpi_hdl) { LOG_ERROR("Failed to register a value change callback"); return NULL; } else { return gpi_hdl; } } gpi_cb_hdl gpi_register_timed_callback(int (*gpi_function)(void *), void *gpi_cb_data, uint64_t time) { // It should not matter which implementation we use for this so just pick // the first one GpiCbHdl *gpi_hdl = registered_impls[0]->register_timed_callback( time, gpi_function, gpi_cb_data); if (!gpi_hdl) { LOG_ERROR("Failed to register a timed callback"); return NULL; } else { return gpi_hdl; } } gpi_cb_hdl gpi_register_readonly_callback(int (*gpi_function)(void *), void *gpi_cb_data) { // It should not matter which implementation we use for this so just pick // the first one GpiCbHdl *gpi_hdl = registered_impls[0]->register_readonly_callback( gpi_function, gpi_cb_data); if (!gpi_hdl) { LOG_ERROR("Failed to register a readonly callback"); return NULL; } else { return gpi_hdl; } } gpi_cb_hdl gpi_register_nexttime_callback(int (*gpi_function)(void *), void *gpi_cb_data) { // It should not matter which implementation we use for this so just pick // the first one GpiCbHdl *gpi_hdl = registered_impls[0]->register_nexttime_callback( gpi_function, gpi_cb_data); if (!gpi_hdl) { LOG_ERROR("Failed to register a nexttime callback"); return NULL; } else { return gpi_hdl; } } gpi_cb_hdl gpi_register_readwrite_callback(int (*gpi_function)(void *), void *gpi_cb_data) { // It should not matter which implementation we use for this so just pick // the first one GpiCbHdl *gpi_hdl = registered_impls[0]->register_readwrite_callback( gpi_function, gpi_cb_data); if (!gpi_hdl) { LOG_ERROR("Failed to register a readwrite callback"); return NULL; } else { return gpi_hdl; } } int gpi_remove_cb(gpi_cb_hdl cb_hdl) { return cb_hdl->remove(); } void gpi_get_cb_info(gpi_cb_hdl cb_hdl, int (**cb_func)(void *), void **cb_data) { cb_hdl->get_cb_info(cb_func, cb_data); } const char *GpiImplInterface::get_name_c() { return m_name.c_str(); } const string &GpiImplInterface::get_name_s() { return m_name; } void gpi_to_user() { LOG_TRACE("Passing control to GPI user"); } void gpi_to_simulator() { if (sim_ending) { gpi_cleanup(); } LOG_TRACE("Returning control to simulator"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/gpi/gpi_priv.h0000644000175100017510000002310115106067236021113 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef COCOTB_GPI_PRIV_H_ #define COCOTB_GPI_PRIV_H_ #include #ifdef GPI_EXPORTS #define GPI_EXPORT COCOTB_EXPORT #else #define GPI_EXPORT COCOTB_IMPORT #endif #include #include #include class GpiCbHdl; class GpiImplInterface; class GpiIterator; class GpiCbHdl; /* Base GPI class others are derived from */ class GPI_EXPORT GpiHdl { public: GpiHdl(GpiImplInterface *impl, void *hdl = NULL) : m_impl(impl), m_obj_hdl(hdl) {} virtual ~GpiHdl() = default; template T get_handle() const { return static_cast(m_obj_hdl); } private: GpiHdl() {} // Disable default constructor public: GpiImplInterface *m_impl; // VPI/VHPI/FLI routines bool is_this_impl(GpiImplInterface *impl); // Is the passed interface the // one this object uses? protected: void *m_obj_hdl; }; /* GPI object handle, maps to a simulation object */ // An object is any item in the hierarchy // Provides methods for iterating through children or finding by name // Initial object is returned by call to GpiImplInterface::get_root_handle() // Subsequent operations to get children go through this handle. // GpiObjHdl::get_handle_by_name/get_handle_by_index are really factories // that construct an object derived from GpiSignalObjHdl or GpiObjHdl class GPI_EXPORT GpiObjHdl : public GpiHdl { public: GpiObjHdl(GpiImplInterface *impl, void *hdl = nullptr, gpi_objtype objtype = GPI_UNKNOWN, bool is_const = false) : GpiHdl(impl, hdl), m_type(objtype), m_const(is_const) {} virtual ~GpiObjHdl() = default; // TODO why do these even exist? Just return the string by ref and call // c_str. virtual const char *get_name_str(); virtual const char *get_fullname_str(); virtual const char *get_type_str(); gpi_objtype get_type() { return m_type; }; bool get_const() { return m_const; }; int get_num_elems() { return m_num_elems; } int get_range_left() { return m_range_left; } int get_range_right() { return m_range_right; } gpi_range_dir get_range_dir() { return m_range_dir; } int get_indexable() { return m_indexable; } const std::string &get_name(); const std::string &get_fullname(); virtual const char *get_definition_name() { return m_definition_name.c_str(); }; virtual const char *get_definition_file() { return m_definition_file.c_str(); }; bool is_native_impl(GpiImplInterface *impl); virtual int initialise(const std::string &name, const std::string &full_name); protected: int m_num_elems = 0; bool m_indexable = false; int m_range_left = -1; int m_range_right = -1; gpi_range_dir m_range_dir = GPI_RANGE_NO_DIR; std::string m_name = "unknown"; std::string m_fullname = "unknown"; std::string m_definition_name; std::string m_definition_file; gpi_objtype m_type; bool m_const; }; /* GPI Signal object handle, maps to a simulation object */ // // Identical to an object but adds additional methods for getting/setting the // value of the signal (which doesn't apply to non signal items in the hierarchy class GPI_EXPORT GpiSignalObjHdl : public GpiObjHdl { public: using GpiObjHdl::GpiObjHdl; virtual ~GpiSignalObjHdl() = default; // Provide public access to the implementation (composition vs inheritance) virtual const char *get_signal_value_binstr() = 0; virtual const char *get_signal_value_str() = 0; virtual double get_signal_value_real() = 0; virtual long get_signal_value_long() = 0; int m_length = 0; virtual int set_signal_value(const int32_t value, gpi_set_action action) = 0; virtual int set_signal_value(const double value, gpi_set_action action) = 0; virtual int set_signal_value_str(std::string &value, gpi_set_action action) = 0; virtual int set_signal_value_binstr(std::string &value, gpi_set_action action) = 0; // virtual GpiCbHdl monitor_value(bool rising_edge) = 0; this was for the // triggers // but the explicit ones are probably better virtual GpiCbHdl *register_value_change_callback( gpi_edge edge, int (*gpi_function)(void *), void *gpi_cb_data) = 0; }; /* GPI Callback handle */ // To set a callback it needs the signal to do this on, // vpiHandle/vhpiHandleT for instance. The class GPI_EXPORT GpiCbHdl : public GpiHdl { public: GpiCbHdl() = delete; GpiCbHdl(GpiImplInterface *impl) : GpiHdl(impl) {} // TODO Some of these routines don't need to be declared here. Only remove() // and get_cb_info() need to. In fact, declaring these here means we can't // do things like pass arguments to arm(). /** Set user callback info * * Not on init to prevent having to pass around the arguments everywhere. * Secondary initialization routine. ONLY CALL ONCE! */ void set_cb_info(int (*cb_func)(void *), void *cb_data) noexcept { this->m_cb_func = cb_func; this->m_cb_data = cb_data; } /** Get the current user callback function and data. */ void get_cb_info(int (**cb_func)(void *), void **cb_data) noexcept { if (cb_func) { *cb_func = m_cb_func; } if (cb_data) { *cb_data = m_cb_data; } } /** Arm the callback after construction. * * Calling virtual functions from constructors does not work as expected. * Secondary initialization routine. ONLY CALL ONCE! */ virtual int arm() = 0; /** Remove the callback before it fires. * * This function should delete the object. */ virtual int remove() = 0; /** Run the callback. * * This function should delete the object if it can't fire again. */ virtual int run() = 0; protected: int (*m_cb_func)(void *); // GPI function to callback void *m_cb_data; // GPI data supplied to "m_cb_func" }; class GPI_EXPORT GpiIterator : public GpiHdl { public: enum Status { NATIVE, // Fully resolved object was created NATIVE_NO_NAME, // Native object was found but unable to fully create NOT_NATIVE, // Non-native object was found but we did get a name NOT_NATIVE_NO_NAME, // Non-native object was found without a name END }; GpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl) : GpiHdl(impl), m_parent(hdl) {} virtual ~GpiIterator() = default; virtual Status next_handle(std::string &name, GpiObjHdl **hdl, void **) { name = ""; *hdl = NULL; return GpiIterator::END; } GpiObjHdl *get_parent() { return m_parent; } protected: GpiObjHdl *m_parent; }; class GPI_EXPORT GpiImplInterface { public: GpiImplInterface(const std::string &name) : m_name(name) {} const char *get_name_c(); const std::string &get_name_s(); virtual ~GpiImplInterface() = default; /* Sim related */ virtual void sim_end() = 0; virtual void get_sim_time(uint32_t *high, uint32_t *low) = 0; virtual void get_sim_precision(int32_t *precision) = 0; virtual const char *get_simulator_product() = 0; virtual const char *get_simulator_version() = 0; /* Hierarchy related */ virtual GpiObjHdl *get_child_by_name(const std::string &name, GpiObjHdl *parent) = 0; virtual GpiObjHdl *get_child_by_index(int32_t index, GpiObjHdl *parent) = 0; virtual GpiObjHdl *get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) = 0; virtual GpiObjHdl *get_root_handle(const char *name) = 0; virtual GpiIterator *iterate_handle(GpiObjHdl *obj_hdl, gpi_iterator_sel type) = 0; /* Callback related, these may (will) return the same handle */ virtual GpiCbHdl *register_timed_callback(uint64_t time, int (*gpi_function)(void *), void *gpi_cb_data) = 0; virtual GpiCbHdl *register_readonly_callback(int (*gpi_function)(void *), void *gpi_cb_data) = 0; virtual GpiCbHdl *register_nexttime_callback(int (*gpi_function)(void *), void *gpi_cb_data) = 0; virtual GpiCbHdl *register_readwrite_callback(int (*gpi_function)(void *), void *gpi_cb_data) = 0; /* Method to provide strings from operation types */ virtual const char *reason_to_string(int reason) = 0; private: std::string m_name; protected: std::string m_product; std::string m_version; }; /* Called from implementation layers back up the stack */ GPI_EXPORT int gpi_register_impl(GpiImplInterface *func_tbl); GPI_EXPORT void gpi_embed_init(int argc, char const *const *argv); GPI_EXPORT void gpi_embed_end(); GPI_EXPORT void gpi_entry_point(); GPI_EXPORT void gpi_to_user(); GPI_EXPORT void gpi_to_simulator(); typedef void (*layer_entry_func)(); /* Use this macro in an implementation layer to define an entry point */ #define GPI_ENTRY_POINT(NAME, func) \ extern "C" { \ COCOTB_EXPORT void NAME##_entry_point() { func(); } \ } #endif /* COCOTB_GPI_PRIV_H_ */ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3487027 cocotb-2.0.1/src/cocotb/share/lib/gpi_log/0000755000175100017510000000000015106070715017763 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/gpi_log/gpi_logging.cpp0000644000175100017510000001536715106067236022774 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include "gpi_logging.h" #include #include #include #include #include #include "cocotb_utils.h" // DEFER static gpi_log_handler_ftype current_handler = nullptr; static gpi_log_filter_ftype current_filter = nullptr; static gpi_log_set_level_ftype current_set_level = nullptr; static void *current_userdata = nullptr; extern "C" void gpi_log_(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, ...) { va_list argp; va_start(argp, msg); gpi_vlog_(name, level, pathname, funcname, lineno, msg, argp); va_end(argp); } extern "C" void gpi_vlog_(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, va_list argp) { if (current_handler) { (*current_handler)(current_userdata, name, level, pathname, funcname, lineno, msg, argp); } else { gpi_native_logger_vlog_(name, level, pathname, funcname, lineno, msg, argp); } } extern "C" void gpi_get_log_handler(gpi_log_handler_ftype *handler, gpi_log_filter_ftype *filter, gpi_log_set_level_ftype *set_level, void **userdata) { *handler = current_handler; *filter = current_filter; *set_level = current_set_level; *userdata = current_userdata; } extern "C" void gpi_set_log_handler(gpi_log_handler_ftype handler, gpi_log_filter_ftype filter, gpi_log_set_level_ftype set_level, void *userdata) { current_handler = handler; current_filter = filter; current_set_level = set_level; current_userdata = userdata; } extern "C" void gpi_clear_log_handler(void) { current_handler = nullptr; current_filter = nullptr; current_set_level = nullptr; current_userdata = nullptr; } extern "C" bool gpi_log_filtered(const char *logger, int level) { if (current_filter) { return current_filter(current_userdata, logger, level); } else { return gpi_native_logger_filtered(level); } } extern "C" int gpi_log_set_level(const char *logger, int level) { if (current_set_level) { return current_set_level(current_userdata, logger, level); } else { return gpi_native_logger_set_level(level); } } static const std::map log_level_str_table = { {GPI_TRACE, "TRACE"}, {GPI_DEBUG, "DEBUG"}, {GPI_INFO, "INFO"}, {GPI_WARNING, "WARNING"}, {GPI_ERROR, "ERROR"}, {GPI_CRITICAL, "CRITICAL"}, }; static const char *unknown_level = "------"; extern "C" const char *gpi_log_level_to_str(int level) { const char *log_level_str = unknown_level; auto idx = log_level_str_table.find(level); if (idx != log_level_str_table.end()) { log_level_str = idx->second; } return log_level_str; } /******************************************************************************* * GPI Native Logger *******************************************************************************/ static int current_native_logger_level = GPI_NOTSET; extern "C" void gpi_native_logger_log_(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, ...) { va_list argp; va_start(argp, msg); gpi_native_logger_vlog_(name, level, pathname, funcname, lineno, msg, argp); va_end(argp); } extern "C" void gpi_native_logger_vlog_(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, va_list argp) { int curr_level = current_native_logger_level; if (current_native_logger_level == GPI_NOTSET) { curr_level = GPI_INFO; } if (level < curr_level) { return; } va_list argp_copy; va_copy(argp_copy, argp); DEFER(va_end(argp_copy)); static std::vector log_buff(512); log_buff.clear(); int n = vsnprintf(log_buff.data(), log_buff.capacity(), msg, argp); if (n < 0) { // On Windows with the Visual C Runtime prior to 2015 the above call to // vsnprintf will return -1 if the buffer would overflow, rather than // the number of bytes that would be written as required by the C99 // standard. // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l // So we try the call again with the buffer NULL and the size 0, which // should return the number of bytes that would be written. va_list argp_copy_again; va_copy(argp_copy_again, argp_copy); DEFER(va_end(argp_copy_again)); n = vsnprintf(NULL, 0, msg, argp_copy_again); if (n < 0) { // Here we know the error is for real, so we complain and move on. // LCOV_EXCL_START fprintf(stderr, "Log message construction failed: (error code) %d\n", n); return; // LCOV_EXCL_STOP } } if ((unsigned)n >= log_buff.capacity()) { log_buff.reserve((unsigned)n + 1); n = vsnprintf(log_buff.data(), (unsigned)n + 1, msg, argp_copy); if (n < 0) { // LCOV_EXCL_START fprintf(stderr, "Log message construction failed: (error code) %d\n", n); return; // LCOV_EXCL_STOP } } fprintf(stdout, " -.--ns "); fprintf(stdout, "%-9s", gpi_log_level_to_str(level)); fprintf(stdout, "%-35s", name); size_t pathlen = strlen(pathname); if (pathlen > 20) { fprintf(stdout, "..%18s:", (pathname + (pathlen - 18))); } else { fprintf(stdout, "%20s:", pathname); } fprintf(stdout, "%-4ld", lineno); fprintf(stdout, " in %-31s ", funcname); fprintf(stdout, "%s", log_buff.data()); fprintf(stdout, "\n"); fflush(stdout); } extern "C" int gpi_native_logger_set_level(int level) { int old_level = current_native_logger_level; current_native_logger_level = level; return old_level; } extern "C" bool gpi_native_logger_filtered(int level) { return level >= current_native_logger_level; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3487027 cocotb-2.0.1/src/cocotb/share/lib/py_gpi_log/0000755000175100017510000000000015106070715020473 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/py_gpi_log/py_gpi_logging.cpp0000644000175100017510000001603315106067236024203 0ustar00runnerrunner// Copyright cocotb contributors // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include "py_gpi_logging.h" #include // all things Python #include // va_list, va_copy, va_end #include // fprintf, vsnprintf #include // std::map #include // std::string #include // std::vector #include "cocotb_utils.h" // DEFER #include "gpi_logging.h" // all things GPI logging static int py_gpi_log_level = GPI_NOTSET; static PyObject *m_log_func = nullptr; static std::map m_logger_map; static PyObject *m_get_logger = nullptr; static void fallback_handler(const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg) { // Note: don't call the LOG_ERROR macro because that might recurse gpi_native_logger_log_(name, level, pathname, funcname, lineno, msg); gpi_native_logger_log_("gpi", GPI_ERROR, __FILE__, __func__, __LINE__, "Error calling Python logging function from C++ " "while logging the above"); } static void py_gpi_log_handler(void *, const char *name, int level, const char *pathname, const char *funcname, long lineno, const char *msg, va_list argp) { // Always pass through messages when NOTSET to let Python make the decision. // Otherwise, skip logs using the local log level for better performance. if (py_gpi_log_level != GPI_NOTSET && level < py_gpi_log_level) { return; } va_list argp_copy; va_copy(argp_copy, argp); DEFER(va_end(argp_copy)); // before the log buffer to ensure it isn't clobbered. PyGILState_STATE gstate = PyGILState_Ensure(); DEFER(PyGILState_Release(gstate)); static std::vector log_buff(512); log_buff.clear(); int n = vsnprintf(log_buff.data(), log_buff.capacity(), msg, argp); if (n < 0) { // On Windows with the Visual C Runtime prior to 2015 the above call to // vsnprintf will return -1 if the buffer would overflow, rather than // the number of bytes that would be written as required by the C99 // standard. // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l // So we try the call again with the buffer NULL and the size 0, which // should return the number of bytes that would be written. va_list argp_copy_again; va_copy(argp_copy_again, argp_copy); DEFER(va_end(argp_copy_again)); n = vsnprintf(NULL, 0, msg, argp_copy_again); if (n < 0) { // Here we know the error is for real, so we complain and move on. // LCOV_EXCL_START fprintf(stderr, "Log message construction failed: (error code) %d\n", n); return; // LCOV_EXCL_STOP } } if ((unsigned)n >= log_buff.capacity()) { log_buff.reserve((unsigned)n + 1); n = vsnprintf(log_buff.data(), (unsigned)n + 1, msg, argp_copy); if (n < 0) { // LCOV_EXCL_START fprintf(stderr, "Log message construction failed: (error code) %d\n", n); return; // LCOV_EXCL_STOP } } PyObject *level_arg = PyLong_FromLong(level); // New reference if (level_arg == NULL) { // LCOV_EXCL_START PyErr_Print(); return fallback_handler(name, level, pathname, funcname, lineno, log_buff.data()); // LCOV_EXCL_STOP } DEFER(Py_DECREF(level_arg)); PyObject *logger; const auto lookup = m_logger_map.find(name); if (lookup == m_logger_map.end()) { logger = PyObject_CallFunction(m_get_logger, "s", name); // incs a ref // LCOV_EXCL_START if (!logger) { PyErr_Print(); return fallback_handler(name, level, pathname, funcname, lineno, log_buff.data()); } // LCOV_EXCL_STOP m_logger_map[name] = logger; // steal that ref } else { logger = lookup->second; } PyObject *filename_arg = PyUnicode_FromString(pathname); // New reference if (filename_arg == NULL) { // LCOV_EXCL_START PyErr_Print(); return fallback_handler(name, level, pathname, funcname, lineno, log_buff.data()); // LCOV_EXCL_STOP } DEFER(Py_DECREF(filename_arg)); PyObject *lineno_arg = PyLong_FromLong(lineno); // New reference if (lineno_arg == NULL) { // LCOV_EXCL_START PyErr_Print(); return fallback_handler(name, level, pathname, funcname, lineno, log_buff.data()); // LCOV_EXCL_STOP } DEFER(Py_DECREF(lineno_arg)); PyObject *msg_arg = PyUnicode_FromString(log_buff.data()); // New reference if (msg_arg == NULL) { // LCOV_EXCL_START PyErr_Print(); return fallback_handler(name, level, pathname, funcname, lineno, log_buff.data()); // LCOV_EXCL_STOP } DEFER(Py_DECREF(msg_arg)); PyObject *function_arg = PyUnicode_FromString(funcname); // New reference if (function_arg == NULL) { // LCOV_EXCL_START PyErr_Print(); return fallback_handler(name, level, pathname, funcname, lineno, log_buff.data()); // LCOV_EXCL_STOP } DEFER(Py_DECREF(function_arg)) // Log function args are logger_name, level, filename, lineno, msg, function PyObject *handler_ret = PyObject_CallFunctionObjArgs( m_log_func, logger, level_arg, filename_arg, lineno_arg, msg_arg, function_arg, NULL); if (handler_ret == NULL) { // LCOV_EXCL_START PyErr_Print(); return fallback_handler(name, level, pathname, funcname, lineno, log_buff.data()); // LCOV_EXCL_STOP } Py_DECREF(handler_ret); } static bool py_gpi_log_filter(void *, const char *, int level) { return level >= py_gpi_log_level; } static bool py_gpi_logger_set_level(void *, const char *, int level) { auto old_level = py_gpi_log_level; py_gpi_log_level = level; gpi_native_logger_set_level(level); return old_level; } extern "C" void py_gpi_logger_initialize(PyObject *log_func, PyObject *get_logger) { Py_INCREF(log_func); Py_INCREF(get_logger); m_log_func = log_func; m_get_logger = get_logger; gpi_set_log_handler(py_gpi_log_handler, py_gpi_log_filter, py_gpi_logger_set_level, nullptr); } extern "C" void py_gpi_logger_finalize() { gpi_clear_log_handler(); Py_XDECREF(m_log_func); Py_XDECREF(m_get_logger); for (auto &elem : m_logger_map) { Py_DECREF(elem.second); } m_logger_map.clear(); } PyObject *pEventFn = NULL; ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3497026 cocotb-2.0.1/src/cocotb/share/lib/simulator/0000755000175100017510000000000015106070715020362 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/simulator/simulatormodule.cpp0000644000175100017510000014014215106067236024321 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause /** * @file simulatormodule.cpp * @brief Python extension to provide access to the simulator * * Uses GPI calls to interface to the simulator. */ #include #include #include #include "cocotb_utils.h" // to_python to_simulator #include "gpi.h" #include "py_gpi_logging.h" // py_gpi_logger_set_level // This file defines the routines available to Python #define MODULE_NAME "simulator" // callback user data struct PythonCallback { PythonCallback(PyObject *func, PyObject *_args, PyObject *_kwargs) : function(func), args(_args), kwargs(_kwargs) { Py_XINCREF(function); Py_XINCREF(args); Py_XINCREF(kwargs); } ~PythonCallback() { Py_XDECREF(function); Py_XDECREF(args); Py_XDECREF(kwargs); } intptr_t padding_; // TODO exists to works around bug with FLI PyObject *function; // Function to call when the callback fires PyObject *args; // The arguments to call the function with PyObject *kwargs; // Keyword arguments to call the function with }; class GpiClock; using gpi_clk_hdl = GpiClock *; /* define the extension types as templates */ namespace { template struct gpi_hdl_Object { PyObject_HEAD gpi_hdl hdl; // The python type object, in a place that is easy to retrieve in templates static PyTypeObject py_type; }; /** __repr__ shows the memory address of the internal handle */ template static PyObject *gpi_hdl_repr(gpi_hdl_Object *self) { auto *type = Py_TYPE(self); return PyUnicode_FromFormat("<%s at %p>", type->tp_name, self->hdl); } /** __hash__ returns the pointer itself */ template static Py_hash_t gpi_hdl_hash(gpi_hdl_Object *self) { auto ret = reinterpret_cast(self->hdl); // hash must never return -1 if (ret == (Py_hash_t)-1) { ret = (Py_hash_t)-2; } return ret; } /** * Create a new python handle object from a pointer, returning None if the * pointer is NULL. */ template static PyObject *gpi_hdl_New(gpi_hdl hdl) { if (hdl == NULL) { Py_RETURN_NONE; } auto *obj = PyObject_New(gpi_hdl_Object, &gpi_hdl_Object::py_type); if (obj == NULL) { return NULL; } obj->hdl = hdl; return (PyObject *)obj; } /** Comparison checks if the types match, and then compares pointers */ template static PyObject *gpi_hdl_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) != &gpi_hdl_Object::py_type || Py_TYPE(other) != &gpi_hdl_Object::py_type) { Py_RETURN_NOTIMPLEMENTED; } auto self_hdl_obj = reinterpret_cast *>(self); auto other_hdl_obj = reinterpret_cast *>(other); switch (op) { case Py_EQ: return PyBool_FromLong(self_hdl_obj->hdl == other_hdl_obj->hdl); case Py_NE: return PyBool_FromLong(self_hdl_obj->hdl != other_hdl_obj->hdl); default: Py_RETURN_NOTIMPLEMENTED; } } // Initialize the Python type slots template PyTypeObject fill_common_slots() { PyTypeObject type = {}; type.ob_base = {PyObject_HEAD_INIT(NULL) 0}; type.tp_basicsize = sizeof(gpi_hdl_Object); type.tp_repr = (reprfunc)gpi_hdl_repr; type.tp_hash = (hashfunc)gpi_hdl_hash; type.tp_flags = Py_TPFLAGS_DEFAULT; type.tp_richcompare = gpi_hdl_richcompare; return type; } // these will be initialized later, once the members are all defined template <> PyTypeObject gpi_hdl_Object::py_type; template <> PyTypeObject gpi_hdl_Object::py_type; template <> PyTypeObject gpi_hdl_Object::py_type; template <> PyTypeObject gpi_hdl_Object::py_type; } // namespace typedef int (*gpi_function_t)(void *); struct sim_time { uint32_t high; uint32_t low; }; /** * @name Callback Handling * @brief Handle a callback coming from GPI * @ingroup python_c_api * * Returns 0 on success or 1 on a failure. * * Handles a callback from the simulator, all of which call this function. * * We extract the associated context and find the Python function (usually * cocotb.scheduler.react) calling it with a reference to the trigger that * fired. The scheduler can then call next() on all the coroutines that * are waiting on that particular trigger. * */ int handle_gpi_callback(void *user_data) { to_python(); DEFER(to_simulator()); PyGILState_STATE gstate = PyGILState_Ensure(); DEFER(PyGILState_Release(gstate)); PythonCallback *cb_data = (PythonCallback *)user_data; DEFER(delete cb_data); // Call the callback PyObject *pValue = PyObject_Call(cb_data->function, cb_data->args, cb_data->kwargs); // If the return value is NULL a Python exception has occurred // The best thing to do here is shutdown as any subsequent // calls will go back to Python which is now in an unknown state if (pValue == NULL) { // Printing a SystemExit calls exit(1), which we don't want. if (!PyErr_ExceptionMatches(PyExc_SystemExit)) { PyErr_Print(); } // Clear error so re-entering Python doesn't fail. PyErr_Clear(); return -1; } // We don't care about the result Py_DECREF(pValue); return 0; } // Register a callback for read-only state of sim // First argument is the function to call // Remaining arguments are keyword arguments to be passed to the callback static PyObject *register_readonly_callback(PyObject *, PyObject *args) { if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } Py_ssize_t numargs = PyTuple_Size(args); if (numargs < 1) { PyErr_SetString(PyExc_TypeError, "Attempt to register ReadOnly callback without enough " "arguments!\n"); return NULL; } // Extract the callback function PyObject *function = PyTuple_GetItem(args, 0); // borrow reference if (!PyCallable_Check(function)) { PyErr_SetString( PyExc_TypeError, "Attempt to register ReadOnly without supplying a callback!\n"); return NULL; } // Remaining args for function PyObject *fArgs = PyTuple_GetSlice(args, 1, numargs); // New reference if (fArgs == NULL) { return NULL; } DEFER(Py_DECREF(fArgs)); PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL); gpi_cb_hdl hdl = gpi_register_readonly_callback( (gpi_function_t)handle_gpi_callback, cb_data); PyObject *rv = gpi_hdl_New(hdl); return rv; } static PyObject *register_rwsynch_callback(PyObject *, PyObject *args) { if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } Py_ssize_t numargs = PyTuple_Size(args); if (numargs < 1) { PyErr_SetString(PyExc_TypeError, "Attempt to register ReadWrite callback without enough " "arguments!\n"); return NULL; } // Extract the callback function PyObject *function = PyTuple_GetItem(args, 0); // borrow reference if (!PyCallable_Check(function)) { PyErr_SetString( PyExc_TypeError, "Attempt to register ReadWrite without supplying a callback!\n"); return NULL; } // Remaining args for function PyObject *fArgs = PyTuple_GetSlice(args, 1, numargs); // New reference if (fArgs == NULL) { return NULL; } DEFER(Py_DECREF(fArgs)); PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL); gpi_cb_hdl hdl = gpi_register_readwrite_callback( (gpi_function_t)handle_gpi_callback, cb_data); PyObject *rv = gpi_hdl_New(hdl); return rv; } static PyObject *register_nextstep_callback(PyObject *, PyObject *args) { if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } Py_ssize_t numargs = PyTuple_Size(args); if (numargs < 1) { PyErr_SetString(PyExc_TypeError, "Attempt to register NextStep callback without enough " "arguments!\n"); return NULL; } // Extract the callback function PyObject *function = PyTuple_GetItem(args, 0); // borrow reference if (!PyCallable_Check(function)) { PyErr_SetString( PyExc_TypeError, "Attempt to register NextStep without supplying a callback!\n"); return NULL; } // Remaining args for function PyObject *fArgs = PyTuple_GetSlice(args, 1, numargs); // New reference if (fArgs == NULL) { return NULL; } DEFER(Py_DECREF(fArgs)); PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL); gpi_cb_hdl hdl = gpi_register_nexttime_callback( (gpi_function_t)handle_gpi_callback, cb_data); PyObject *rv = gpi_hdl_New(hdl); return rv; } // Register a timed callback. // First argument should be the time in picoseconds // Second argument is the function to call // Remaining arguments and keyword arguments are to be passed to the callback static PyObject *register_timed_callback(PyObject *, PyObject *args) { if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } Py_ssize_t numargs = PyTuple_Size(args); if (numargs < 2) { PyErr_SetString( PyExc_TypeError, "Attempt to register timed callback without enough arguments!\n"); return NULL; } uint64_t time; { // Extract the time PyObject *pTime = PyTuple_GetItem(args, 0); long long pTime_as_longlong = PyLong_AsLongLong(pTime); if (pTime_as_longlong == -1 && PyErr_Occurred()) { return NULL; } else if (pTime_as_longlong < 0) { PyErr_SetString(PyExc_ValueError, "Timer value must be a positive integer"); return NULL; } else { time = (uint64_t)pTime_as_longlong; } } // Extract the callback function PyObject *function = PyTuple_GetItem(args, 1); // borrow reference if (!PyCallable_Check(function)) { PyErr_SetString(PyExc_TypeError, "Attempt to register timed callback without passing a " "callable callback!\n"); return NULL; } // Remaining args for function PyObject *fArgs = PyTuple_GetSlice(args, 2, numargs); // New reference if (fArgs == NULL) { return NULL; } DEFER(Py_DECREF(fArgs)); PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL); gpi_cb_hdl hdl = gpi_register_timed_callback( (gpi_function_t)handle_gpi_callback, cb_data, time); // Check success PyObject *rv = gpi_hdl_New(hdl); return rv; } // Register signal change callback // First argument should be the signal handle // Second argument is the function to call // Remaining arguments and keyword arguments are to be passed to the callback static PyObject *register_value_change_callback( PyObject *, PyObject *args) //, PyObject *keywds) { if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } Py_ssize_t numargs = PyTuple_Size(args); if (numargs < 3) { PyErr_SetString(PyExc_TypeError, "Attempt to register value change callback without " "enough arguments!\n"); return NULL; } PyObject *pSigHdl = PyTuple_GetItem(args, 0); if (Py_TYPE(pSigHdl) != &gpi_hdl_Object::py_type) { PyErr_SetString(PyExc_TypeError, "First argument must be a gpi_sim_hdl"); return NULL; } gpi_sim_hdl sig_hdl = ((gpi_hdl_Object *)pSigHdl)->hdl; // Extract the callback function PyObject *function = PyTuple_GetItem(args, 1); // borrow reference if (!PyCallable_Check(function)) { PyErr_SetString(PyExc_TypeError, "Attempt to register value change callback without " "passing a callable callback!\n"); return NULL; } PyObject *pedge = PyTuple_GetItem(args, 2); // borrow reference gpi_edge edge = (gpi_edge)PyLong_AsLong(pedge); // Remaining args for function PyObject *fArgs = PyTuple_GetSlice(args, 3, numargs); // New reference if (fArgs == NULL) { return NULL; } DEFER(Py_DECREF(fArgs)); PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL); gpi_cb_hdl hdl = gpi_register_value_change_callback( (gpi_function_t)handle_gpi_callback, cb_data, sig_hdl, edge); // Check success PyObject *rv = gpi_hdl_New(hdl); return rv; } static PyObject *iterate(gpi_hdl_Object *self, PyObject *args) { int type; if (!PyArg_ParseTuple(args, "i:iterate", &type)) { return NULL; } gpi_iterator_hdl result = gpi_iterate(self->hdl, (gpi_iterator_sel)type); return gpi_hdl_New(result); } static PyObject *package_iterate(PyObject *, PyObject *) { gpi_iterator_hdl result = gpi_iterate(NULL, GPI_PACKAGE_SCOPES); return gpi_hdl_New(result); } static PyObject *next(gpi_hdl_Object *self) { gpi_sim_hdl result = gpi_next(self->hdl); // Raise StopIteration when we're done if (!result) { PyErr_SetNone(PyExc_StopIteration); return NULL; } return gpi_hdl_New(result); } // Raise an exception on failure // Return None if for example get bin_string on enum? static PyObject *get_signal_val_binstr(gpi_hdl_Object *self, PyObject *) { const char *result = gpi_get_signal_value_binstr(self->hdl); if (result == NULL) { // LCOV_EXCL_START PyErr_SetString(PyExc_RuntimeError, "Simulator yielded a null pointer instead of binstr"); return NULL; // LCOV_EXCL_STOP } return PyUnicode_FromString(result); } static PyObject *get_signal_val_str(gpi_hdl_Object *self, PyObject *) { const char *result = gpi_get_signal_value_str(self->hdl); if (result == NULL) { // LCOV_EXCL_START PyErr_SetString(PyExc_RuntimeError, "Simulator yielded a null pointer instead of string"); return NULL; // LCOV_EXCL_STOP } return PyBytes_FromString(result); } static PyObject *get_signal_val_real(gpi_hdl_Object *self, PyObject *) { double result = gpi_get_signal_value_real(self->hdl); return PyFloat_FromDouble(result); } static PyObject *get_signal_val_long(gpi_hdl_Object *self, PyObject *) { long result = gpi_get_signal_value_long(self->hdl); return PyLong_FromLong(result); } static PyObject *set_signal_val_binstr(gpi_hdl_Object *self, PyObject *args) { const char *binstr; gpi_set_action action; if (!PyArg_ParseTuple(args, "is:set_signal_val_binstr", &action, &binstr)) { return NULL; } gpi_set_signal_value_binstr(self->hdl, binstr, action); Py_RETURN_NONE; } static PyObject *set_signal_val_str(gpi_hdl_Object *self, PyObject *args) { gpi_set_action action; const char *str; if (!PyArg_ParseTuple(args, "iy:set_signal_val_str", &action, &str)) { return NULL; } gpi_set_signal_value_str(self->hdl, str, action); Py_RETURN_NONE; } static PyObject *set_signal_val_real(gpi_hdl_Object *self, PyObject *args) { double value; gpi_set_action action; if (!PyArg_ParseTuple(args, "id:set_signal_val_real", &action, &value)) { return NULL; } gpi_set_signal_value_real(self->hdl, value, action); Py_RETURN_NONE; } static PyObject *set_signal_val_int(gpi_hdl_Object *self, PyObject *args) { long long value; gpi_set_action action; if (!PyArg_ParseTuple(args, "iL:set_signal_val_int", &action, &value)) { return NULL; } gpi_set_signal_value_int(self->hdl, static_cast(value), action); Py_RETURN_NONE; } static PyObject *get_definition_name(gpi_hdl_Object *self, PyObject *) { const char *result = gpi_get_definition_name(self->hdl); return PyUnicode_FromString(result); } static PyObject *get_definition_file(gpi_hdl_Object *self, PyObject *) { const char *result = gpi_get_definition_file(self->hdl); return PyUnicode_FromString(result); } static PyObject *get_handle_by_name(gpi_hdl_Object *self, PyObject *args) { const char *name; // if unset, we assume AUTO, which maintains backward-compatibility int py_discovery_method = 0; gpi_discovery c_discovery_method = GPI_AUTO; if (!PyArg_ParseTuple(args, "s|i:get_handle_by_name", &name, &py_discovery_method)) { return NULL; } // do some additional input validation, then map to enum if (py_discovery_method < 0 || py_discovery_method > 1) { PyErr_SetString(PyExc_ValueError, "Enum value for discovery_method out of range"); return NULL; } else { c_discovery_method = (gpi_discovery)py_discovery_method; } gpi_sim_hdl result = gpi_get_handle_by_name(self->hdl, name, c_discovery_method); return gpi_hdl_New(result); } static PyObject *get_handle_by_index(gpi_hdl_Object *self, PyObject *args) { int32_t index; if (!PyArg_ParseTuple(args, "i:get_handle_by_index", &index)) { return NULL; } gpi_sim_hdl result = gpi_get_handle_by_index(self->hdl, index); return gpi_hdl_New(result); } static PyObject *get_root_handle(PyObject *, PyObject *args) { const char *name; if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } if (!PyArg_ParseTuple(args, "z:get_root_handle", &name)) { return NULL; } gpi_sim_hdl result = gpi_get_root_handle(name); if (NULL == result) { Py_RETURN_NONE; } return gpi_hdl_New(result); } static PyObject *get_name_string(gpi_hdl_Object *self, PyObject *) { const char *result = gpi_get_signal_name_str(self->hdl); return PyUnicode_FromString(result); } static PyObject *get_type(gpi_hdl_Object *self, PyObject *) { gpi_objtype result = gpi_get_object_type(self->hdl); return PyLong_FromLong(result); } static PyObject *get_const(gpi_hdl_Object *self, PyObject *) { int result = gpi_is_constant(self->hdl); return PyBool_FromLong(result); } static PyObject *get_type_string(gpi_hdl_Object *self, PyObject *) { const char *result = gpi_get_signal_type_str(self->hdl); return PyUnicode_FromString(result); } static PyObject *is_running(PyObject *, PyObject *) { return PyBool_FromLong(gpi_has_registered_impl()); } // Returns a high, low, tuple of simulator time // Note we can never log from this function since the logging mechanism calls // this to annotate log messages with the current simulation time static PyObject *get_sim_time(PyObject *, PyObject *) { if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } struct sim_time local_time; gpi_get_sim_time(&local_time.high, &local_time.low); PyObject *pTuple = PyTuple_New(2); PyTuple_SetItem( pTuple, 0, PyLong_FromUnsignedLong( local_time .high)); // Note: This function “steals” a reference to o. PyTuple_SetItem( pTuple, 1, PyLong_FromUnsignedLong( local_time.low)); // Note: This function “steals” a reference to o. return pTuple; } static PyObject *get_precision(PyObject *, PyObject *) { if (!gpi_has_registered_impl()) { char const *msg = "Simulator is not available! Defaulting precision to 1 fs."; if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0) { return NULL; } return PyLong_FromLong(-15); // preserves old behavior } int32_t precision; gpi_get_sim_precision(&precision); return PyLong_FromLong(precision); } static PyObject *get_simulator_product(PyObject *, PyObject *) { if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } return PyUnicode_FromString(gpi_get_simulator_product()); } static PyObject *get_simulator_version(PyObject *, PyObject *) { if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } return PyUnicode_FromString(gpi_get_simulator_version()); } static PyObject *get_num_elems(gpi_hdl_Object *self, PyObject *) { int elems = gpi_get_num_elems(self->hdl); return PyLong_FromLong(elems); } static PyObject *get_range(gpi_hdl_Object *self, PyObject *) { int rng_left = gpi_get_range_left(self->hdl); int rng_right = gpi_get_range_right(self->hdl); int rng_dir = gpi_get_range_dir(self->hdl); return Py_BuildValue("(i,i,i)", rng_left, rng_right, rng_dir); } static PyObject *get_indexable(gpi_hdl_Object *self, PyObject *) { int indexable = gpi_is_indexable(self->hdl); return PyBool_FromLong(indexable); } static PyObject *stop_simulator(PyObject *, PyObject *) { if (!gpi_has_registered_impl()) { PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; } gpi_sim_end(); Py_RETURN_NONE; } static PyObject *deregister(gpi_hdl_Object *self, PyObject *) { // cleanup uncalled callback void *cb_data; gpi_get_cb_info(self->hdl, nullptr, &cb_data); auto cb = static_cast(cb_data); delete cb; // deregister from interface gpi_remove_cb(self->hdl); Py_RETURN_NONE; } static PyObject *set_gpi_log_level(PyObject *, PyObject *args) { int l_level; if (!PyArg_ParseTuple(args, "i:log_level", &l_level)) { return NULL; } gpi_log_set_level("gpi", l_level); Py_RETURN_NONE; } static PyObject *initialize_logger(PyObject *, PyObject *args) { PyObject *log_func; PyObject *get_logger; if (!PyArg_ParseTuple(args, "OO", &log_func, &get_logger)) { PyErr_Print(); return NULL; } py_gpi_logger_initialize(log_func, get_logger); Py_RETURN_NONE; } static PyObject *set_sim_event_callback(PyObject *, PyObject *args) { if (pEventFn) { PyErr_SetString(PyExc_RuntimeError, "Simulator event callback already set!"); return NULL; } PyObject *sim_event_callback; if (!PyArg_ParseTuple(args, "O", &sim_event_callback)) { PyErr_Print(); Py_RETURN_NONE; } Py_INCREF(sim_event_callback); pEventFn = sim_event_callback; Py_RETURN_NONE; } class GpiClock { public: GpiClock(GpiObjHdl *clk_sig) : clk_signal(clk_sig) {} ~GpiClock() { stop(); } // Start the clock. Returns nonzero in case of failure: // - EBUSY if the clock was already started (stop first) // - EINVAL if the parameters are invalid // - EAGAIN if registering the toggle callback failed int start(uint64_t period_steps, uint64_t high_steps, bool start_high, gpi_set_action set_action); int stop(); private: GpiObjHdl *clk_signal = nullptr; GpiCbHdl *clk_toggle_cb_hdl = nullptr; uint64_t period = 0; uint64_t t_high = 0; gpi_set_action m_set_action; int clk_val = 0; int toggle(bool initialSet); static int toggle_cb(void *gpi_clk); }; int GpiClock::start(uint64_t period_steps, uint64_t high_steps, bool start_high, gpi_set_action set_action) { if (clk_toggle_cb_hdl) { return EBUSY; } if ((period_steps < 2) || (high_steps < 1) || (high_steps >= period_steps)) { return EINVAL; } period = period_steps; t_high = high_steps; m_set_action = set_action; clk_val = start_high; return toggle(true); } int GpiClock::stop() { if (!clk_toggle_cb_hdl) { return -1; } gpi_remove_cb(clk_toggle_cb_hdl); clk_toggle_cb_hdl = nullptr; return 0; } int GpiClock::toggle(bool initialSet) { if (!initialSet) { clk_val = !clk_val; } gpi_set_signal_value_int(clk_signal, clk_val, m_set_action); uint64_t to_next_edge = clk_val ? t_high : (period - t_high); clk_toggle_cb_hdl = gpi_register_timed_callback(&GpiClock::toggle_cb, this, to_next_edge); if (!clk_toggle_cb_hdl) { // LCOV_EXCL_START if (!initialSet) { // Failing when called from start() will be reported via // exception, but log in case of later failure that would // otherwise be silent. LOG_ERROR("Clock will be stopped: failed to register toggle cb"); } return EAGAIN; // LCOV_EXCL_STOP } return 0; } int GpiClock::toggle_cb(void *gpi_clk) { GpiClock *clk_obj = (GpiClock *)gpi_clk; return clk_obj->toggle(false); } // Create a new clock object static PyObject *clock_create(PyObject *, PyObject *args) { if (!gpi_has_registered_impl()) { // LCOV_EXCL_START PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return NULL; // LCOV_EXCL_STOP } // Extract the clock signal sim object PyObject *pSigHdl; if (!PyArg_ParseTuple(args, "O!:clock_create", &gpi_hdl_Object::py_type, &pSigHdl)) { return NULL; } gpi_sim_hdl sim_hdl = ((gpi_hdl_Object *)pSigHdl)->hdl; GpiClock *gpi_clk = new GpiClock(sim_hdl); if (gpi_clk) { return gpi_hdl_New(gpi_clk); } else { // LCOV_EXCL_START PyErr_SetString(PyExc_RuntimeError, "Failed to create clock!"); return NULL; // LCOV_EXCL_STOP } } static void clock_dealloc(PyObject *self) { if (!gpi_has_registered_impl()) { // LCOV_EXCL_START PyErr_SetString(PyExc_RuntimeError, "No simulator available!"); return; // LCOV_EXCL_STOP } if (Py_TYPE(self) != &gpi_hdl_Object::py_type) { // LCOV_EXCL_START PyErr_SetString(PyExc_TypeError, "Wrong type for clock_dealloc!"); return; // LCOV_EXCL_STOP } GpiClock *gpi_clk = ((gpi_hdl_Object *)self)->hdl; delete gpi_clk; Py_TYPE(self)->tp_free((PyObject *)self); } static PyObject *clk_start(gpi_hdl_Object *self, PyObject *args) { unsigned long long period, t_high; int start_high; int set_action; if (!PyArg_ParseTuple(args, "KKpi:start", &period, &t_high, &start_high, &set_action)) { return NULL; } int ret = self->hdl->start(period, t_high, start_high, (gpi_set_action)set_action); if (ret != 0) { if (ret == EINVAL) { PyErr_SetString(PyExc_ValueError, "Failed to start clock: invalid arguments!\n"); } else if (ret == EBUSY) { PyErr_SetString(PyExc_RuntimeError, "Failed to start clock: already started!\n"); } else { // LCOV_EXCL_START PyErr_SetString(PyExc_RuntimeError, "Failed to start clock!\n"); // LCOV_EXCL_STOP } return NULL; } Py_RETURN_NONE; } static PyObject *clk_stop(gpi_hdl_Object *self, PyObject *) { self->hdl->stop(); Py_RETURN_NONE; } static int add_module_constants(PyObject *simulator) { // Make the GPI constants accessible from the C world if (PyModule_AddIntConstant(simulator, "UNKNOWN", GPI_UNKNOWN) < 0 || PyModule_AddIntConstant(simulator, "MEMORY", GPI_MEMORY) < 0 || PyModule_AddIntConstant(simulator, "MODULE", GPI_MODULE) < 0 || PyModule_AddIntConstant(simulator, "NETARRAY", GPI_ARRAY) < 0 || PyModule_AddIntConstant(simulator, "ENUM", GPI_ENUM) < 0 || PyModule_AddIntConstant(simulator, "STRUCTURE", GPI_STRUCTURE) < 0 || PyModule_AddIntConstant(simulator, "PACKED_STRUCTURE", GPI_PACKED_STRUCTURE) < 0 || PyModule_AddIntConstant(simulator, "REAL", GPI_REAL) < 0 || PyModule_AddIntConstant(simulator, "INTEGER", GPI_INTEGER) < 0 || PyModule_AddIntConstant(simulator, "STRING", GPI_STRING) < 0 || PyModule_AddIntConstant(simulator, "GENARRAY", GPI_GENARRAY) < 0 || PyModule_AddIntConstant(simulator, "PACKAGE", GPI_PACKAGE) < 0 || PyModule_AddIntConstant(simulator, "OBJECTS", GPI_OBJECTS) < 0 || PyModule_AddIntConstant(simulator, "DRIVERS", GPI_DRIVERS) < 0 || PyModule_AddIntConstant(simulator, "LOADS", GPI_LOADS) < 0 || PyModule_AddIntConstant(simulator, "RISING", GPI_RISING) < 0 || PyModule_AddIntConstant(simulator, "FALLING", GPI_FALLING) < 0 || PyModule_AddIntConstant(simulator, "VALUE_CHANGE", GPI_VALUE_CHANGE) < 0 || PyModule_AddIntConstant(simulator, "RANGE_UP", GPI_RANGE_UP) < 0 || PyModule_AddIntConstant(simulator, "RANGE_DOWN", GPI_RANGE_DOWN) < 0 || PyModule_AddIntConstant(simulator, "RANGE_NO_DIR", GPI_RANGE_NO_DIR) < 0 || PyModule_AddIntConstant(simulator, "LOGIC", GPI_LOGIC) < 0 || PyModule_AddIntConstant(simulator, "LOGIC_ARRAY", GPI_LOGIC_ARRAY) < 0 || false) { return -1; } return 0; } // Add the extension types as entries in the module namespace static int add_module_types(PyObject *simulator) { PyObject *typ; typ = (PyObject *)&gpi_hdl_Object::py_type; Py_INCREF(typ); if (PyModule_AddObject(simulator, "gpi_sim_hdl", typ) < 0) { Py_DECREF(typ); return -1; } typ = (PyObject *)&gpi_hdl_Object::py_type; Py_INCREF(typ); if (PyModule_AddObject(simulator, "gpi_cb_hdl", typ) < 0) { Py_DECREF(typ); return -1; } typ = (PyObject *)&gpi_hdl_Object::py_type; Py_INCREF(typ); if (PyModule_AddObject(simulator, "gpi_iterator_hdl", typ) < 0) { Py_DECREF(typ); return -1; } typ = (PyObject *)&gpi_hdl_Object::py_type; Py_INCREF(typ); if (PyModule_AddObject(simulator, "GpiClock", typ) < 0) { // LCOV_EXCL_START Py_DECREF(typ); return -1; // LCOV_EXCL_STOP } return 0; } /* NOTE: in the following docstrings we are specifying the parameters twice, but * this is necessary. The first docstring before the long '--' line specifies * the __text_signature__ that is used by the help() function. And the second * after the '--' line contains type annotations used by the * `autodoc_docstring_signature` setting of sphinx.ext.autodoc for generating * documentation because type annotations are not supported in * __text_signature__. */ static PyMethodDef SimulatorMethods[] = { {"get_root_handle", get_root_handle, METH_VARARGS, PyDoc_STR("get_root_handle(name, /)\n" "--\n\n" "get_root_handle(name: str) -> cocotb.simulator.gpi_sim_hdl\n" "Get the root handle.")}, {"package_iterate", package_iterate, METH_NOARGS, PyDoc_STR("package_iterate(/)\n" "--\n\n" "package_iterate() -> cocotb.simulator.gpi_iterator_hdl\n" "Get an iterator handle to loop over all HDL packages.\n" "\n" ".. versionadded:: 2.0")}, {"register_timed_callback", register_timed_callback, METH_VARARGS, PyDoc_STR("register_timed_callback(time, func, /, *args)\n" "--\n\n" "register_timed_callback(time: int, func: Callable[..., Any], " "*args: Any) -> cocotb.simulator.gpi_cb_hdl\n" "Register a timed callback.")}, {"register_value_change_callback", register_value_change_callback, METH_VARARGS, PyDoc_STR("register_value_change_callback(signal, func, edge, /, *args)\n" "--\n\n" "register_value_change_callback(signal: " "cocotb.simulator.gpi_sim_hdl, func: Callable[..., Any], edge: " "int, *args: Any) -> cocotb.simulator.gpi_cb_hdl\n" "Register a signal change callback.")}, {"register_readonly_callback", register_readonly_callback, METH_VARARGS, PyDoc_STR("register_readonly_callback(func, /, *args)\n" "--\n\n" "register_readonly_callback(func: Callable[..., Any], *args: " "Any) -> cocotb.simulator.gpi_cb_hdl\n" "Register a callback for the read-only phase.")}, {"register_nextstep_callback", register_nextstep_callback, METH_VARARGS, PyDoc_STR("register_nextstep_callback(func, /, *args)\n" "--\n\n" "register_nextstep_callback(func: Callable[..., Any], *args: " "Any) -> cocotb.simulator.gpi_cb_hdl\n" "Register a callback for the cbNextSimTime callback.")}, {"register_rwsynch_callback", register_rwsynch_callback, METH_VARARGS, PyDoc_STR("register_rwsynch_callback(func, /, *args)\n" "--\n\n" "register_rwsynch_callback(func: Callable[..., Any], *args: " "Any) -> cocotb.simulator.gpi_cb_hdl\n" "Register a callback for the read-write phase.")}, {"stop_simulator", stop_simulator, METH_VARARGS, PyDoc_STR("stop_simulator()\n" "--\n\n" "stop_simulator() -> None\n" "Instruct the attached simulator to stop. Users should not call " "this function.")}, {"set_gpi_log_level", set_gpi_log_level, METH_VARARGS, PyDoc_STR("set_gpi_log_level(level, /)\n" "--\n\n" "set_gpi_log_level(level: int) -> None\n" "Set the log level of GPI logger.")}, {"is_running", is_running, METH_NOARGS, PyDoc_STR("is_running()\n" "--\n\n" "is_running() -> bool\n" "Returns ``True`` if the caller is running within a simulator.\n" "\n" ".. versionadded:: 1.4")}, {"get_sim_time", get_sim_time, METH_NOARGS, PyDoc_STR("get_sim_time()\n" "--\n\n" "get_sim_time() -> Tuple[int, int]\n" "Get the current simulation time.\n" "\n" "Time is represented as a tuple of 32-bit integers (``(low32, " "high32)``) comprising a single 64-bit integer.")}, {"get_precision", get_precision, METH_NOARGS, PyDoc_STR("get_precision()\n" "--\n\n" "get_precision() -> int\n" "Get the precision of the simulator in powers of 10.\n" "\n" "For example, if ``-12`` is returned, the simulator's time " "precision is 10**-12 or 1 ps.")}, {"get_simulator_product", get_simulator_product, METH_NOARGS, PyDoc_STR("get_simulator_product()\n" "--\n\n" "get_simulator_product() -> str\n" "Get the simulator's product string.")}, {"get_simulator_version", get_simulator_version, METH_NOARGS, PyDoc_STR("get_simulator_version()\n" "--\n\n" "get_simulator_version() -> str\n" "Get the simulator's product version string.")}, {"clock_create", clock_create, METH_VARARGS, PyDoc_STR("clock_create(signal, /)\n" "--\n\n" "clock_create(signal: cocotb.simulator.gpi_sim_hdl" ") -> cocotb.simulator.GpiClock\n" "Create a clock driver on a signal.\n" "\n" ".. versionadded:: 2.0")}, {"initialize_logger", initialize_logger, METH_VARARGS, PyDoc_STR("initialize_logger(log_func, /)\n" "--\n\n" "initialize_logger(" "log_func: Callable[[Logger, int, str, int, str, str], None], " "get_logger: Callable[[str], Logger]" ") -> None\n" "Initialize the GPI logger with Python logging functions.")}, {"set_sim_event_callback", set_sim_event_callback, METH_VARARGS, PyDoc_STR("set_sim_event_callback(sim_event_callback, /)\n" "--\n\n" "set_sim_event_callback(sim_event_callback: Callable[[str], " "None]) -> None\n" "Set the callback for simulator events.")}, {NULL, NULL, 0, NULL} /* Sentinel */ }; static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT, MODULE_NAME, NULL, -1, SimulatorMethods, NULL, NULL, NULL, NULL}; #ifndef _WIN32 // Only required for Python < 3.9, default for 3.9+ (bpo-11410) #pragma GCC visibility push(default) PyMODINIT_FUNC PyInit_simulator(void); #pragma GCC visibility pop #endif PyMODINIT_FUNC PyInit_simulator(void) { /* initialize the extension types */ if (PyType_Ready(&gpi_hdl_Object::py_type) < 0) { return NULL; } if (PyType_Ready(&gpi_hdl_Object::py_type) < 0) { return NULL; } if (PyType_Ready(&gpi_hdl_Object::py_type) < 0) { return NULL; } if (PyType_Ready(&gpi_hdl_Object::py_type) < 0) { // LCOV_EXCL_START return NULL; // LCOV_EXCL_STOP } PyObject *simulator = PyModule_Create(&moduledef); if (simulator == NULL) { return NULL; } if (add_module_constants(simulator) < 0) { Py_DECREF(simulator); return NULL; } if (add_module_types(simulator) < 0) { Py_DECREF(simulator); return NULL; } return simulator; } /* NOTE: in the following docstrings we are specifying the parameters twice, but * this is necessary. The first docstring before the long '--' line specifies * the __text_signature__ that is used by the help() function. And the second * after the '--' line contains type annotations used by the * `autodoc_docstring_signature` setting of sphinx.ext.autodoc for generating * documentation because type annotations are not supported in * __text_signature__. */ static PyMethodDef gpi_sim_hdl_methods[] = { {"get_signal_val_long", (PyCFunction)get_signal_val_long, METH_NOARGS, PyDoc_STR("get_signal_val_long($self)\n" "--\n\n" "get_signal_val_long() -> int\n" "Get the value of a signal as an integer.")}, {"get_signal_val_str", (PyCFunction)get_signal_val_str, METH_NOARGS, PyDoc_STR("get_signal_val_str($self)\n" "--\n\n" "get_signal_val_str() -> bytes\n" "Get the value of a signal as a byte string.")}, {"get_signal_val_binstr", (PyCFunction)get_signal_val_binstr, METH_NOARGS, PyDoc_STR("get_signal_val_binstr($self)\n" "--\n\n" "get_signal_val_binstr() -> str\n" "Get the value of a logic vector signal as a string of (``0``, " "``1``, ``X``, etc.), one element per character.")}, {"get_signal_val_real", (PyCFunction)get_signal_val_real, METH_NOARGS, PyDoc_STR("get_signal_val_real($self)\n" "--\n\n" "get_signal_val_real() -> float\n" "Get the value of a signal as a float.")}, {"set_signal_val_int", (PyCFunction)set_signal_val_int, METH_VARARGS, PyDoc_STR("set_signal_val_int($self, action, value, /)\n" "--\n\n" "set_signal_val_int(action: int, value: int) -> None\n" "Set the value of a signal using an int.")}, {"set_signal_val_str", (PyCFunction)set_signal_val_str, METH_VARARGS, PyDoc_STR("set_signal_val_str($self, action, value, /)\n" "--\n\n" "set_signal_val_str(action: int, value: bytes) -> None\n" "Set the value of a signal using a user-encoded string.")}, {"set_signal_val_binstr", (PyCFunction)set_signal_val_binstr, METH_VARARGS, PyDoc_STR("set_signal_val_binstr($self, action, value, /)\n" "--\n\n" "set_signal_val_binstr(action: int, value: str) -> None\n" "Set the value of a logic vector signal using a string of " "(``0``, ``1``, ``X``, etc.), one element per character.")}, {"set_signal_val_real", (PyCFunction)set_signal_val_real, METH_VARARGS, PyDoc_STR("set_signal_val_real($self, action, value, /)\n" "--\n\n" "set_signal_val_real(action: int, value: float) -> None\n" "Set the value of a signal using a float.")}, {"get_definition_name", (PyCFunction)get_definition_name, METH_NOARGS, PyDoc_STR("get_definition_name($self)\n" "--\n\n" "get_definition_name() -> str\n" "Get the name of a GPI object's definition.")}, {"get_definition_file", (PyCFunction)get_definition_file, METH_NOARGS, PyDoc_STR("get_definition_file($self)\n" "--\n\n" "get_definition_file() -> str\n" "Get the file that sources the object's definition.")}, {"get_handle_by_name", (PyCFunction)get_handle_by_name, METH_VARARGS, PyDoc_STR( "get_handle_by_name($self, name, discovery_method/)\n" "--\n\n" "get_handle_by_name(name: str, discovery_method: " "cocotb.handle._GPIDiscovery) -> " "cocotb.simulator.gpi_sim_hdl\n" "Get a handle to a child object by name.\n" "Specify *discovery_method* to determine the signal discovery " "strategy. :data:`~cocotb.handle.GPIDiscovery.AUTO` by default.")}, {"get_handle_by_index", (PyCFunction)get_handle_by_index, METH_VARARGS, PyDoc_STR( "get_handle_by_index($self, index, /)\n" "--\n\n" "get_handle_by_index(index: int) -> cocotb.simulator.gpi_sim_hdl\n" "Get a handle to a child object by index.")}, {"get_name_string", (PyCFunction)get_name_string, METH_NOARGS, PyDoc_STR("get_name_string($self)\n" "--\n\n" "get_name_string() -> str\n" "Get the name of an object as a string.")}, {"get_type_string", (PyCFunction)get_type_string, METH_NOARGS, PyDoc_STR("get_type_string($self)\n" "--\n\n" "get_type_string() -> str\n" "Get the GPI type of an object as a string.")}, {"get_type", (PyCFunction)get_type, METH_NOARGS, PyDoc_STR("get_type($self)\n" "--\n\n" "get_type() -> int\n" "Get the GPI type of an object as an enum.")}, {"get_const", (PyCFunction)get_const, METH_NOARGS, PyDoc_STR("get_const($self)\n" "--\n\n" "get_const() -> bool\n" "Return ``True`` if the object is a constant.")}, {"get_num_elems", (PyCFunction)get_num_elems, METH_NOARGS, PyDoc_STR("get_num_elems($self)\n" "--\n\n" "get_num_elems() -> int\n" "Get the number of elements contained in the handle.")}, {"get_range", (PyCFunction)get_range, METH_NOARGS, PyDoc_STR("get_range($self)\n" "--\n\n" "get_range() -> Tuple[int, int, int]\n" "Get the range of elements (tuple) contained in the handle. " "The first two elements of the tuple specify the left and right " "bounds, while the third specifies the direction (``1`` for " "ascending, ``-1`` for descending, and ``0`` for undefined).")}, {"get_indexable", (PyCFunction)get_indexable, METH_NOARGS, PyDoc_STR("get_indexable($self)\n" "--\n\n" "get_indexable() -> bool\n" "Return ``True`` if indexable.")}, {"iterate", (PyCFunction)iterate, METH_VARARGS, PyDoc_STR( "iterate($self, mode, /)\n" "--\n\n" "iterate(mode: int) -> cocotb.simulator.gpi_iterator_hdl\n" "Get an iterator handle to loop over all members in an object.")}, {NULL, NULL, 0, NULL} /* Sentinel */ }; // putting these at the bottom means that all the functions above are accessible template <> PyTypeObject gpi_hdl_Object::py_type = []() -> PyTypeObject { auto type = fill_common_slots(); type.tp_name = "cocotb.simulator.gpi_sim_hdl"; type.tp_doc = "GPI object handle.\n" "\n" "Contains methods for getting and setting the value of a GPI object, " "and introspection."; type.tp_methods = gpi_sim_hdl_methods; return type; }(); template <> PyTypeObject gpi_hdl_Object::py_type = []() -> PyTypeObject { auto type = fill_common_slots(); type.tp_name = "cocotb.simulator.gpi_iterator_hdl"; type.tp_doc = "GPI iterator handle."; type.tp_iter = PyObject_SelfIter; type.tp_iternext = (iternextfunc)next; return type; }(); static PyMethodDef gpi_cb_hdl_methods[] = { {"deregister", (PyCFunction)deregister, METH_NOARGS, PyDoc_STR("deregister($self)\n" "--\n\n" "deregister() -> None\n" "De-register this callback.")}, {NULL, NULL, 0, NULL} /* Sentinel */ }; template <> PyTypeObject gpi_hdl_Object::py_type = []() -> PyTypeObject { auto type = fill_common_slots(); type.tp_name = "cocotb.simulator.gpi_cb_hdl"; type.tp_doc = "GPI callback handle."; type.tp_methods = gpi_cb_hdl_methods; return type; }(); static PyMethodDef gpi_clk_methods[] = { {"start", (PyCFunction)clk_start, METH_VARARGS, PyDoc_STR( "start($self, period_steps, high_steps, start_high)\n" "--\n\n" "start(period_steps: int, high_steps: int, start_high: bool) -> None\n" "Start this clock now.\n" "\n" "The clock will have a period of *period_steps* time steps, " "and out of that period it will be high for *high_steps* time steps. " "If *start_high* is ``True``, start at the beginning of the high " "state, " "otherwise start at the beginning of the low state.\n" "\n" "Raises:\n" " TypeError: If there are an incorrect number of arguments or " "they are of the wrong type.\n" " ValueError: If *period_steps* and *high_steps* are such that in " "one " "period the duration of the low or high state would be less " "than one time step, or *high_steps* is greater than *period_steps*.\n" " RuntimeError: If the clock was already started, or the " "GPI callback could not be registered.")}, {"stop", (PyCFunction)clk_stop, METH_NOARGS, PyDoc_STR("stop($self)\n" "--\n\n" "stop() -> None\n" "Stop this clock now.")}, {NULL, NULL, 0, NULL} /* Sentinel */ }; template <> PyTypeObject gpi_hdl_Object::py_type = []() -> PyTypeObject { auto type = fill_common_slots(); type.tp_name = "cocotb.simulator.GpiClock"; type.tp_doc = "C++ clock using the GPI."; type.tp_methods = gpi_clk_methods; type.tp_dealloc = clock_dealloc; return type; }(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3497026 cocotb-2.0.1/src/cocotb/share/lib/utils/0000755000175100017510000000000015106070715017503 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/utils/cocotb_utils.cpp0000644000175100017510000000440015106067236022702 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include #include #include #ifdef _WIN32 #include #else #include #endif // Tracks if we are in the context of Python or Simulator int is_python_context = 0; extern "C" void *utils_dyn_open(const char *lib_name) { void *ret = NULL; #ifdef _WIN32 SetErrorMode(0); ret = static_cast(LoadLibrary(lib_name)); if (!ret) { const char *log_fmt = "Unable to open lib %s%s%s"; LPSTR msg_ptr; if (FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), (LPSTR)&msg_ptr, 255, NULL)) { LOG_ERROR(log_fmt, lib_name, ": ", msg_ptr); LocalFree(msg_ptr); } else { LOG_ERROR(log_fmt, lib_name, "", ""); } } #else /* Clear status */ dlerror(); ret = dlopen(lib_name, RTLD_LAZY | RTLD_GLOBAL); if (!ret) { LOG_ERROR("Unable to open lib %s: %s", lib_name, dlerror()); } #endif return ret; } extern "C" void *utils_dyn_sym(void *handle, const char *sym_name) { void *entry_point; #ifdef _WIN32 entry_point = reinterpret_cast( GetProcAddress(static_cast(handle), sym_name)); if (!entry_point) { const char *log_fmt = "Unable to find symbol %s%s%s"; LPSTR msg_ptr; if (FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), (LPSTR)&msg_ptr, 255, NULL)) { LOG_ERROR(log_fmt, sym_name, ": ", msg_ptr); LocalFree(msg_ptr); } else { LOG_ERROR(log_fmt, sym_name, "", ""); } } #else entry_point = dlsym(handle, sym_name); if (!entry_point) { LOG_ERROR("Unable to find symbol %s: %s", sym_name, dlerror()); } #endif return entry_point; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3497026 cocotb-2.0.1/src/cocotb/share/lib/verilator/0000755000175100017510000000000015106070715020352 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/verilator/verilator.cpp0000644000175100017510000001367315106067236023103 0ustar00runnerrunner// Copyright cocotb contributors // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include // basename #include // stderr, fprintf #include // std::unique_ptr #include // std::string #include "Vtop.h" #include "verilated.h" #include "verilated_vpi.h" #ifndef VM_TRACE_FST // emulate new verilator behavior for legacy versions #define VM_TRACE_FST 0 #endif #if VM_TRACE #if VM_TRACE_FST #include using verilated_trace_t = VerilatedFstC; #else #include using verilated_trace_t = VerilatedVcdC; #endif static verilated_trace_t *tfp; #endif static vluint64_t main_time = 0; // Current simulation time double sc_time_stamp() { // Called by $time in Verilog return main_time; // converts to double, to match // what SystemC does } extern "C" { void vlog_startup_routines_bootstrap(void); } static inline bool settle_value_callbacks() { bool cbs_called, again; // Call Value Change callbacks // These can modify signal values so we loop // until there are no more changes cbs_called = again = VerilatedVpi::callValueCbs(); while (again) { again = VerilatedVpi::callValueCbs(); } return cbs_called; } void wrap_up() { VerilatedVpi::callCbs(cbEndOfSimulation); #if VM_TRACE if (tfp) { delete tfp; tfp = nullptr; } #endif // VM_COVERAGE is a define which is set if Verilator is // instructed to collect coverage (when compiling the simulation) #if VM_COVERAGE VerilatedCov::write(); // Uses +verilator+coverage+file+, // defaults to coverage.dat #endif } int main(int argc, char **argv) { #if VM_TRACE_FST const char *traceFile = "dump.fst"; #else const char *traceFile = "dump.vcd"; #endif bool traceOn = false; bool traceFlush = false; for (int i = 1; i < argc; i++) { std::string arg = std::string(argv[i]); if (arg == "--trace") { #if VM_TRACE traceOn = true; #else fprintf(stderr, "Error: --trace requires the design to be built with trace " "support\n"); return -1; #endif } else if (arg == "--trace-flush") { traceFlush = true; } else if (arg == "--trace-file") { if (++i < argc) { traceFile = argv[i]; } else { fprintf(stderr, "Error: --trace-file requires a parameter\n"); return -1; } } else if (arg == "--help") { fprintf( stderr, "usage: %s [--trace] [--trace-flush] [--trace-file TRACEFILE]\n" "\n" "cocotb + Verilator sim\n" "\n" "options:\n" " --trace Enable tracing (VCD or FST)\n" " --trace-flush Flush trace at each time step (slow)\n" " --trace-file Specify the trace file name (%s by " "default)\n", basename(argv[0]), traceFile); return 0; } } Verilated::commandArgs(argc, argv); #ifdef VERILATOR_SIM_DEBUG Verilated::debug(99); #endif std::unique_ptr top(new Vtop("")); Verilated::fatalOnVpiError(false); // otherwise it will fail on systemtf #ifdef VERILATOR_SIM_DEBUG Verilated::internalsDump(); #endif #if VM_TRACE Verilated::traceEverOn(true); if (traceOn) { tfp = new verilated_trace_t; top->trace(tfp, 99); tfp->open(traceFile); } #endif vlog_startup_routines_bootstrap(); Verilated::addExitCb([](void *) { wrap_up(); }, nullptr); VerilatedVpi::callCbs(cbStartOfSimulation); settle_value_callbacks(); while (!Verilated::gotFinish()) { do { // We must evaluate whole design until we process all 'events' for // this time step do { top->eval_step(); VerilatedVpi::clearEvalNeeded(); VerilatedVpi::doInertialPuts(); settle_value_callbacks(); } while (VerilatedVpi::evalNeeded()); // Run ReadWrite callback as we are done processing this eval step VerilatedVpi::callCbs(cbReadWriteSynch); VerilatedVpi::doInertialPuts(); settle_value_callbacks(); } while (VerilatedVpi::evalNeeded()); top->eval_end_step(); // Call ReadOnly callbacks VerilatedVpi::callCbs(cbReadOnlySynch); #if VM_TRACE if (tfp) { tfp->dump(main_time); if (traceFlush) { tfp->flush(); } } #endif // cocotb controls the clock inputs using cbAfterDelay so // skip ahead to the next registered callback const vluint64_t NO_TOP_EVENTS_PENDING = static_cast(~0ULL); vluint64_t next_time_cocotb = VerilatedVpi::cbNextDeadline(); vluint64_t next_time_timing = top->eventsPending() ? top->nextTimeSlot() : NO_TOP_EVENTS_PENDING; vluint64_t next_time = std::min(next_time_cocotb, next_time_timing); // If there are no more cbAfterDelay callbacks, // the next deadline is max value, so end the simulation now if (next_time == NO_TOP_EVENTS_PENDING) { break; } else { main_time = next_time; } // Call registered NextSimTime // It should be called in simulation cycle before everything else // but not on first cycle VerilatedVpi::callCbs(cbNextSimTime); settle_value_callbacks(); // Call registered timed callbacks (e.g. clock timer) // These are called at the beginning of the time step // before the iterative regions (IEEE 1800-2012 4.4.1) VerilatedVpi::callTimedCbs(); settle_value_callbacks(); } top->final(); wrap_up(); return 0; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3507025 cocotb-2.0.1/src/cocotb/share/lib/vhpi/0000755000175100017510000000000015106070715017311 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/vhpi/VhpiCbHdl.cpp0000644000175100017510000011357115106067236021634 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include #include // fixed-size int types and format strings #include #include // numeric_limits #include #include "VhpiImpl.h" #include "_vendor/vhpi/vhpi_user.h" namespace { using bufSize_type = decltype(vhpiValueT::bufSize); } // Main entry point for callbacks from simulator void handle_vhpi_callback(const vhpiCbDataT *cb_data) { gpi_to_user(); VhpiCbHdl *cb_hdl = (VhpiCbHdl *)cb_data->user_data; // LCOV_EXCL_START if (!cb_hdl) { LOG_CRITICAL("VHPI: Callback data corrupted: ABORTING"); gpi_embed_end(); return; } // LCOV_EXCL_STOP if (cb_hdl->run()) { // sim failed, so call shutdown gpi_embed_end(); } gpi_to_simulator(); } VhpiArrayObjHdl::~VhpiArrayObjHdl() { LOG_DEBUG("VHPI: Releasing VhpiArrayObjHdl handle for %s at %p", get_fullname_str(), (void *)get_handle()); if (vhpi_release_handle(get_handle())) check_vhpi_error(); } VhpiObjHdl::~VhpiObjHdl() { /* Don't release handles for pseudo-regions, as they borrow the handle of * the containing region */ if (m_type != GPI_GENARRAY) { LOG_DEBUG("VHPI: Releasing VhpiObjHdl handle for %s at %p", get_fullname_str(), (void *)get_handle()); if (vhpi_release_handle(get_handle())) check_vhpi_error(); } } VhpiSignalObjHdl::~VhpiSignalObjHdl() { switch (m_value.format) { case vhpiIntVecVal: case vhpiEnumVecVal: case vhpiLogicVecVal: delete[] m_value.value.enumvs; default: break; } if (m_binvalue.value.str) delete[] m_binvalue.value.str; LOG_DEBUG("VHPI: Releasing VhpiSignalObjHdl handle for %s at %p", get_fullname_str(), (void *)get_handle()); if (vhpi_release_handle(get_handle())) check_vhpi_error(); } bool get_range(vhpiHandleT hdl, vhpiIntT dim, int *left, int *right, gpi_range_dir *dir) { #ifdef IUS /* IUS/Xcelium does not appear to set the vhpiIsUnconstrainedP property. IUS * Docs say will return -1 if unconstrained, but with vhpiIntT being * unsigned, the value returned is below. */ const vhpiIntT UNCONSTRAINED = 2147483647; #endif bool error = true; vhpiHandleT base_hdl = vhpi_handle(vhpiBaseType, hdl); if (base_hdl == NULL) { vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, hdl); if (st_hdl != NULL) { base_hdl = vhpi_handle(vhpiBaseType, st_hdl); vhpi_release_handle(st_hdl); } } if (base_hdl != NULL) { vhpiHandleT it = vhpi_iterator(vhpiConstraints, base_hdl); vhpiIntT curr_idx = 0; if (it != NULL) { vhpiHandleT constraint; while ((constraint = vhpi_scan(it)) != NULL) { if (curr_idx == dim) { vhpi_release_handle(it); vhpiIntT l_rng = vhpi_get(vhpiLeftBoundP, constraint); vhpiIntT r_rng = vhpi_get(vhpiRightBoundP, constraint); #ifdef IUS if (l_rng != UNCONSTRAINED && r_rng != UNCONSTRAINED) { #else if (!vhpi_get(vhpiIsUnconstrainedP, constraint)) { #endif error = false; *left = static_cast(l_rng); *right = static_cast(r_rng); #ifdef MODELSIM /* Issue #4236: Questa's VHPI sets vhpiIsUpP incorrectly * so we must rely on the values of `left` and `right` * to infer direction. */ if (*left < *right) { #else if (vhpi_get(vhpiIsUpP, constraint) == 1) { #endif *dir = GPI_RANGE_UP; } else { *dir = GPI_RANGE_DOWN; } } break; } ++curr_idx; } } vhpi_release_handle(base_hdl); } if (error) { vhpiHandleT sub_type_hdl = vhpi_handle(vhpiSubtype, hdl); if (sub_type_hdl != NULL) { vhpiHandleT it = vhpi_iterator(vhpiConstraints, sub_type_hdl); vhpiIntT curr_idx = 0; if (it != NULL) { vhpiHandleT constraint; while ((constraint = vhpi_scan(it)) != NULL) { if (curr_idx == dim) { vhpi_release_handle(it); /* IUS/Xcelium only sets the vhpiIsUnconstrainedP * incorrectly on the base type */ if (!vhpi_get(vhpiIsUnconstrainedP, constraint)) { error = false; *left = static_cast( vhpi_get(vhpiLeftBoundP, constraint)); *right = static_cast( vhpi_get(vhpiRightBoundP, constraint)); #ifdef MODELSIM /* Issue #4236: See above */ if (*left < *right) { #else if (vhpi_get(vhpiIsUpP, constraint) == 1) { #endif *dir = GPI_RANGE_UP; } else { *dir = GPI_RANGE_DOWN; } } break; } ++curr_idx; } } vhpi_release_handle(sub_type_hdl); } } return error; } vhpiPutValueModeT map_put_value_mode(gpi_set_action action) { vhpiPutValueModeT put_value_mode = vhpiDeposit; switch (action) { case GPI_DEPOSIT: case GPI_NO_DELAY: put_value_mode = vhpiDepositPropagate; break; case GPI_FORCE: put_value_mode = vhpiForcePropagate; break; case GPI_RELEASE: put_value_mode = vhpiRelease; break; default: assert(0); } return put_value_mode; } int VhpiArrayObjHdl::initialise(const std::string &name, const std::string &fq_name) { vhpiHandleT handle = GpiObjHdl::get_handle(); m_indexable = true; vhpiHandleT type = vhpi_handle(vhpiBaseType, handle); if (type == NULL) { vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, handle); if (st_hdl != NULL) { type = vhpi_handle(vhpiBaseType, st_hdl); vhpi_release_handle(st_hdl); } } if (NULL == type) { LOG_ERROR("VHPI: Unable to get vhpiBaseType for %s", fq_name.c_str()); return -1; } vhpiIntT num_dim = vhpi_get(vhpiNumDimensionsP, type); vhpiIntT dim_idx = 0; /* Need to determine which dimension constraint is needed */ if (num_dim > 1) { std::string hdl_name = vhpi_get_str(vhpiCaseNameP, handle); if (hdl_name.length() < name.length()) { std::string pseudo_idx = name.substr(hdl_name.length()); while (pseudo_idx.length() > 0) { std::size_t found = pseudo_idx.find_first_of(")"); if (found != std::string::npos) { ++dim_idx; pseudo_idx = pseudo_idx.substr(found + 1); } else { break; } } } } bool error = get_range(handle, dim_idx, &m_range_left, &m_range_right, &m_range_dir); if (error) { LOG_ERROR( "VHPI: Unable to obtain constraints for an indexable object %s.", fq_name.c_str()); return -1; } if (m_range_dir == GPI_RANGE_DOWN) { m_num_elems = m_range_left - m_range_right + 1; } else { m_num_elems = m_range_right - m_range_left + 1; } if (m_num_elems < 0) { m_num_elems = 0; } return GpiObjHdl::initialise(name, fq_name); } int VhpiObjHdl::initialise(const std::string &name, const std::string &fq_name) { vhpiHandleT handle = GpiObjHdl::get_handle(); if (handle != NULL && m_type != GPI_STRUCTURE) { vhpiHandleT du_handle = vhpi_handle(vhpiDesignUnit, handle); if (du_handle != NULL) { vhpiHandleT pu_handle = vhpi_handle(vhpiPrimaryUnit, du_handle); if (pu_handle != NULL) { const char *str; str = vhpi_get_str(vhpiNameP, pu_handle); if (str != NULL) m_definition_name = str; str = vhpi_get_str(vhpiFileNameP, pu_handle); if (str != NULL) m_definition_file = str; } } } return GpiObjHdl::initialise(name, fq_name); } int VhpiSignalObjHdl::initialise(const std::string &name, const std::string &fq_name) { // Determine the type of object, either scalar or vector m_value.format = vhpiObjTypeVal; m_value.bufSize = 0; m_value.value.str = NULL; m_value.numElems = 0; /* We also alloc a second value member for use with read string operations */ m_binvalue.format = vhpiBinStrVal; m_binvalue.bufSize = 0; m_binvalue.numElems = 0; m_binvalue.value.str = NULL; vhpiHandleT handle = GpiObjHdl::get_handle(); if (0 > vhpi_get_value(get_handle(), &m_value)) { LOG_ERROR("VHPI: vhpi_get_value failed for %s (%s)", fq_name.c_str(), vhpi_get_str(vhpiKindStrP, handle)); return -1; } LOG_DEBUG( "VHPI: Found %s of format type %s (%d) format object with %d elems " "buffsize %d size %d", name.c_str(), ((VhpiImpl *)GpiObjHdl::m_impl)->format_to_string(m_value.format), m_value.format, m_value.numElems, m_value.bufSize, vhpi_get(vhpiSizeP, handle)); // Default - overridden below in certain special cases m_num_elems = m_value.numElems; switch (m_value.format) { case vhpiIntVal: case vhpiEnumVal: case vhpiSmallEnumVal: case vhpiRealVal: case vhpiCharVal: { break; } case vhpiStrVal: { m_indexable = true; m_num_elems = static_cast(vhpi_get(vhpiSizeP, handle)); int bufSize = m_num_elems * static_cast(sizeof(vhpiCharT)) + 1; m_value.bufSize = static_cast(bufSize); m_value.value.str = new vhpiCharT[bufSize]; m_value.numElems = m_num_elems; LOG_DEBUG("VHPI: Overriding num_elems to %d", m_num_elems); break; } default: { LOG_ERROR( "VHPI: Unable to determine property for %s (%d) format object", ((VhpiImpl *)GpiObjHdl::m_impl) ->format_to_string(m_value.format), m_value.format); return -1; } } if (m_indexable && get_range(handle, 0, &m_range_left, &m_range_right, &m_range_dir)) { m_indexable = false; } if (m_num_elems) { int bufSize = m_num_elems * static_cast(sizeof(vhpiCharT)) + 1; m_binvalue.bufSize = static_cast(bufSize); m_binvalue.value.str = new vhpiCharT[bufSize]; } return GpiObjHdl::initialise(name, fq_name); } int VhpiLogicSignalObjHdl::initialise(const std::string &name, const std::string &fq_name) { // Determine the type of object, either scalar or vector m_value.format = vhpiLogicVal; m_value.bufSize = 0; m_value.value.str = NULL; m_value.numElems = 0; /* We also alloc a second value member for use with read string operations */ m_binvalue.format = vhpiBinStrVal; m_binvalue.bufSize = 0; m_binvalue.numElems = 0; m_binvalue.value.str = NULL; vhpiHandleT handle = GpiObjHdl::get_handle(); vhpiHandleT base_hdl = vhpi_handle(vhpiBaseType, handle); if (base_hdl == NULL) { vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, handle); if (st_hdl != NULL) { base_hdl = vhpi_handle(vhpiBaseType, st_hdl); vhpi_release_handle(st_hdl); } } vhpiHandleT query_hdl = (base_hdl != NULL) ? base_hdl : handle; m_num_elems = static_cast(vhpi_get(vhpiSizeP, handle)); if (m_num_elems == 0) { LOG_DEBUG("VHPI: Null vector... Delete object"); return -1; } if (vhpi_get(vhpiKindP, query_hdl) == vhpiArrayTypeDeclK) { m_indexable = true; m_value.format = vhpiLogicVecVal; int bufSize = m_num_elems * static_cast(sizeof(vhpiEnumT)); m_value.bufSize = static_cast(bufSize); m_value.value.enumvs = new vhpiEnumT[bufSize]; } if (m_indexable && get_range(handle, 0, &m_range_left, &m_range_right, &m_range_dir)) { m_indexable = false; } if (m_num_elems) { int bufSize = m_num_elems * static_cast(sizeof(vhpiCharT)) + 1; m_binvalue.bufSize = static_cast(bufSize); m_binvalue.value.str = new vhpiCharT[bufSize]; } return GpiObjHdl::initialise(name, fq_name); } VhpiCbHdl::VhpiCbHdl(GpiImplInterface *impl) : GpiCbHdl(impl) { cb_data.reason = 0; cb_data.cb_rtn = handle_vhpi_callback; cb_data.obj = NULL; cb_data.time = NULL; cb_data.value = NULL; cb_data.user_data = (char *)this; vhpi_time.high = 0; vhpi_time.low = 0; } int VhpiCbHdl::remove() { auto err = vhpi_remove_cb(get_handle()); // LCOV_EXCL_START if (err) { LOG_DEBUG("VHPI: Unable to remove callback!"); check_vhpi_error(); // If we fail to remove the callback, mark it as removed so once it // fires we can squash it then remove the callback cleanly. m_removed = true; } // LCOV_EXCL_STOP else { delete this; } return 0; } int VhpiCbHdl::arm() { vhpiHandleT new_hdl = vhpi_register_cb(&cb_data, vhpiReturnCb); // LCOV_EXCL_START if (!new_hdl) { check_vhpi_error(); LOG_ERROR( "VHPI: Unable to register a callback handle for VHPI type " "%s(%d)", m_impl->reason_to_string(cb_data.reason), cb_data.reason); check_vhpi_error(); return -1; } // LCOV_EXCL_STOP m_obj_hdl = new_hdl; return 0; } int VhpiCbHdl::run() { int res = 0; // LCOV_EXCL_START if (!m_removed) { // Only call up if not removed. res = m_cb_func(m_cb_data); } // LCOV_EXCL_STOP // Many callbacks in VHPI are recurring, so we try to remove them after they // fire. For the callbacks that aren't recurring, this doesn't seem to make // the simulator unhappy, so whatever. auto err = vhpi_remove_cb(get_handle()); // LCOV_EXCL_START if (err) { LOG_DEBUG("VHPI: Unable to remove callback!"); check_vhpi_error(); // If we fail to remove the callback, mark it as removed so if it fires // we can squash it. m_removed = true; } // LCOV_EXCL_STOP else { delete this; } return res; } // Value related functions vhpiEnumT VhpiSignalObjHdl::chr2vhpi(const char value) { switch (value) { case '0': return vhpi0; case '1': return vhpi1; case 'U': case 'u': return vhpiU; case 'Z': case 'z': return vhpiZ; case 'X': case 'x': return vhpiX; case 'W': case 'w': return vhpiW; case 'L': case 'l': return vhpiL; case 'H': case 'h': return vhpiH; case '-': return vhpiDontCare; default: LOG_ERROR("VHPI: Character '%c' is not a valid vhpiEnumT", value); return vhpiDontCare; } } // Value related functions int VhpiLogicSignalObjHdl::set_signal_value(int32_t value, gpi_set_action action) { switch (m_value.format) { case vhpiEnumVal: case vhpiLogicVal: { m_value.value.enumv = value ? vhpi1 : vhpi0; break; } case vhpiEnumVecVal: case vhpiLogicVecVal: { int i; for (i = 0; i < m_num_elems; i++) m_value.value.enumvs[m_num_elems - i - 1] = value & (1 << i) ? vhpi1 : vhpi0; m_value.numElems = m_num_elems; break; } default: { LOG_ERROR( "VHPI: Unable to set a std_logic signal with a raw value"); return -1; } } if (vhpi_put_value(GpiObjHdl::get_handle(), &m_value, map_put_value_mode(action))) { check_vhpi_error(); return -1; } return 0; } int VhpiLogicSignalObjHdl::set_signal_value_binstr(std::string &value, gpi_set_action action) { switch (m_value.format) { case vhpiEnumVal: case vhpiLogicVal: { m_value.value.enumv = chr2vhpi(value.c_str()[0]); break; } case vhpiEnumVecVal: case vhpiLogicVecVal: { if ((int)value.length() != m_num_elems) { LOG_ERROR( "VHPI: Unable to set logic vector due to the string having " "incorrect length. Length of %d needs to be %d", value.length(), m_num_elems); return -1; } m_value.numElems = m_num_elems; std::string::iterator iter; int i = 0; for (iter = value.begin(); (iter != value.end()) && (i < m_num_elems); iter++, i++) { m_value.value.enumvs[i] = chr2vhpi(*iter); } break; } default: { LOG_ERROR( "VHPI: Unable to set a std_logic signal with a raw value"); return -1; } } if (vhpi_put_value(GpiObjHdl::get_handle(), &m_value, map_put_value_mode(action))) { check_vhpi_error(); return -1; } return 0; } // Value related functions int VhpiSignalObjHdl::set_signal_value(int32_t value, gpi_set_action action) { switch (m_value.format) { case vhpiEnumVecVal: case vhpiLogicVecVal: { int i; for (i = 0; i < m_num_elems; i++) m_value.value.enumvs[m_num_elems - i - 1] = value & (1 << i) ? vhpi1 : vhpi0; // Since we may not get the numElems correctly from the sim and have // to infer it we also need to set it here as well each time. m_value.numElems = m_num_elems; break; } case vhpiLogicVal: case vhpiEnumVal: { m_value.value.enumv = static_cast(value); break; } case vhpiSmallEnumVal: { m_value.value.smallenumv = static_cast(value); break; } case vhpiIntVal: { m_value.value.intg = static_cast(value); break; } case vhpiCharVal: { using CharLimits = std::numeric_limits; if ((value > CharLimits::max()) || (value < CharLimits::min())) { LOG_ERROR("VHPI: Data loss detected"); return -1; } m_value.value.ch = static_cast(value); break; } default: { LOG_ERROR("VHPI: Unable to handle this format type %s", ((VhpiImpl *)GpiObjHdl::m_impl) ->format_to_string(m_value.format)); return -1; } } if (vhpi_put_value(GpiObjHdl::get_handle(), &m_value, map_put_value_mode(action))) { check_vhpi_error(); return -1; } return 0; } int VhpiSignalObjHdl::set_signal_value(double value, gpi_set_action action) { switch (m_value.format) { case vhpiRealVal: m_value.numElems = 1; m_value.bufSize = sizeof(value); m_value.value.real = value; break; default: { LOG_ERROR("VHPI: Unable to set a Real handle with format type %s", ((VhpiImpl *)GpiObjHdl::m_impl) ->format_to_string(m_value.format)); return -1; } } if (vhpi_put_value(GpiObjHdl::get_handle(), &m_value, map_put_value_mode(action))) { check_vhpi_error(); return -1; } return 0; } int VhpiSignalObjHdl::set_signal_value_binstr(std::string &value, gpi_set_action action) { switch (m_value.format) { case vhpiEnumVal: case vhpiLogicVal: { m_value.value.enumv = chr2vhpi(value.c_str()[0]); break; } case vhpiEnumVecVal: case vhpiLogicVecVal: { if ((int)value.length() != m_num_elems) { LOG_ERROR( "VHPI: Unable to set logic vector due to the string having " "incorrect length. Length of %d needs to be %d", value.length(), m_num_elems); return -1; } m_value.numElems = m_num_elems; std::string::iterator iter; int i = 0; for (iter = value.begin(); (iter != value.end()) && (i < m_num_elems); iter++, i++) { m_value.value.enumvs[i] = chr2vhpi(*iter); } break; } default: { LOG_ERROR("VHPI: Unable to handle this format type: %s", ((VhpiImpl *)GpiObjHdl::m_impl) ->format_to_string(m_value.format)); return -1; } } if (vhpi_put_value(GpiObjHdl::get_handle(), &m_value, map_put_value_mode(action))) { check_vhpi_error(); return -1; } return 0; } int VhpiSignalObjHdl::set_signal_value_str(std::string &value, gpi_set_action action) { switch (m_value.format) { case vhpiStrVal: { std::vector writable(value.begin(), value.end()); writable.push_back('\0'); strncpy(m_value.value.str, &writable[0], static_cast(m_value.numElems)); m_value.value.str[m_value.numElems] = '\0'; break; } default: { LOG_ERROR("VHPI: Unable to handle this format type: %s", ((VhpiImpl *)GpiObjHdl::m_impl) ->format_to_string(m_value.format)); return -1; } } if (vhpi_put_value(GpiObjHdl::get_handle(), &m_value, map_put_value_mode(action))) { check_vhpi_error(); return -1; } return 0; } const char *VhpiSignalObjHdl::get_signal_value_binstr() { switch (m_value.format) { case vhpiRealVal: LOG_INFO("VHPI: get_signal_value_binstr not supported for %s", ((VhpiImpl *)GpiObjHdl::m_impl) ->format_to_string(m_value.format)); return ""; default: { /* Some simulators do not support BinaryValues so we fake up here * for them */ int ret = vhpi_get_value(GpiObjHdl::get_handle(), &m_binvalue); if (ret) { check_vhpi_error(); LOG_ERROR( "VHPI: Size of m_binvalue.value.str was not large enough: " "req=%d have=%d for type %s", ret, m_binvalue.bufSize, ((VhpiImpl *)GpiObjHdl::m_impl) ->format_to_string(m_value.format)); } return m_binvalue.value.str; } } } const char *VhpiSignalObjHdl::get_signal_value_str() { switch (m_value.format) { case vhpiStrVal: { int ret = vhpi_get_value(GpiObjHdl::get_handle(), &m_value); if (ret) { check_vhpi_error(); LOG_ERROR( "VHPI: Size of m_value.value.str was not large enough: " "req=%d have=%d for type %s", ret, m_value.bufSize, ((VhpiImpl *)GpiObjHdl::m_impl) ->format_to_string(m_value.format)); } break; } default: { LOG_ERROR("VHPI: Reading strings not valid for this handle"); return ""; } } return m_value.value.str; } double VhpiSignalObjHdl::get_signal_value_real() { m_value.format = vhpiRealVal; m_value.numElems = 1; m_value.bufSize = sizeof(double); if (vhpi_get_value(GpiObjHdl::get_handle(), &m_value)) { check_vhpi_error(); LOG_ERROR("VHPI: Failed to get value of type real"); } return m_value.value.real; } long VhpiSignalObjHdl::get_signal_value_long() { vhpiValueT value; value.format = vhpiIntVal; value.numElems = 0; if (vhpi_get_value(GpiObjHdl::get_handle(), &value)) { check_vhpi_error(); LOG_ERROR("VHPI: Failed to get value of type long"); } return static_cast(value.value.intg); } GpiCbHdl *VhpiSignalObjHdl::register_value_change_callback( gpi_edge edge, int (*cb_func)(void *), void *cb_data) { auto cb_hdl = new VhpiValueCbHdl(m_impl, this, edge); auto err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { delete cb_hdl; return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } VhpiValueCbHdl::VhpiValueCbHdl(GpiImplInterface *impl, VhpiSignalObjHdl *sig, gpi_edge edge) : VhpiCbHdl(impl), m_signal(sig), m_edge(edge) { cb_data.reason = vhpiCbValueChange; cb_data.time = &vhpi_time; cb_data.obj = m_signal->get_handle(); } int VhpiValueCbHdl::run() { // LCOV_EXCL_START if (m_removed) { // Only call up if not removed. return 0; } // LCOV_EXCL_STOP bool pass = false; switch (m_edge) { case GPI_RISING: { pass = !strcmp(m_signal->get_signal_value_binstr(), "1"); break; } case GPI_FALLING: { pass = !strcmp(m_signal->get_signal_value_binstr(), "0"); break; } case GPI_VALUE_CHANGE: { pass = true; break; } } int res = 0; if (pass) { res = m_cb_func(m_cb_data); // Remove recurring callback once fired auto err = vhpi_remove_cb(get_handle()); // LCOV_EXCL_START if (err) { LOG_DEBUG("VHPI: Unable to remove callback!"); check_vhpi_error(); // If we fail to remove the callback, mark it as removed so if it // fires we can squash it. m_removed = true; } // LCOV_EXCL_STOP else { delete this; } } // else Don't remove and let it fire again. return res; } VhpiStartupCbHdl::VhpiStartupCbHdl(GpiImplInterface *impl) : VhpiCbHdl(impl) { cb_data.reason = vhpiCbStartOfSimulation; } VhpiShutdownCbHdl::VhpiShutdownCbHdl(GpiImplInterface *impl) : VhpiCbHdl(impl) { cb_data.reason = vhpiCbEndOfSimulation; } VhpiTimedCbHdl::VhpiTimedCbHdl(GpiImplInterface *impl, uint64_t time) : VhpiCbHdl(impl) { vhpi_time.high = (uint32_t)(time >> 32); vhpi_time.low = (uint32_t)(time); cb_data.reason = vhpiCbAfterDelay; cb_data.time = &vhpi_time; } VhpiReadWriteCbHdl::VhpiReadWriteCbHdl(GpiImplInterface *impl) : VhpiCbHdl(impl) { cb_data.reason = vhpiCbRepLastKnownDeltaCycle; cb_data.time = &vhpi_time; } VhpiReadOnlyCbHdl::VhpiReadOnlyCbHdl(GpiImplInterface *impl) : VhpiCbHdl(impl) { cb_data.reason = vhpiCbRepEndOfTimeStep; cb_data.time = &vhpi_time; } VhpiNextPhaseCbHdl::VhpiNextPhaseCbHdl(GpiImplInterface *impl) : VhpiCbHdl(impl) { cb_data.reason = vhpiCbRepNextTimeStep; cb_data.time = &vhpi_time; } decltype(VhpiIterator::iterate_over) VhpiIterator::iterate_over = [] { /* for reused lists */ std::initializer_list root_options = { vhpiInternalRegions, vhpiSigDecls, vhpiVarDecls, vhpiPortDecls, vhpiGenericDecls, vhpiConstDecls, // vhpiIndexedNames, vhpiCompInstStmts, vhpiBlockStmts, }; std::initializer_list sig_options = { vhpiIndexedNames, vhpiSelectedNames, }; std::initializer_list simplesig_options = { vhpiDecls, vhpiInternalRegions, vhpiSensitivitys, vhpiStmts, }; std::initializer_list gen_options = { vhpiDecls, vhpiInternalRegions, vhpiSigDecls, vhpiVarDecls, vhpiConstDecls, vhpiCompInstStmts, vhpiBlockStmts, }; return decltype(VhpiIterator::iterate_over){ {vhpiRootInstK, root_options}, {vhpiCompInstStmtK, root_options}, {vhpiGenericDeclK, sig_options}, {vhpiSigDeclK, sig_options}, {vhpiSelectedNameK, sig_options}, {vhpiIndexedNameK, sig_options}, {vhpiPortDeclK, sig_options}, {vhpiCondSigAssignStmtK, simplesig_options}, {vhpiSimpleSigAssignStmtK, simplesig_options}, {vhpiSelectSigAssignStmtK, simplesig_options}, {vhpiForGenerateK, gen_options}, {vhpiIfGenerateK, gen_options}, {vhpiBlockStmtK, gen_options}, {vhpiConstDeclK, { vhpiAttrSpecs, vhpiIndexedNames, vhpiSelectedNames, }}, }; }(); VhpiIterator::VhpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl) : GpiIterator(impl, hdl), m_iterator(NULL), m_iter_obj(NULL) { vhpiHandleT iterator; vhpiHandleT vhpi_hdl = m_parent->get_handle(); vhpiClassKindT type = (vhpiClassKindT)vhpi_get(vhpiKindP, vhpi_hdl); try { selected = &iterate_over.at(type); } catch (std::out_of_range const &) { LOG_WARN( "VHPI: Implementation does not know how to iterate over %s(%d)", vhpi_get_str(vhpiKindStrP, vhpi_hdl), type); selected = nullptr; return; } /* Find the first mapping type that yields a valid iterator */ for (one2many = selected->begin(); one2many != selected->end(); one2many++) { /* GPI_GENARRAY are pseudo-regions and all that should be searched for * are the sub-regions */ if (m_parent->get_type() == GPI_GENARRAY && *one2many != vhpiInternalRegions) { LOG_DEBUG( "VHPI: vhpi_iterator vhpiOneToManyT=%d skipped for " "GPI_GENARRAY type", *one2many); continue; } iterator = vhpi_iterator(*one2many, vhpi_hdl); if (iterator) break; LOG_DEBUG("VHPI: vhpi_iterate vhpiOneToManyT=%d returned NULL", *one2many); } if (NULL == iterator) { LOG_DEBUG( "VHPI: vhpi_iterate return NULL for all relationships on %s (%d) " "kind:%s", vhpi_get_str(vhpiCaseNameP, vhpi_hdl), type, vhpi_get_str(vhpiKindStrP, vhpi_hdl)); selected = NULL; return; } LOG_DEBUG("VHPI: Created iterator working from scope %d (%s)", vhpi_get(vhpiKindP, vhpi_hdl), vhpi_get_str(vhpiKindStrP, vhpi_hdl)); /* On some simulators (Aldec) vhpiRootInstK is a null level of hierarchy. * We check that something is going to come back, if not, we try the level * down. */ m_iter_obj = vhpi_hdl; m_iterator = iterator; } VhpiIterator::~VhpiIterator() { if (m_iterator) vhpi_release_handle(m_iterator); } #define VHPI_TYPE_MIN (1000) GpiIterator::Status VhpiIterator::next_handle(std::string &name, GpiObjHdl **hdl, void **raw_hdl) { vhpiHandleT obj; GpiObjHdl *new_obj; if (!selected) return GpiIterator::END; gpi_objtype obj_type = m_parent->get_type(); std::string parent_name = m_parent->get_name(); /* We want the next object in the current mapping. * If the end of mapping is reached then we want to * try the next one until a new object is found. */ do { obj = NULL; if (m_iterator) { obj = vhpi_scan(m_iterator); /* For GPI_GENARRAY, only allow the generate statements through that * match the name of the generate block. */ if (obj != NULL && obj_type == GPI_GENARRAY) { if (vhpi_get(vhpiKindP, obj) == vhpiForGenerateK) { std::string rgn_name = vhpi_get_str(vhpiCaseNameP, obj); if (!VhpiImpl::compare_generate_labels(rgn_name, parent_name)) { obj = NULL; continue; } } else { obj = NULL; continue; } } if (obj != NULL && (vhpiProcessStmtK == vhpi_get(vhpiKindP, obj) || vhpiCondSigAssignStmtK == vhpi_get(vhpiKindP, obj) || vhpiSimpleSigAssignStmtK == vhpi_get(vhpiKindP, obj) || vhpiSelectSigAssignStmtK == vhpi_get(vhpiKindP, obj))) { LOG_DEBUG("VHPI: Skipping %s (%s)", vhpi_get_str(vhpiFullNameP, obj), vhpi_get_str(vhpiKindStrP, obj)); obj = NULL; continue; } if (obj != NULL) { LOG_DEBUG("VHPI: Found an item %s", vhpi_get_str(vhpiFullNameP, obj)); break; } else { LOG_DEBUG("VHPI: vhpi_scan on vhpiOneToManyT=%d returned NULL", *one2many); } LOG_DEBUG("VHPI: End of vhpiOneToManyT=%d iteration", *one2many); m_iterator = NULL; } else { LOG_DEBUG("VHPI: No valid vhpiOneToManyT=%d iterator", *one2many); } if (++one2many >= selected->end()) { obj = NULL; break; } /* GPI_GENARRAY are pseudo-regions and all that should be searched for * are the sub-regions */ if (obj_type == GPI_GENARRAY && *one2many != vhpiInternalRegions) { LOG_DEBUG( "VHPI: vhpi_iterator vhpiOneToManyT=%d skipped for " "GPI_GENARRAY type", *one2many); continue; } m_iterator = vhpi_iterator(*one2many, m_iter_obj); } while (!obj); if (NULL == obj) { LOG_DEBUG("VHPI: No more children, all relationships have been tested"); return GpiIterator::END; } const char *c_name = vhpi_get_str(vhpiCaseNameP, obj); if (!c_name) { vhpiIntT type = vhpi_get(vhpiKindP, obj); if (type < VHPI_TYPE_MIN) { *raw_hdl = (void *)obj; return GpiIterator::NOT_NATIVE_NO_NAME; } LOG_DEBUG( "VHPI: Unable to get the name for this object of type " PRIu32, type); return GpiIterator::NATIVE_NO_NAME; } /* * If the parent is not a generate loop, then watch for generate handles and * create the pseudo-region. * * NOTE: Taking advantage of the "caching" to only create one pseudo-region * object. Otherwise a list would be required and checked while iterating */ if (*one2many == vhpiInternalRegions && obj_type != GPI_GENARRAY && vhpi_get(vhpiKindP, obj) == vhpiForGenerateK) { std::string idx_str = c_name; std::size_t found = idx_str.rfind(GEN_IDX_SEP_LHS); if (found != std::string::npos && found != 0) { name = idx_str.substr(0, found); obj = m_parent->get_handle(); } else { LOG_WARN("VHPI: Unhandled Generate Loop Format - %s", name.c_str()); name = c_name; } } else { name = c_name; } LOG_DEBUG("VHPI: vhpi_scan found %s (%d) kind:%s name:%s", name.c_str(), vhpi_get(vhpiKindP, obj), vhpi_get_str(vhpiKindStrP, obj), vhpi_get_str(vhpiCaseNameP, obj)); /* We try and create a handle internally, if this is not possible we return and GPI will try other implementations with the name */ std::string fq_name = m_parent->get_fullname(); if (fq_name == ":") { fq_name += name; } else if (obj_type == GPI_GENARRAY) { std::size_t found = name.rfind(GEN_IDX_SEP_LHS); if (found != std::string::npos) { fq_name += name.substr(found); } else { LOG_WARN("VHPI: Unhandled Sub-Element Format - %s", name.c_str()); fq_name += "." + name; } } else if (obj_type == GPI_STRUCTURE) { std::size_t found = name.rfind("."); if (found != std::string::npos) { fq_name += name.substr(found); name = name.substr(found + 1); } else { LOG_WARN("VHPI: Unhandled Sub-Element Format - %s", name.c_str()); fq_name += "." + name; } } else { fq_name += "." + name; } VhpiImpl *vhpi_impl = reinterpret_cast(m_impl); new_obj = vhpi_impl->create_gpi_obj_from_handle(obj, name, fq_name); if (new_obj) { *hdl = new_obj; return GpiIterator::NATIVE; } else return GpiIterator::NOT_NATIVE; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/vhpi/VhpiImpl.cpp0000644000175100017510000011402515106067236021554 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2014, 2018 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include "VhpiImpl.h" #include #include #include #include #include "_vendor/vhpi/vhpi_user.h" #include "gpi_logging.h" #include "vhpi_user_ext.h" #ifdef NVC #include #endif #define CASE_STR(_X) \ case _X: \ return #_X const char *VhpiImpl::format_to_string(int format) { switch (format) { CASE_STR(vhpiBinStrVal); CASE_STR(vhpiOctStrVal); CASE_STR(vhpiDecStrVal); CASE_STR(vhpiHexStrVal); CASE_STR(vhpiEnumVal); CASE_STR(vhpiSmallEnumVal); CASE_STR(vhpiIntVal); CASE_STR(vhpiLogicVal); CASE_STR(vhpiRealVal); CASE_STR(vhpiStrVal); CASE_STR(vhpiCharVal); CASE_STR(vhpiTimeVal); CASE_STR(vhpiPhysVal); CASE_STR(vhpiObjTypeVal); CASE_STR(vhpiPtrVal); CASE_STR(vhpiEnumVecVal); CASE_STR(vhpiRawDataVal); default: return "unknown"; } } const char *VhpiImpl::reason_to_string(int reason) { switch (reason) { CASE_STR(vhpiCbValueChange); CASE_STR(vhpiCbStartOfNextCycle); CASE_STR(vhpiCbStartOfPostponed); CASE_STR(vhpiCbEndOfTimeStep); CASE_STR(vhpiCbNextTimeStep); CASE_STR(vhpiCbAfterDelay); CASE_STR(vhpiCbStartOfSimulation); CASE_STR(vhpiCbEndOfSimulation); CASE_STR(vhpiCbEndOfProcesses); CASE_STR(vhpiCbLastKnownDeltaCycle); default: return "unknown"; } } #undef CASE_STR void VhpiImpl::get_sim_time(uint32_t *high, uint32_t *low) { vhpiTimeT vhpi_time_s; vhpi_get_time(&vhpi_time_s, NULL); check_vhpi_error(); *high = vhpi_time_s.high; *low = vhpi_time_s.low; } static int32_t log10int(uint64_t v) { int32_t i = -1; do { v /= 10; i += 1; } while (v); return i; } void VhpiImpl::get_sim_precision(int32_t *precision) { /* The value returned is in number of femtoseconds */ vhpiPhysT prec = vhpi_get_phys(vhpiResolutionLimitP, NULL); uint64_t femtoseconds = ((uint64_t)prec.high << 32) | prec.low; *precision = log10int(femtoseconds) - 15; } const char *VhpiImpl::get_simulator_product() { if (m_product.empty()) { vhpiHandleT tool = vhpi_handle(vhpiTool, NULL); if (tool) { m_product = vhpi_get_str(vhpiNameP, tool); vhpi_release_handle(tool); } else { m_product = "UNKNOWN"; } } return m_product.c_str(); } const char *VhpiImpl::get_simulator_version() { if (m_version.empty()) { vhpiHandleT tool = vhpi_handle(vhpiTool, NULL); if (tool) { m_version = vhpi_get_str(vhpiToolVersionP, tool); vhpi_release_handle(tool); } else { m_version = "UNKNOWN"; } } return m_version.c_str(); } // Determine whether a VHPI object type is a constant or not bool is_const(vhpiHandleT hdl) { vhpiHandleT tmp = hdl; /* Need to walk the prefix's back to the original handle to get a type * that is not vhpiSelectedNameK or vhpiIndexedNameK */ do { vhpiIntT vhpitype = vhpi_get(vhpiKindP, tmp); if (vhpiConstDeclK == vhpitype || vhpiGenericDeclK == vhpitype) return true; } while ((tmp = vhpi_handle(vhpiPrefix, tmp)) != NULL); return false; } bool is_enum_logic(vhpiHandleT hdl) { const char *type = vhpi_get_str(vhpiNameP, hdl); if (0 == strncmp(type, "BIT", sizeof("BIT") - 1) || 0 == strncmp(type, "STD_ULOGIC", sizeof("STD_ULOGIC") - 1) || 0 == strncmp(type, "STD_LOGIC", sizeof("STD_LOGIC") - 1)) { return true; } else { vhpiIntT num_enum = vhpi_get(vhpiNumLiteralsP, hdl); if (2 == num_enum) { vhpiHandleT it = vhpi_iterator(vhpiEnumLiterals, hdl); if (it != NULL) { const char *enums_1[2] = { "0", "1"}; // Aldec does not return the single quotes const char *enums_2[2] = {"'0'", "'1'"}; vhpiHandleT enum_hdl; int cnt = 0; while ((enum_hdl = vhpi_scan(it)) != NULL) { const char *etype = vhpi_get_str(vhpiStrValP, enum_hdl); if (1 < cnt || (0 != strncmp(etype, enums_1[cnt], strlen(enums_1[cnt])) && 0 != strncmp(etype, enums_2[cnt], strlen(enums_2[cnt])))) { vhpi_release_handle(it); return false; } ++cnt; } return true; } } else if (9 == num_enum) { vhpiHandleT it = vhpi_iterator(vhpiEnumLiterals, hdl); if (it != NULL) { const char *enums_1[9] = { "U", "X", "0", "1", "Z", "W", "L", "H", "-"}; // Aldec does not return the single // quotes const char *enums_2[9] = {"'U'", "'X'", "'0'", "'1'", "'Z'", "'W'", "'L'", "'H'", "'-'"}; vhpiHandleT enum_hdl; int cnt = 0; while ((enum_hdl = vhpi_scan(it)) != NULL) { const char *etype = vhpi_get_str(vhpiStrValP, enum_hdl); if (8 < cnt || (0 != strncmp(etype, enums_1[cnt], strlen(enums_1[cnt])) && 0 != strncmp(etype, enums_2[cnt], strlen(enums_2[cnt])))) { vhpi_release_handle(it); return false; } ++cnt; } return true; } } } return false; } bool is_enum_char(vhpiHandleT hdl) { const vhpiIntT NUM_ENUMS_IN_CHAR_TYPE = 256; const char *type = vhpi_get_str(vhpiNameP, hdl); if (0 == strncmp(type, "CHARACTER", sizeof("STD_ULOGIC") - 1)) { return true; } else { return (vhpi_get(vhpiNumLiteralsP, hdl) == NUM_ENUMS_IN_CHAR_TYPE); } } bool is_enum_boolean(vhpiHandleT hdl) { const char *type = vhpi_get_str(vhpiNameP, hdl); if (0 == strncmp(type, "BOOLEAN", sizeof("BOOLEAN") - 1)) { return true; } else { vhpiIntT num_enum = vhpi_get(vhpiNumLiteralsP, hdl); if (2 == num_enum) { vhpiHandleT it = vhpi_iterator(vhpiEnumLiterals, hdl); if (it != NULL) { vhpiHandleT enum_hdl; int cnt = 0; while ((enum_hdl = vhpi_scan(it)) != NULL) { const char *etype = vhpi_get_str(vhpiStrValP, enum_hdl); if (((0 == cnt && 0 != strncmp(etype, "FALSE", strlen("FALSE"))) && (0 == cnt && 0 != strncmp(etype, "false", strlen("false")))) || ((1 == cnt && 0 != strncmp(etype, "TRUE", strlen("TRUE"))) && (1 == cnt && 0 != strncmp(etype, "true", strlen("true")))) || 2 <= cnt) { vhpi_release_handle(it); return false; } ++cnt; } return true; } } } return false; } static bool compare_names(const std::string &a, const std::string &b) { #ifdef NVC /* NVC does not properly implement the CaseName property and returns Names instead (nickg/nvc#723). */ return a.size() == b.size() && equal(a.begin(), a.end(), b.begin(), [](char x, char y) { return std::toupper(x) == std::toupper(y); }); #else return a == b; #endif } GpiObjHdl *VhpiImpl::create_gpi_obj_from_handle(vhpiHandleT new_hdl, const std::string &name, const std::string &fq_name) { vhpiIntT type; gpi_objtype gpi_type; GpiObjHdl *new_obj = NULL; if (vhpiVerilog == (type = vhpi_get(vhpiKindP, new_hdl))) { LOG_DEBUG("VHPI: vhpiVerilog returned from vhpi_get(vhpiType, ...)"); return NULL; } /* We need to delve further here to determine how to later set the values of an object */ vhpiHandleT base_hdl = vhpi_handle(vhpiBaseType, new_hdl); if (base_hdl == NULL) { vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, new_hdl); if (st_hdl != NULL) { base_hdl = vhpi_handle(vhpiBaseType, st_hdl); vhpi_release_handle(st_hdl); } } vhpiHandleT query_hdl = (base_hdl != NULL) ? base_hdl : new_hdl; vhpiIntT base_type = vhpi_get(vhpiKindP, query_hdl); switch (base_type) { case vhpiArrayTypeDeclK: { vhpiIntT num_dim = vhpi_get(vhpiNumDimensionsP, query_hdl); if (num_dim > 1) { LOG_DEBUG("VHPI: Detected a MULTI-DIMENSIONAL ARRAY type %s", fq_name.c_str()); gpi_type = GPI_ARRAY; } else { vhpiHandleT elem_base_type_hdl = NULL; vhpiIntT elem_base_type = 0; vhpiHandleT elem_sub_type_hdl = vhpi_handle(vhpiElemType, query_hdl); /* vhpiElemType is not supported in all simulators. */ if (!elem_sub_type_hdl) { elem_sub_type_hdl = vhpi_handle(vhpiElemSubtype, query_hdl); } if (elem_sub_type_hdl != NULL) { elem_base_type_hdl = vhpi_handle(vhpiBaseType, elem_sub_type_hdl); if (elem_base_type_hdl == NULL) { elem_base_type_hdl = elem_sub_type_hdl; } else { vhpi_release_handle(elem_sub_type_hdl); } } if (elem_base_type_hdl != NULL) { elem_base_type = vhpi_get(vhpiKindP, elem_base_type_hdl); if (elem_base_type == vhpiEnumTypeDeclK) { if (is_enum_logic(elem_base_type_hdl)) { LOG_DEBUG("VHPI: Detected a LOGIC VECTOR type %s", fq_name.c_str()); gpi_type = GPI_LOGIC_ARRAY; } else if (is_enum_char(elem_base_type_hdl)) { LOG_DEBUG("VHPI: Detected a STRING type %s", fq_name.c_str()); gpi_type = GPI_STRING; } else { LOG_DEBUG( "VHPI: Detected a NON-LOGIC ENUM VECTOR type " "%s", fq_name.c_str()); gpi_type = GPI_ARRAY; } } else { LOG_DEBUG("VHPI: Detected a NON-ENUM VECTOR type %s", fq_name.c_str()); gpi_type = GPI_ARRAY; } } else { LOG_ERROR( "VHPI: Unable to determine the Array Element Base Type " "for %s. Defaulting to GPI_ARRAY.", vhpi_get_str(vhpiFullCaseNameP, new_hdl)); gpi_type = GPI_ARRAY; } } break; } case vhpiEnumTypeDeclK: { if (is_enum_logic(query_hdl)) { LOG_DEBUG("VHPI: Detected a LOGIC type %s", fq_name.c_str()); gpi_type = GPI_LOGIC; } else if (is_enum_char(query_hdl)) { LOG_DEBUG("VHPI: Detected a CHAR type %s", fq_name.c_str()); gpi_type = GPI_INTEGER; } else if (is_enum_boolean(query_hdl)) { LOG_DEBUG("VHPI: Detected a BOOLEAN/INTEGER type %s", fq_name.c_str()); gpi_type = GPI_INTEGER; } else { LOG_DEBUG("VHPI: Detected an ENUM type %s", fq_name.c_str()); gpi_type = GPI_ENUM; } break; } case vhpiIntTypeDeclK: { LOG_DEBUG("VHPI: Detected an INT type %s", fq_name.c_str()); gpi_type = GPI_INTEGER; break; } case vhpiFloatTypeDeclK: { LOG_DEBUG("VHPI: Detected a REAL type %s", fq_name.c_str()); gpi_type = GPI_REAL; break; } case vhpiRecordTypeDeclK: { LOG_DEBUG("VHPI: Detected a STRUCTURE type %s", fq_name.c_str()); gpi_type = GPI_STRUCTURE; break; } case vhpiProcessStmtK: case vhpiSimpleSigAssignStmtK: case vhpiCondSigAssignStmtK: case vhpiSelectSigAssignStmtK: { gpi_type = GPI_MODULE; break; } case vhpiRootInstK: case vhpiIfGenerateK: case vhpiForGenerateK: case vhpiBlockStmtK: case vhpiCompInstStmtK: { std::string hdl_name = vhpi_get_str(vhpiCaseNameP, new_hdl); if (base_type == vhpiRootInstK && !compare_names(hdl_name, name)) { vhpiHandleT arch = vhpi_handle(vhpiDesignUnit, new_hdl); if (NULL != arch) { vhpiHandleT prim = vhpi_handle(vhpiPrimaryUnit, arch); if (NULL != prim) { hdl_name = vhpi_get_str(vhpiCaseNameP, prim); } } } if (!compare_names(name, hdl_name)) { LOG_DEBUG("VHPI: Found pseudo-region %s", fq_name.c_str()); gpi_type = GPI_GENARRAY; } else { gpi_type = GPI_MODULE; } break; } default: { vhpiIntT is_static = vhpi_get(vhpiStaticnessP, query_hdl); /* Non locally static objects are not accessible for read/write so we create this as a GpiObjType */ if (is_static == vhpiGloballyStatic) { gpi_type = GPI_MODULE; break; } LOG_ERROR("VHPI: Not able to map type (%s) %u to object", vhpi_get_str(vhpiKindStrP, query_hdl), type); new_obj = NULL; goto out; } } LOG_DEBUG("VHPI: Creating %s of type %d (%s)", vhpi_get_str(vhpiFullCaseNameP, new_hdl), gpi_type, vhpi_get_str(vhpiKindStrP, query_hdl)); switch (gpi_type) { case GPI_ARRAY: { new_obj = new VhpiArrayObjHdl(this, new_hdl, gpi_type); break; } case GPI_GENARRAY: case GPI_MODULE: case GPI_STRUCTURE: case GPI_PACKAGE: { new_obj = new VhpiObjHdl(this, new_hdl, gpi_type); break; } case GPI_LOGIC: case GPI_LOGIC_ARRAY: { new_obj = new VhpiLogicSignalObjHdl(this, new_hdl, gpi_type, is_const(new_hdl)); break; } default: { new_obj = new VhpiSignalObjHdl(this, new_hdl, gpi_type, is_const(new_hdl)); break; } } if (new_obj->initialise(name, fq_name)) { delete new_obj; new_obj = NULL; } out: if (base_hdl != NULL) vhpi_release_handle(base_hdl); return new_obj; } static std::string fully_qualified_name(const std::string &name, GpiObjHdl *parent) { std::string fq_name = parent->get_fullname(); if (fq_name == ":") { fq_name += name; } else { fq_name += "." + name; } #ifdef NVC /* Convert to a canonical form to avoid problems with case insensitivity. */ std::transform(fq_name.begin(), fq_name.end(), fq_name.begin(), ::toupper); #endif return fq_name; } GpiObjHdl *VhpiImpl::get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) { LOG_DEBUG("VHPI: Trying to convert raw to VHPI handle"); vhpiHandleT new_hdl = (vhpiHandleT)raw_hdl; const char *c_name = vhpi_get_str(vhpiCaseNameP, new_hdl); if (!c_name) { LOG_DEBUG("VHPI: Unable to query name of passed in handle"); return NULL; } std::string name = c_name; std::string fq_name = fully_qualified_name(name, parent); GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name); if (new_obj == NULL) { vhpi_release_handle(new_hdl); LOG_DEBUG("VHPI: Unable to fetch object %s", fq_name.c_str()); return NULL; } return new_obj; } GpiObjHdl *VhpiImpl::get_child_by_name(const std::string &name, GpiObjHdl *parent) { vhpiHandleT vhpi_hdl = parent->get_handle(); vhpiHandleT new_hdl; std::string fq_name = fully_qualified_name(name, parent); std::vector writable(fq_name.begin(), fq_name.end()); writable.push_back('\0'); new_hdl = vhpi_handle_by_name(&writable[0], NULL); if (new_hdl == NULL && parent->get_type() == GPI_STRUCTURE) { /* vhpi_handle_by_name() doesn't always work for records, specifically * records in generics */ vhpiHandleT iter = vhpi_iterator(vhpiSelectedNames, vhpi_hdl); if (iter != NULL) { while ((new_hdl = vhpi_scan(iter)) != NULL) { std::string selected_name = vhpi_get_str(vhpiCaseNameP, new_hdl); std::size_t found = selected_name.find_last_of("."); if (found != std::string::npos) { selected_name = selected_name.substr(found + 1); } if (compare_names(selected_name, name)) { vhpi_release_handle(iter); break; } } } } else if (new_hdl == NULL) { /* If not found, check to see if the name of a generate loop */ vhpiHandleT iter = vhpi_iterator(vhpiInternalRegions, vhpi_hdl); if (iter != NULL) { vhpiHandleT rgn; for (rgn = vhpi_scan(iter); rgn != NULL; rgn = vhpi_scan(iter)) { if (vhpi_get(vhpiKindP, rgn) == vhpiForGenerateK) { std::string rgn_name = vhpi_get_str(vhpiCaseNameP, rgn); if (compare_generate_labels(rgn_name, name)) { new_hdl = vhpi_hdl; vhpi_release_handle(iter); break; } } } } if (new_hdl == NULL) { LOG_DEBUG("VHPI: Unable to query vhpi_handle_by_name %s", fq_name.c_str()); return NULL; } } /* Generate Loops have inconsistent behavior across VHPI. A "name" * without an index, i.e. dut.loop vs dut.loop(0), may or may not map to * to the start index. If it doesn't then it won't find anything. * * If this unique case is hit, we need to create the Pseudo-region, with the * handle being equivalent to the parent handle. */ if (vhpi_get(vhpiKindP, new_hdl) == vhpiForGenerateK) { vhpi_release_handle(new_hdl); new_hdl = vhpi_hdl; } GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name); if (new_obj == NULL) { vhpi_release_handle(new_hdl); LOG_DEBUG("VHPI: Unable to fetch object %s", fq_name.c_str()); return NULL; } return new_obj; } GpiObjHdl *VhpiImpl::get_child_by_index(int32_t index, GpiObjHdl *parent) { vhpiHandleT vhpi_hdl = parent->get_handle(); std::string name = parent->get_name(); std::string fq_name = parent->get_fullname(); vhpiHandleT new_hdl = NULL; char buff[14]; // needs to be large enough to hold -2^31 to 2^31-1 in // string form ('(''-'10+'')'\0') gpi_objtype obj_type = parent->get_type(); if (obj_type == GPI_GENARRAY) { LOG_DEBUG( "VHPI: Get child at index %d of parent %s " "(pseudo-region)", index, parent->get_name_str()); snprintf(buff, sizeof(buff), "%d", index); std::string idx_str = buff; name += (GEN_IDX_SEP_LHS + idx_str + GEN_IDX_SEP_RHS); fq_name += (GEN_IDX_SEP_LHS + idx_str + GEN_IDX_SEP_RHS); std::vector writable(fq_name.begin(), fq_name.end()); writable.push_back('\0'); new_hdl = vhpi_handle_by_name(&writable[0], NULL); } else if (obj_type == GPI_LOGIC || obj_type == GPI_LOGIC_ARRAY || obj_type == GPI_ARRAY || obj_type == GPI_STRING) { LOG_DEBUG("VHPI: Get child at index %d of parent %s (%s)", index, parent->get_fullname_str(), vhpi_get_str(vhpiKindStrP, vhpi_hdl)); snprintf(buff, sizeof(buff), "(%d)", index); std::string idx_str = buff; name += idx_str; fq_name += idx_str; vhpiHandleT base_hdl = vhpi_handle(vhpiBaseType, vhpi_hdl); if (base_hdl == NULL) { vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, vhpi_hdl); if (st_hdl != NULL) { base_hdl = vhpi_handle(vhpiBaseType, st_hdl); vhpi_release_handle(st_hdl); } } if (base_hdl == NULL) { LOG_ERROR("VHPI: Unable to get the vhpiBaseType of %s", parent->get_fullname_str()); return NULL; } vhpiIntT num_dim = vhpi_get(vhpiNumDimensionsP, base_hdl); int idx = 0; /* Need to translate the index into a zero-based flattened array index */ if (num_dim > 1) { std::string hdl_name = vhpi_get_str(vhpiCaseNameP, vhpi_hdl); std::vector indices; /* Need to determine how many indices have been received. A valid * handle will only be found when all indices are received, * otherwise need a pseudo-handle. * * When working with pseudo-handles: * hdl_name: sig_name * parent->get_name(): sig_name(x)(y)... where x,y,... are the * indices to a multi-dimensional array. pseudo_idx: (x)(y)... */ if (hdl_name.length() < parent->get_name().length()) { std::string pseudo_idx = parent->get_name().substr(hdl_name.length()); while (pseudo_idx.length() > 0) { std::size_t found = pseudo_idx.find_first_of(")"); if (found != std::string::npos) { indices.push_back( atoi(pseudo_idx.substr(1, found - 1).c_str())); pseudo_idx = pseudo_idx.substr(found + 1); } else { break; } } } indices.push_back(index); if (indices.size() == num_dim) { #ifdef IUS /* IUS/Xcelium does not appear to set the vhpiIsUnconstrainedP * property. IUS Docs say it will return -1 if unconstrained, * but with vhpiIntT being unsigned, the value returned is * below. */ const vhpiIntT UNCONSTRAINED = 2147483647; #endif std::vector constraints; /* All necessary indices are available, need to iterate over * dimension constraints to determine the index into the * zero-based flattened array. * * Check the constraints on the base type first. (always works * for Aldec, but not unconstrained types in IUS/Xcelium) If the * base type fails, then try the sub-type. (sub-type is listed * as deprecated for Aldec) */ vhpiHandleT it, constraint; it = vhpi_iterator(vhpiConstraints, base_hdl); if (it != NULL) { while ((constraint = vhpi_scan(it)) != NULL) { #ifdef IUS vhpiIntT l_rng = vhpi_get(vhpiLeftBoundP, constraint); vhpiIntT r_rng = vhpi_get(vhpiRightBoundP, constraint); if (l_rng == UNCONSTRAINED || r_rng == UNCONSTRAINED) { #else if (vhpi_get(vhpiIsUnconstrainedP, constraint)) { #endif /* Bail and try the sub-type handle */ vhpi_release_handle(it); break; } constraints.push_back(constraint); } } /* If all the dimensions were not obtained, try again with the * sub-type handle */ if (constraints.size() != num_dim) { vhpiHandleT sub_hdl = vhpi_handle(vhpiSubtype, vhpi_hdl); ; constraints.clear(); if (sub_hdl != NULL) { it = vhpi_iterator(vhpiConstraints, sub_hdl); if (it != NULL) { while ((constraint = vhpi_scan(it)) != NULL) { /* IUS/Xcelium only sets the * vhpiIsUnconstrainedP incorrectly on the base * type */ if (vhpi_get(vhpiIsUnconstrainedP, constraint)) { vhpi_release_handle(it); break; } constraints.push_back(constraint); } } } } if (constraints.size() == num_dim) { int scale = 1; while (constraints.size() > 0) { int raw_idx = indices.back(); constraint = constraints.back(); int left = static_cast( vhpi_get(vhpiLeftBoundP, constraint)); int right = static_cast( vhpi_get(vhpiRightBoundP, constraint)); int len = 0; if (left > right) { idx += (scale * (left - raw_idx)); len = left - right + 1; } else { idx += (scale * (raw_idx - left)); len = right - left + 1; } scale = scale * len; indices.pop_back(); constraints.pop_back(); } } else { LOG_ERROR("VHPI: Unable to access all constraints for %s", parent->get_fullname_str()); return NULL; } } else { new_hdl = vhpi_hdl; // Set to the parent handle to create the // pseudo-handle } } else { int left = parent->get_range_left(); int right = parent->get_range_right(); if (left > right) { idx = left - index; } else { idx = index - left; } } if (new_hdl == NULL) { new_hdl = vhpi_handle_by_index(vhpiIndexedNames, vhpi_hdl, idx); if (!new_hdl) { /* Support for the above seems poor, so if it did not work try an iteration instead, spotty support for multi-dimensional arrays */ vhpiHandleT iter = vhpi_iterator(vhpiIndexedNames, vhpi_hdl); if (iter != NULL) { int curr_index = 0; while ((new_hdl = vhpi_scan(iter)) != NULL) { if (idx == curr_index) { vhpi_release_handle(iter); break; } curr_index++; } } } if (new_hdl != NULL) { LOG_DEBUG("VHPI: Index (%d->%d) found %s (%s)", index, idx, vhpi_get_str(vhpiCaseNameP, new_hdl), vhpi_get_str(vhpiKindStrP, new_hdl)); } } } else { LOG_ERROR( "VHPI: Parent of type %s must be of type GPI_GENARRAY, " "GPI_LOGIC, GPI_ARRAY, or GPI_STRING to have an index.", parent->get_type_str()); return NULL; } if (new_hdl == NULL) { LOG_DEBUG("VHPI: Unable to query vhpi_handle_by_index %d", index); return NULL; } GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name); if (new_obj == NULL) { vhpi_release_handle(new_hdl); LOG_DEBUG( "VHPI: Could not fetch object below entity (%s) at index (%d)", parent->get_name_str(), index); return NULL; } return new_obj; } GpiObjHdl *VhpiImpl::get_root_handle(const char *name) { vhpiHandleT root = vhpi_handle(vhpiRootInst, NULL); if (!root) { LOG_ERROR("VHPI: Attempting to get the vhpiRootInst failed"); check_vhpi_error(); return NULL; } // IEEE 1076-2019 Clause 19.4.3 // For an object of class rootInst, the values of the Name and CaseName // properties are the simple name of the entity declaration whose // instantiation is represented by the object. std::string root_name = vhpi_get_str(vhpiCaseNameP, root); LOG_DEBUG("VHPI: We have found root='%s'", root_name.c_str()); if (name && !compare_names(name, root_name)) { LOG_DEBUG( "VHPI: root name '%s' doesn't match requested name '%s'. Trying " "fallbacks", root_name.c_str(), name); } else { return create_gpi_obj_from_handle(root, root_name, root_name); } // Some simulators do not return the correct entity name for rootInst, // so implement fallbacks. // First, try to get the entity (primaryUnit) associated with the rootInst // and its name. vhpiHandleT arch = vhpi_handle(vhpiDesignUnit, root); if (!arch) { LOG_DEBUG( "VHPI: Unable to get vhpiDesignUnit (arch) from root handle. " "Trying handle lookup by name"); check_vhpi_error(); } vhpiHandleT entity = NULL; if (arch && !(entity = vhpi_handle(vhpiPrimaryUnit, arch))) { LOG_DEBUG( "VHPI: Unable to get vhpiPrimaryUnit (entity) from arch handle. " "Trying handle lookup by name"); check_vhpi_error(); } if (entity) { root_name = vhpi_get_str(vhpiCaseNameP, entity); // If this matches the name then it is what we want, // but we use the root handle two levels up as the DUT // because we do not want an object of type vhpiEntityDeclK as the DUT if (name && !compare_names(name, root_name)) { LOG_DEBUG( "VHPI: Root entity name '%s' doesn't match requested name " "'%s'. Trying handle lookup by name", root_name.c_str(), name); } else { return create_gpi_obj_from_handle(root, root_name, root_name); } } // Second, we search for the root handle by name if (!name) { // name should never be null here, but fail if it is. LOG_ERROR("VHPI: Couldn't find root handle"); return NULL; } // Search using hierarchical path, which starts with ':', // to disambiguate with library information model objects // that have the same name as the rootInst entity. std::string search_name; if (name[0] != ':') { search_name = ":"; } search_name += name; vhpiHandleT dut = vhpi_handle_by_name(search_name.c_str(), NULL); if (!dut) { LOG_DEBUG("VHPI: Unable to get root handle by name"); check_vhpi_error(); } else { root_name = vhpi_get_str(vhpiCaseNameP, dut); vhpiIntT dut_kind = vhpi_get(vhpiKindP, dut); std::string dut_kind_str = vhpi_get_str(vhpiKindStrP, dut); if (!compare_names(name, root_name)) { LOG_DEBUG( "VHPI: found root handle of type %s (%d) with name '%s' " "doesn't match requested name '%s'", dut_kind_str.c_str(), dut_kind, root_name.c_str(), name); } else { return create_gpi_obj_from_handle(dut, root_name, root_name); } } LOG_ERROR("VHPI: Couldn't find root handle '%s'", name); return NULL; } GpiIterator *VhpiImpl::iterate_handle(GpiObjHdl *obj_hdl, gpi_iterator_sel type) { GpiIterator *new_iter = NULL; switch (type) { case GPI_OBJECTS: new_iter = new VhpiIterator(this, obj_hdl); break; case GPI_DRIVERS: LOG_WARN("VHPI: Drivers iterator not implemented yet"); break; case GPI_LOADS: LOG_WARN("VHPI: Loads iterator not implemented yet"); break; default: LOG_WARN("VHPI: Other iterator types not implemented yet"); break; } return new_iter; } GpiCbHdl *VhpiImpl::register_timed_callback(uint64_t time, int (*cb_func)(void *), void *cb_data) { auto *cb_hdl = new VhpiTimedCbHdl(this, time); auto err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { delete cb_hdl; return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiCbHdl *VhpiImpl::register_readwrite_callback(int (*cb_func)(void *), void *cb_data) { auto *cb_hdl = new VhpiReadWriteCbHdl(this); auto err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { delete cb_hdl; return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiCbHdl *VhpiImpl::register_readonly_callback(int (*cb_func)(void *), void *cb_data) { auto *cb_hdl = new VhpiReadOnlyCbHdl(this); auto err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { delete cb_hdl; return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiCbHdl *VhpiImpl::register_nexttime_callback(int (*cb_func)(void *), void *cb_data) { auto *cb_hdl = new VhpiNextPhaseCbHdl(this); auto err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { delete cb_hdl; return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } void VhpiImpl::sim_end() { m_sim_finish_cb->remove(); int err = vhpi_control(vhpiFinish, vhpiDiagTimeLoc); // LCOV_EXCL_START if (err) { LOG_DEBUG("VHPI: Failed to end simulation"); check_vhpi_error(); } // LCOV_EXCL_STOP } bool VhpiImpl::compare_generate_labels(const std::string &a, const std::string &b) { /* Compare two generate labels for equality ignoring any suffixed index. */ std::size_t a_idx = a.rfind(GEN_IDX_SEP_LHS); std::size_t b_idx = b.rfind(GEN_IDX_SEP_LHS); return compare_names(a.substr(0, a_idx), b.substr(0, b_idx)); } static int startup_callback(void *) { vhpiHandleT tool, argv_iter, argv_hdl; char **tool_argv = NULL; int tool_argc = 0; int i = 0; tool = vhpi_handle(vhpiTool, NULL); if (tool) { tool_argc = static_cast(vhpi_get(vhpiArgcP, tool)); tool_argv = new char *[tool_argc]; assert(tool_argv); argv_iter = vhpi_iterator(vhpiArgvs, tool); if (argv_iter) { while ((argv_hdl = vhpi_scan(argv_iter))) { tool_argv[i] = const_cast(static_cast( vhpi_get_str(vhpiStrValP, argv_hdl))); i++; } } vhpi_release_handle(tool); } gpi_embed_init(tool_argc, tool_argv); delete[] tool_argv; return 0; } static int shutdown_callback(void *) { gpi_embed_end(); return 0; } void VhpiImpl::main() noexcept { auto startup_cb = new VhpiStartupCbHdl(this); auto err = startup_cb->arm(); // LCOV_EXCL_START if (err) { LOG_CRITICAL( "VHPI: Unable to register startup callback! Simulation will end."); check_vhpi_error(); delete startup_cb; exit(1); } // LCOV_EXCL_STOP startup_cb->set_cb_info(startup_callback, nullptr); auto shutdown_cb = new VhpiShutdownCbHdl(this); err = shutdown_cb->arm(); // LCOV_EXCL_START if (err) { LOG_CRITICAL( "VHPI: Unable to register shutdown callback! Simulation will end."); check_vhpi_error(); startup_cb->remove(); delete shutdown_cb; exit(1); } // LCOV_EXCL_STOP shutdown_cb->set_cb_info(shutdown_callback, nullptr); m_sim_finish_cb = shutdown_cb; gpi_register_impl(this); gpi_entry_point(); } static void vhpi_main() { auto vhpi_table = new VhpiImpl("VHPI"); vhpi_table->main(); } static void register_impl() { auto vhpi_table = new VhpiImpl("VHPI"); gpi_register_impl(vhpi_table); } // pre-defined VHPI registration table extern "C" { COCOTBVHPI_EXPORT void (*vhpi_startup_routines[])() = {vhpi_main, nullptr}; // For non-VHPI compliant applications that cannot find vhpi_startup_routines COCOTBVHPI_EXPORT void vhpi_startup_routines_bootstrap() { vhpi_main(); } } GPI_ENTRY_POINT(cocotbvhpi, register_impl) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/vhpi/VhpiImpl.h0000644000175100017510000002236115106067236021222 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef COCOTB_VHPI_IMPL_H_ #define COCOTB_VHPI_IMPL_H_ #include #include #include "../gpi/gpi_priv.h" #include "_vendor/vhpi/vhpi_user.h" #include "exports.h" #include "gpi.h" #include "gpi_logging.h" #ifdef COCOTBVHPI_EXPORTS #define COCOTBVHPI_EXPORT COCOTB_EXPORT #else #define COCOTBVHPI_EXPORT COCOTB_IMPORT #endif // Define Index separator #ifdef ALDEC // Aldec #define GEN_IDX_SEP_LHS "__" #define GEN_IDX_SEP_RHS "" #else // IUS/Xcelium and Questa #define GEN_IDX_SEP_LHS "(" #define GEN_IDX_SEP_RHS ")" #endif // Should be run after every VHPI call to check error status static inline void __check_vhpi_error(const char *file, const char *func, long line) { if (gpi_log_filtered("gpi", GPI_DEBUG)) { return; } int err_occurred = 0; vhpiErrorInfoT info; enum gpi_log_level loglevel; err_occurred = vhpi_check_error(&info); if (!err_occurred) return; switch (info.severity) { case vhpiNote: loglevel = GPI_INFO; break; case vhpiWarning: loglevel = GPI_WARNING; break; case vhpiError: loglevel = GPI_ERROR; break; case vhpiFailure: case vhpiSystem: case vhpiInternal: loglevel = GPI_CRITICAL; break; default: loglevel = GPI_INFO; break; } LOG_EXPLICIT("gpi", GPI_DEBUG, file, func, line, "VHPI Internal Error: %s @ %s:%d: %s", gpi_log_level_to_str(loglevel), info.file, info.line, info.message); } #define check_vhpi_error() \ do { \ __check_vhpi_error(__FILE__, __func__, __LINE__); \ } while (0) class VhpiCbHdl : public GpiCbHdl { public: VhpiCbHdl(GpiImplInterface *impl); int arm() override; int remove() override; int run() override; protected: vhpiCbDataT cb_data; vhpiTimeT vhpi_time; bool m_removed = false; }; class VhpiSignalObjHdl; class VhpiValueCbHdl : public VhpiCbHdl { public: VhpiValueCbHdl(GpiImplInterface *impl, VhpiSignalObjHdl *sig, gpi_edge edge); int run() override; private: GpiSignalObjHdl *m_signal; gpi_edge m_edge; }; class VhpiTimedCbHdl : public VhpiCbHdl { public: VhpiTimedCbHdl(GpiImplInterface *impl, uint64_t time); }; class VhpiReadOnlyCbHdl : public VhpiCbHdl { public: VhpiReadOnlyCbHdl(GpiImplInterface *impl); }; class VhpiNextPhaseCbHdl : public VhpiCbHdl { public: VhpiNextPhaseCbHdl(GpiImplInterface *impl); }; class VhpiStartupCbHdl : public VhpiCbHdl { public: VhpiStartupCbHdl(GpiImplInterface *impl); // Too many sims get upset trying to remove startup callbacks so we just // don't try. TODO Is this still accurate? int run() override { int res = 0; if (!m_removed) { res = m_cb_func(m_cb_data); } delete this; return res; } int remove() override { m_removed = true; return 0; } }; class VhpiShutdownCbHdl : public VhpiCbHdl { public: VhpiShutdownCbHdl(GpiImplInterface *impl); // Too many sims get upset trying to remove startup callbacks so we just // don't try. TODO Is this still accurate? int run() override { int res = 0; if (!m_removed) { res = m_cb_func(m_cb_data); } delete this; return res; } int remove() override { m_removed = true; return 0; } }; class VhpiReadWriteCbHdl : public VhpiCbHdl { public: VhpiReadWriteCbHdl(GpiImplInterface *impl); }; class VhpiArrayObjHdl : public GpiObjHdl { public: VhpiArrayObjHdl(GpiImplInterface *impl, vhpiHandleT hdl, gpi_objtype objtype) : GpiObjHdl(impl, hdl, objtype) {} ~VhpiArrayObjHdl() override; int initialise(const std::string &name, const std::string &fq_name) override; }; class VhpiObjHdl : public GpiObjHdl { public: VhpiObjHdl(GpiImplInterface *impl, vhpiHandleT hdl, gpi_objtype objtype) : GpiObjHdl(impl, hdl, objtype) {} ~VhpiObjHdl() override; int initialise(const std::string &name, const std::string &fq_name) override; }; class VhpiSignalObjHdl : public GpiSignalObjHdl { public: VhpiSignalObjHdl(GpiImplInterface *impl, vhpiHandleT hdl, gpi_objtype objtype, bool is_const) : GpiSignalObjHdl(impl, hdl, objtype, is_const) {} ~VhpiSignalObjHdl() override; const char *get_signal_value_binstr() override; const char *get_signal_value_str() override; double get_signal_value_real() override; long get_signal_value_long() override; using GpiSignalObjHdl::set_signal_value; int set_signal_value(int32_t value, gpi_set_action action) override; int set_signal_value(double value, gpi_set_action action) override; int set_signal_value_str(std::string &value, gpi_set_action action) override; int set_signal_value_binstr(std::string &value, gpi_set_action action) override; /* Value change callback accessor */ int initialise(const std::string &name, const std::string &fq_name) override; GpiCbHdl *register_value_change_callback(gpi_edge edge, int (*function)(void *), void *cb_data) override; protected: vhpiEnumT chr2vhpi(char value); vhpiValueT m_value; vhpiValueT m_binvalue; }; class VhpiLogicSignalObjHdl : public VhpiSignalObjHdl { public: VhpiLogicSignalObjHdl(GpiImplInterface *impl, vhpiHandleT hdl, gpi_objtype objtype, bool is_const) : VhpiSignalObjHdl(impl, hdl, objtype, is_const) {} using GpiSignalObjHdl::set_signal_value; int set_signal_value(int32_t value, gpi_set_action action) override; int set_signal_value_binstr(std::string &value, gpi_set_action action) override; int initialise(const std::string &name, const std::string &fq_name) override; }; class VhpiIterator : public GpiIterator { public: VhpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl); ~VhpiIterator() override; Status next_handle(std::string &name, GpiObjHdl **hdl, void **raw_hdl) override; private: vhpiHandleT m_iterator; vhpiHandleT m_iter_obj; static std::map> iterate_over; /* Possible mappings */ std::vector *selected; /* Mapping currently in use */ std::vector::iterator one2many; }; class VhpiImpl : public GpiImplInterface { public: VhpiImpl(const std::string &name) : GpiImplInterface(name) {} /* Sim related */ void sim_end() override; void get_sim_time(uint32_t *high, uint32_t *low) override; void get_sim_precision(int32_t *precision) override; const char *get_simulator_product() override; const char *get_simulator_version() override; /* Hierarchy related */ GpiObjHdl *get_root_handle(const char *name) override; GpiIterator *iterate_handle(GpiObjHdl *obj_hdl, gpi_iterator_sel type) override; /* Callback related, these may (will) return the same handle*/ GpiCbHdl *register_timed_callback(uint64_t time, int (*function)(void *), void *cb_data) override; GpiCbHdl *register_readonly_callback(int (*function)(void *), void *cb_data) override; GpiCbHdl *register_nexttime_callback(int (*function)(void *), void *cb_data) override; GpiCbHdl *register_readwrite_callback(int (*function)(void *), void *cb_data) override; GpiObjHdl *get_child_by_name(const std::string &name, GpiObjHdl *parent) override; GpiObjHdl *get_child_by_index(int32_t index, GpiObjHdl *parent) override; GpiObjHdl *get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) override; const char *reason_to_string(int reason) override; const char *format_to_string(int format); GpiObjHdl *create_gpi_obj_from_handle(vhpiHandleT new_hdl, const std::string &name, const std::string &fq_name); static bool compare_generate_labels(const std::string &a, const std::string &b); /** Entry point for the simulator. * * Called if this GpiImpl will act as the main simulator entry point. * Registers simulator startup and shutdown callbacks, and controls the * behavior gpi_sim_end. */ void main() noexcept; private: // We store the shutdown callback handle here so sim_end() can remove() it // if it's called. VhpiShutdownCbHdl *m_sim_finish_cb; }; #endif /*COCOTB_VHPI_IMPL_H_ */ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3517027 cocotb-2.0.1/src/cocotb/share/lib/vpi/0000755000175100017510000000000015106070715017141 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/vpi/VpiCbHdl.cpp0000644000175100017510000001556715106067236021322 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include "VpiImpl.h" #include "gpi_logging.h" #include "share/lib/gpi/gpi_priv.h" #ifndef VPI_NO_QUEUE_SETIMMEDIATE_CALLBACKS #include #include static std::deque cb_queue; #endif static int32_t handle_vpi_callback_(GpiCbHdl *cb_hdl) { gpi_to_user(); // LCOV_EXCL_START if (!cb_hdl) { LOG_CRITICAL("VPI: Callback data corrupted: ABORTING"); gpi_embed_end(); return -1; } // LCOV_EXCL_STOP if (cb_hdl->run()) { // sim failed, so call shutdown gpi_embed_end(); return 0; } gpi_to_simulator(); return 0; } // Main re-entry point for callbacks from simulator int32_t handle_vpi_callback(p_cb_data cb_data) { #ifdef VPI_NO_QUEUE_SETIMMEDIATE_CALLBACKS VpiCbHdl *cb_hdl = (VpiCbHdl *)cb_data->user_data; return handle_vpi_callback_(cb_hdl); #else // must push things into a queue because Icaurus (gh-4067), Xcelium // (gh-4013), and Questa (gh-4105) react to value changes on signals that // are set with vpiNoDelay immediately, and not after the current callback // has ended, causing re-entrancy. static bool reacting = false; VpiCbHdl *cb_hdl = (VpiCbHdl *)cb_data->user_data; if (reacting) { cb_queue.push_back(cb_hdl); return 0; } reacting = true; int32_t ret = handle_vpi_callback_(cb_hdl); while (!cb_queue.empty()) { handle_vpi_callback_(cb_queue.front()); cb_queue.pop_front(); } reacting = false; return ret; #endif } VpiCbHdl::VpiCbHdl(GpiImplInterface *impl) : GpiCbHdl(impl) { vpi_time.high = 0; vpi_time.low = 0; vpi_time.type = vpiSimTime; cb_data.reason = 0; cb_data.cb_rtn = handle_vpi_callback; cb_data.obj = NULL; cb_data.time = &vpi_time; cb_data.value = NULL; cb_data.index = 0; cb_data.user_data = (char *)this; } int VpiCbHdl::arm() { vpiHandle new_hdl = vpi_register_cb(&cb_data); if (!new_hdl) { LOG_ERROR( "VPI: Unable to register a callback handle for VPI type %s(%d)", m_impl->reason_to_string(cb_data.reason), cb_data.reason); check_vpi_error(); return -1; } m_obj_hdl = new_hdl; return 0; } int VpiCbHdl::remove() { #ifndef VPI_NO_QUEUE_SETIMMEDIATE_CALLBACKS // check if it's already fired and is in callback queue auto it = std::find(cb_queue.begin(), cb_queue.end(), this); if (it != cb_queue.end()) { cb_queue.erase(it); // In Verilator some callbacks are recurring, so we *should* try to // remove by falling through to the code below. Other sims don't like // removing callbacks that have already fired. #ifndef VERILATOR // It's already fired, we shouldn't try to vpi_remove_cb() it now. delete this; return 0; #endif } #endif auto err = vpi_remove_cb(get_handle()); // LCOV_EXCL_START if (!err) { LOG_DEBUG("VPI: Unable to remove callback"); check_vpi_error(); // put it in a removed state so if it fires we can squash it m_removed = true; } // LCOV_EXCL_STOP else { delete this; } return 0; } int VpiCbHdl::run() { int res = 0; // LCOV_EXCL_START if (!m_removed) { // Only call up if not removed. res = m_cb_func(m_cb_data); } // LCOV_EXCL_STOP // Verilator seems to think some callbacks are recurring that Icarus and other // sims do not. So we remove all callbacks here after firing because Verilator // doesn't seem to mind (other sims do). #ifdef VERILATOR // Remove recurring callback once fired auto err = vpi_remove_cb(get_handle()); // LCOV_EXCL_START if (!err) { LOG_DEBUG("VPI: Unable to remove callback"); check_vpi_error(); // put it in a removed state so if it fires we can squash it m_removed = true; } // LCOV_EXCL_STOP else { delete this; } #else // For other simulators: VPI spec says one-shot callbacks auto-cleanup // their handle after firing. We just need to delete the C++ object. delete this; #endif return res; } VpiValueCbHdl::VpiValueCbHdl(GpiImplInterface *impl, VpiSignalObjHdl *signal, gpi_edge edge) : VpiCbHdl(impl), m_signal(signal), m_edge(edge) { vpi_time.type = vpiSuppressTime; m_vpi_value.format = vpiIntVal; cb_data.reason = cbValueChange; cb_data.time = &vpi_time; cb_data.value = &m_vpi_value; cb_data.obj = m_signal->get_handle(); } int VpiValueCbHdl::run() { // LCOV_EXCL_START if (m_removed) { // Only call up if not removed. return 0; } // LCOV_EXCL_STOP bool pass = false; switch (m_edge) { case GPI_RISING: { pass = !strcmp(m_signal->get_signal_value_binstr(), "1"); break; } case GPI_FALLING: { pass = !strcmp(m_signal->get_signal_value_binstr(), "0"); break; } case GPI_VALUE_CHANGE: { pass = true; break; } } int res = 0; if (pass) { res = m_cb_func(m_cb_data); // Remove recurring callback once fired. auto err = vpi_remove_cb(get_handle()); // LCOV_EXCL_START if (!err) { LOG_DEBUG("VPI: Unable to remove callback"); check_vpi_error(); // If we fail to remove the callback, put it in a removed state so // if it fires we can squash it. m_removed = true; } // LCOV_EXCL_STOP else { delete this; } } // else Don't remove and let it fire again. return res; } VpiStartupCbHdl::VpiStartupCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) { #ifndef IUS cb_data.reason = cbStartOfSimulation; #else vpi_time.high = (uint32_t)(0); vpi_time.low = (uint32_t)(0); vpi_time.type = vpiSimTime; cb_data.reason = cbAfterDelay; #endif } VpiShutdownCbHdl::VpiShutdownCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) { cb_data.reason = cbEndOfSimulation; } VpiTimedCbHdl::VpiTimedCbHdl(GpiImplInterface *impl, uint64_t time) : VpiCbHdl(impl) { vpi_time.high = (uint32_t)(time >> 32); vpi_time.low = (uint32_t)(time); vpi_time.type = vpiSimTime; cb_data.reason = cbAfterDelay; } VpiReadWriteCbHdl::VpiReadWriteCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) { cb_data.reason = cbReadWriteSynch; } VpiReadOnlyCbHdl::VpiReadOnlyCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) { cb_data.reason = cbReadOnlySynch; } VpiNextPhaseCbHdl::VpiNextPhaseCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) { cb_data.reason = cbNextSimTime; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/vpi/VpiImpl.cpp0000644000175100017510000006124715106067236021243 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include "VpiImpl.h" #include "_vendor/vpi/vpi_user.h" #include "gpi.h" #include "gpi_logging.h" #include "vpi_user_ext.h" #define CASE_STR(_X) \ case _X: \ return #_X const char *VpiImpl::reason_to_string(int reason) { switch (reason) { CASE_STR(cbValueChange); CASE_STR(cbAtStartOfSimTime); CASE_STR(cbReadWriteSynch); CASE_STR(cbReadOnlySynch); CASE_STR(cbNextSimTime); CASE_STR(cbAfterDelay); CASE_STR(cbStartOfSimulation); CASE_STR(cbEndOfSimulation); default: return "unknown"; } } #undef CASE_STR void VpiImpl::get_sim_time(uint32_t *high, uint32_t *low) { s_vpi_time vpi_time_s; vpi_time_s.type = vpiSimTime; // vpiSimTime; vpi_get_time(NULL, &vpi_time_s); check_vpi_error(); *high = vpi_time_s.high; *low = vpi_time_s.low; } void VpiImpl::get_sim_precision(int32_t *precision) { *precision = vpi_get(vpiTimePrecision, NULL); } const char *VpiImpl::get_simulator_product() { if (m_product.empty() && m_version.empty()) { s_vpi_vlog_info info; if (!vpi_get_vlog_info(&info)) { LOG_WARN("Could not obtain info about the simulator"); m_product = "UNKNOWN"; m_version = "UNKNOWN"; } else { m_product = info.product; m_version = info.version; } } return m_product.c_str(); } const char *VpiImpl::get_simulator_version() { get_simulator_product(); return m_version.c_str(); } static gpi_objtype to_gpi_objtype(int32_t vpitype, int num_elements = 0, bool is_vector = false) { switch (vpitype) { case vpiNet: case vpiNetBit: case vpiBitVar: case vpiReg: case vpiRegBit: case vpiMemoryWord: case vpiPackedArrayVar: case vpiPackedArrayNet: if (is_vector || num_elements > 1) { return GPI_LOGIC_ARRAY; } else { return GPI_LOGIC; } break; case vpiRealNet: case vpiRealVar: return GPI_REAL; case vpiInterfaceArray: case vpiRegArray: case vpiNetArray: case vpiGenScopeArray: case vpiMemory: return GPI_ARRAY; case vpiEnumNet: case vpiEnumVar: return GPI_ENUM; case vpiIntVar: case vpiIntegerVar: case vpiIntegerNet: return GPI_INTEGER; case vpiStructVar: case vpiStructNet: case vpiUnionVar: case vpiUnionNet: return GPI_STRUCTURE; case vpiInterface: case vpiModule: case vpiPort: case vpiGate: case vpiSwitch: case vpiPrimTerm: case vpiGenScope: return GPI_MODULE; case vpiPackage: return GPI_PACKAGE; case vpiStringVar: return GPI_STRING; default: LOG_DEBUG("Unable to map VPI type %d onto GPI type", vpitype); return GPI_UNKNOWN; } } static gpi_objtype const_type_to_gpi_objtype(int32_t const_type) { // Most simulators only return vpiDecConst or vpiBinaryConst switch (const_type) { #ifdef IUS case vpiUndefined: LOG_WARN( "VPI: Xcelium reports undefined parameters as vpiUndefined, " "guessing this is a logic vector"); return GPI_LOGIC_ARRAY; #endif case vpiDecConst: case vpiBinaryConst: case vpiOctConst: case vpiHexConst: case vpiIntConst: return GPI_LOGIC_ARRAY; case vpiRealConst: return GPI_REAL; case vpiStringConst: return GPI_STRING; // case vpiTimeConst: // Not implemented default: LOG_WARN( "Unable to map vpiConst type %d onto GPI type, " "guessing this is a logic vector", const_type); return GPI_LOGIC_ARRAY; } } GpiObjHdl *VpiImpl::create_gpi_obj_from_handle(vpiHandle new_hdl, const std::string &name, const std::string &fq_name) { int32_t type; GpiObjHdl *new_obj = NULL; if (vpiUnknown == (type = vpi_get(vpiType, new_hdl))) { LOG_DEBUG("vpiUnknown returned from vpi_get(vpiType, ...)"); return NULL; } /* What sort of instance is this ?*/ switch (type) { case vpiNet: case vpiNetBit: case vpiBitVar: case vpiReg: case vpiRegBit: case vpiEnumNet: case vpiEnumVar: case vpiIntVar: case vpiIntegerVar: case vpiIntegerNet: case vpiPackedArrayVar: case vpiPackedArrayNet: case vpiRealVar: case vpiRealNet: case vpiStringVar: case vpiMemoryWord: case vpiInterconnectNet: { const auto is_vector = vpi_get(vpiVector, new_hdl); const auto num_elements = vpi_get(vpiSize, new_hdl); new_obj = new VpiSignalObjHdl( this, new_hdl, to_gpi_objtype(type, num_elements, is_vector), false); break; } case vpiParameter: case vpiConstant: { auto const_type = vpi_get(vpiConstType, new_hdl); new_obj = new VpiSignalObjHdl( this, new_hdl, const_type_to_gpi_objtype(const_type), true); break; } case vpiRegArray: case vpiNetArray: case vpiInterfaceArray: case vpiMemory: case vpiInterconnectArray: { const auto is_vector = vpi_get(vpiVector, new_hdl); const auto num_elements = vpi_get(vpiSize, new_hdl); new_obj = new VpiArrayObjHdl( this, new_hdl, to_gpi_objtype(type, num_elements, is_vector)); break; } case vpiStructVar: case vpiStructNet: case vpiUnionVar: case vpiUnionNet: { auto is_vector = false; if (vpi_get(vpiPacked, new_hdl)) { LOG_DEBUG("VPI: Found packed struct/union data type"); new_obj = new VpiSignalObjHdl(this, new_hdl, GPI_PACKED_STRUCTURE, false); break; } else if (vpi_get(vpiVector, new_hdl)) { is_vector = true; } const auto num_elements = vpi_get(vpiSize, new_hdl); new_obj = new VpiObjHdl( this, new_hdl, to_gpi_objtype(type, num_elements, is_vector)); break; } case vpiModule: case vpiInterface: case vpiPort: case vpiGate: case vpiSwitch: case vpiPrimTerm: case vpiGenScope: case vpiGenScopeArray: { std::string hdl_name = vpi_get_str(vpiName, new_hdl); if (hdl_name != name) { LOG_DEBUG("Found pseudo-region %s (hdl_name=%s but name=%s)", fq_name.c_str(), hdl_name.c_str(), name.c_str()); new_obj = new VpiObjHdl(this, new_hdl, GPI_GENARRAY); } else { new_obj = new VpiObjHdl(this, new_hdl, to_gpi_objtype(type)); } break; } default: /* We should only print a warning here if the type is really Verilog, It could be VHDL as some simulators allow querying of both languages via the same handle */ const char *type_name = vpi_get_str(vpiType, new_hdl); std::string unknown = "vpiUnknown"; if (type_name && (unknown != type_name)) { LOG_WARN("VPI: Not able to map type %s(%d) to object.", type_name, type); } else { LOG_WARN("VPI: Simulator does not know this type (%d) via VPI", type); } return NULL; } new_obj->initialise(name, fq_name); LOG_DEBUG("VPI: Created GPI object from type %s(%d)", vpi_get_str(vpiType, new_hdl), type); return new_obj; } GpiObjHdl *VpiImpl::get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) { LOG_DEBUG("Trying to convert raw to VPI handle"); vpiHandle new_hdl = (vpiHandle)raw_hdl; const char *c_name = vpi_get_str(vpiName, new_hdl); if (!c_name) { LOG_DEBUG("Unable to query name of passed in handle"); return NULL; } std::string name = c_name; std::string fq_name = parent->get_fullname() + get_type_delimiter(parent) + name; GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name); if (new_obj == NULL) { vpi_free_object(new_hdl); LOG_DEBUG("Unable to fetch object %s", fq_name.c_str()); return NULL; } return new_obj; } GpiObjHdl *VpiImpl::get_child_by_name(const std::string &name, GpiObjHdl *parent) { const vpiHandle parent_hdl = parent->get_handle(); std::string fq_name = parent->get_fullname() + get_type_delimiter(parent) + name; vpiHandle new_hdl = vpi_handle_by_name(const_cast(fq_name.c_str()), NULL); #ifdef IUS if (new_hdl != NULL && vpi_get(vpiType, new_hdl) == vpiGenScope) { // verify that this xcelium scope is valid, or else we segfault on the // invalid scope. Xcelium only returns vpiGenScope, no vpiGenScopeArray vpiHandle iter = vpi_iterate(vpiInternalScope, parent_hdl); bool is_valid = [&]() -> bool { for (auto rgn = vpi_scan(iter); rgn != NULL; rgn = vpi_scan(iter)) { if (VpiImpl::compare_generate_labels(vpi_get_str(vpiName, rgn), name)) { return true; } } return false; }(); vpi_free_object(iter); if (!is_valid) { vpi_free_object(new_hdl); new_hdl = NULL; } } #endif // Xcelium will segfault on a scope that doesn't exist #ifndef IUS /* Some simulators do not support vpiGenScopeArray, only vpiGenScope: * - Icarus Verilog * - Verilator * - Questa/Modelsim * * If handle is not found by name, look for a generate block with * a matching prefix. * For Example: * genvar idx; * generate * for (idx = 0; idx < 5; idx = idx + 1) begin * ... * end * endgenerate * * genblk1 => vpiGenScopeArray (not found) * genblk1[0] => vpiGenScope * ... * genblk1[4] => vpiGenScope * * genblk1 is not found directly, but if genblk1[n] is found, * genblk1 must exist, so create the pseudo-region object for it. */ if (new_hdl == NULL) { LOG_DEBUG( "Unable to find '%s' through vpi_handle_by_name, looking for " "matching generate scope array using fallback", fq_name.c_str()); vpiHandle iter = vpi_iterate(vpiInternalScope, parent_hdl); if (iter != NULL) { for (auto rgn = vpi_scan(iter); rgn != NULL; rgn = vpi_scan(iter)) { auto rgn_type = vpi_get(vpiType, rgn); if (rgn_type == vpiGenScope || rgn_type == vpiModule) { std::string rgn_name = vpi_get_str(vpiName, rgn); if (VpiImpl::compare_generate_labels(rgn_name, name)) { new_hdl = parent_hdl; vpi_free_object(iter); break; } } } } } #endif if (new_hdl == NULL) { LOG_DEBUG("Unable to find '%s'", fq_name.c_str()); return NULL; } /* Generate Loops have inconsistent behavior across vpi tools. A "name" * without an index, i.e. dut.loop vs dut.loop[0], will find a handle to * vpiGenScopeArray, but not all tools support iterating over the * vpiGenScopeArray. We don't want to create a GpiObjHdl to this type of * vpiHandle. * * If this unique case is hit, we need to create the Pseudo-region, with the * handle being equivalent to the parent handle. */ if (vpi_get(vpiType, new_hdl) == vpiGenScopeArray) { vpi_free_object(new_hdl); new_hdl = parent_hdl; } GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name); if (new_obj == NULL) { vpi_free_object(new_hdl); LOG_DEBUG("Unable to create object '%s'", fq_name.c_str()); return NULL; } return new_obj; } GpiObjHdl *VpiImpl::get_child_by_index(int32_t index, GpiObjHdl *parent) { vpiHandle vpi_hdl = parent->get_handle(); vpiHandle new_hdl = NULL; char buff[14]; // needs to be large enough to hold -2^31 to 2^31-1 in // string form ('['+'-'10+']'+'\0') gpi_objtype obj_type = parent->get_type(); if (obj_type == GPI_GENARRAY) { snprintf(buff, 14, "[%d]", index); LOG_DEBUG("VPI: Get child at index %d of parent '%s' (pseudo-region)", index, parent->get_name_str()); std::string idx = buff; std::string hdl_name = parent->get_fullname() + idx; std::vector writable(hdl_name.begin(), hdl_name.end()); writable.push_back('\0'); new_hdl = vpi_handle_by_name(&writable[0], NULL); } else if (obj_type == GPI_LOGIC || obj_type == GPI_LOGIC_ARRAY || obj_type == GPI_ARRAY || obj_type == GPI_STRING) { new_hdl = vpi_handle_by_index(vpi_hdl, index); /* vpi_handle_by_index() doesn't work for all simulators when dealing * with a two-dimensional array. For example: wire [7:0] sig_t4 * [0:1][0:2]; * * Assume vpi_hdl is for "sig_t4": * vpi_handle_by_index(vpi_hdl, 0); // Returns a handle to * sig_t4[0] for IUS, but NULL on Questa * * Questa only works when both indices are provided, i.e. will need a * pseudo-handle to behave like the first index. */ if (new_hdl == NULL) { int left = parent->get_range_left(); int right = parent->get_range_right(); bool ascending = parent->get_range_dir() == GPI_RANGE_UP; LOG_DEBUG( "Unable to find handle through vpi_handle_by_index(), " "attempting second method"); if ((ascending && (index < left || index > right)) || (!ascending && (index > left || index < right))) { LOG_ERROR( "Invalid Index - Index %d is not in the range of [%d:%d]", index, left, right); return NULL; } /* Get the number of constraints to determine if the index will * result in a pseudo-handle or should be found */ vpiHandle p_hdl = parent->get_handle(); vpiHandle it = vpi_iterate(vpiRange, p_hdl); int constraint_cnt = 0; if (it != NULL) { while (vpi_scan(it) != NULL) { ++constraint_cnt; } } else { constraint_cnt = 1; } std::string act_hdl_name = vpi_get_str(vpiName, p_hdl); /* Removing the act_hdl_name from the parent->get_name() will leave * the pseudo-indices */ if (act_hdl_name.length() < parent->get_name().length()) { std::string idx_str = parent->get_name().substr(act_hdl_name.length()); while (idx_str.length() > 0) { std::size_t found = idx_str.find_first_of("]"); if (found != std::string::npos) { --constraint_cnt; idx_str = idx_str.substr(found + 1); } else { break; } } } snprintf(buff, 14, "[%d]", index); std::string idx = buff; std::string hdl_name = parent->get_fullname() + idx; std::vector writable(hdl_name.begin(), hdl_name.end()); writable.push_back('\0'); new_hdl = vpi_handle_by_name(&writable[0], NULL); /* Create a pseudo-handle if not the last index into a * multi-dimensional array */ if (new_hdl == NULL && constraint_cnt > 1) { new_hdl = p_hdl; } } } else { LOG_ERROR( "VPI: Parent of type %s must be of type GPI_GENARRAY, " "GPI_LOGIC, GPI_LOGIC, GPI_ARRAY, or GPI_STRING to have an index.", parent->get_type_str()); return NULL; } if (new_hdl == NULL) { LOG_DEBUG("Unable to vpi_get_handle_by_index %s[%d]", parent->get_name_str(), index); return NULL; } snprintf(buff, 14, "[%d]", index); std::string idx = buff; std::string name = parent->get_name() + idx; std::string fq_name = parent->get_fullname() + idx; GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name); if (new_obj == NULL) { vpi_free_object(new_hdl); LOG_DEBUG("Unable to fetch object below entity (%s) at index (%d)", parent->get_name_str(), index); return NULL; } return new_obj; } GpiObjHdl *VpiImpl::get_root_handle(const char *name) { vpiHandle root; vpiHandle iterator; GpiObjHdl *rv; std::string root_name; // vpi_iterate with a ref of NULL returns the top level module iterator = vpi_iterate(vpiModule, NULL); check_vpi_error(); if (!iterator) { LOG_INFO("Nothing visible via VPI"); return NULL; } for (root = vpi_scan(iterator); root != NULL; root = vpi_scan(iterator)) { if (to_gpi_objtype(vpi_get(vpiType, root)) != GPI_MODULE) continue; // prevents finding virtual classes (which Xcelium puts at the top-level // scope) when looking for objects with get_root_handle. const char *obj_name = vpi_get_str(vpiFullName, root); if ((!name && obj_name[0] != '\\') || (name && !strcmp(name, obj_name))) break; } if (!root) { check_vpi_error(); goto error; } // Need to free the iterator if it didn't return NULL if (iterator && !vpi_free_object(iterator)) { LOG_WARN("VPI: Attempting to free root iterator failed!"); check_vpi_error(); } root_name = vpi_get_str(vpiFullName, root); rv = new GpiObjHdl(this, root, to_gpi_objtype(vpi_get(vpiType, root))); rv->initialise(root_name, root_name); return rv; error: LOG_ERROR("VPI: Couldn't find root handle %s", name); iterator = vpi_iterate(vpiModule, NULL); for (root = vpi_scan(iterator); root != NULL; root = vpi_scan(iterator)) { LOG_ERROR("VPI: Toplevel instances: %s != %s...", name, vpi_get_str(vpiFullName, root)); if (name == NULL || !strcmp(name, vpi_get_str(vpiFullName, root))) break; } return NULL; } GpiIterator *VpiImpl::iterate_handle(GpiObjHdl *obj_hdl, gpi_iterator_sel type) { GpiIterator *new_iter = NULL; switch (type) { case GPI_OBJECTS: new_iter = new VpiIterator(this, obj_hdl); break; case GPI_DRIVERS: new_iter = new VpiSingleIterator(this, obj_hdl, vpiDriver); break; case GPI_LOADS: new_iter = new VpiSingleIterator(this, obj_hdl, vpiLoad); break; case GPI_PACKAGE_SCOPES: new_iter = new VpiPackageIterator(this); break; default: LOG_WARN("Other iterator types not implemented yet"); break; } return new_iter; } GpiCbHdl *VpiImpl::register_timed_callback(uint64_t time, int (*cb_func)(void *), void *cb_data) { auto cb_hdl = new VpiTimedCbHdl(this, time); auto err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { delete cb_hdl; return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiCbHdl *VpiImpl::register_readwrite_callback(int (*cb_func)(void *), void *cb_data) { auto cb_hdl = new VpiReadWriteCbHdl(this); auto err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { delete cb_hdl; return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiCbHdl *VpiImpl::register_readonly_callback(int (*cb_func)(void *), void *cb_data) { auto cb_hdl = new VpiReadOnlyCbHdl(this); auto err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { delete cb_hdl; return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } GpiCbHdl *VpiImpl::register_nexttime_callback(int (*cb_func)(void *), void *cb_data) { auto cb_hdl = new VpiNextPhaseCbHdl(this); auto err = cb_hdl->arm(); // LCOV_EXCL_START if (err) { delete cb_hdl; return NULL; } // LCOV_EXCL_STOP cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } // If the Python world wants things to shut down then unregister // the callback for end of sim void VpiImpl::sim_end() { m_sim_finish_cb->remove(); #ifdef ICARUS // Must skip checking return value on Icarus because their version of // vpi_control() returns void for some reason. vpi_control(vpiFinish, vpiDiagTimeLoc); #else int ok = vpi_control(vpiFinish, vpiDiagTimeLoc); // LCOV_EXCL_START if (!ok) { LOG_DEBUG("VPI: Failed to end simulation"); check_vpi_error(); } // LCOV_EXCL_STOP #endif } bool VpiImpl::compare_generate_labels(const std::string &a, const std::string &b) { /* Compare two generate labels for equality ignoring any suffixed index. */ std::size_t a_idx = a.rfind("["); std::size_t b_idx = b.rfind("["); return a.substr(0, a_idx) == b.substr(0, b_idx); } const char *VpiImpl::get_type_delimiter(GpiObjHdl *obj_hdl) { return (obj_hdl->get_type() == GPI_PACKAGE) ? "" : "."; } static int startup_callback(void *) { s_vpi_vlog_info info; auto pass = vpi_get_vlog_info(&info); // LCOV_EXCL_START if (!pass) { LOG_ERROR("Unable to get argv and argc from simulator"); info.argc = 0; info.argv = nullptr; } // LCOV_EXCL_STOP gpi_embed_init(info.argc, info.argv); return 0; } static int shutdown_callback(void *) { gpi_embed_end(); return 0; } void VpiImpl::main() noexcept { auto startup_cb = new VpiStartupCbHdl(this); auto err = startup_cb->arm(); // LCOV_EXCL_START if (err) { LOG_CRITICAL( "VPI: Unable to register startup callback! Simulation will end."); check_vpi_error(); delete startup_cb; exit(1); } // LCOV_EXCL_STOP startup_cb->set_cb_info(startup_callback, nullptr); auto shutdown_cb = new VpiShutdownCbHdl(this); err = shutdown_cb->arm(); // LCOV_EXCL_START if (err) { LOG_CRITICAL( "VPI: Unable to register shutdown callback! Simulation will end."); check_vpi_error(); startup_cb->remove(); delete shutdown_cb; exit(1); } // LCOV_EXCL_STOP shutdown_cb->set_cb_info(shutdown_callback, nullptr); m_sim_finish_cb = shutdown_cb; gpi_register_impl(this); gpi_entry_point(); } static void vpi_main() { #ifdef VCS // VCS loads the entry point both during compilation and again at // simulation. Only during simulation are most of the VPI routines // working. So we check if we are in compilation and exit early since we // don't need to do anything for compilation currently. s_vpi_vlog_info info; if (!vpi_get_vlog_info(&info)) { return; } #endif auto vpi_table = new VpiImpl("VPI"); vpi_table->main(); } static void register_impl() { auto vpi_table = new VpiImpl("VPI"); gpi_register_impl(vpi_table); } extern "C" { COCOTBVPI_EXPORT void (*vlog_startup_routines[])() = {vpi_main, nullptr}; // For non-VPI compliant applications that cannot find vlog_startup_routines // symbol COCOTBVPI_EXPORT void vlog_startup_routines_bootstrap() { vpi_main(); } } GPI_ENTRY_POINT(cocotbvpi, register_impl) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/vpi/VpiImpl.h0000644000175100017510000002303515106067236020701 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #ifndef COCOTB_VPI_IMPL_H_ #define COCOTB_VPI_IMPL_H_ #include #include #include #include "../gpi/gpi_priv.h" #include "_vendor/vpi/sv_vpi_user.h" #include "exports.h" #include "gpi.h" #include "gpi_logging.h" #ifdef COCOTBVPI_EXPORTS #define COCOTBVPI_EXPORT COCOTB_EXPORT #else #define COCOTBVPI_EXPORT COCOTB_IMPORT #endif // TODO Move the check_vpi_error stuff into another file // Should be run after every VPI call to check error status static inline void __check_vpi_error(const char *file, const char *func, long line) { if (gpi_log_filtered("gpi", GPI_DEBUG)) { return; } int level = 0; s_vpi_error_info info; enum gpi_log_level loglevel; memset(&info, 0, sizeof(info)); level = vpi_chk_error(&info); if (info.code == 0 && level == 0) { return; } switch (level) { case vpiNotice: loglevel = GPI_INFO; break; case vpiWarning: loglevel = GPI_WARNING; break; case vpiError: loglevel = GPI_ERROR; break; case vpiSystem: case vpiInternal: loglevel = GPI_CRITICAL; break; default: loglevel = GPI_WARNING; } LOG_EXPLICIT("gpi", GPI_DEBUG, file, func, line, "VPI Internal Error: %s @ %s:%d: %s", gpi_log_level_to_str(loglevel), info.file, info.line, info.message); } #define check_vpi_error() \ do { \ __check_vpi_error(__FILE__, __func__, __LINE__); \ } while (0) class VpiCbHdl : public GpiCbHdl { public: VpiCbHdl(GpiImplInterface *impl); int arm() override; int remove() override; int run() override; protected: s_cb_data cb_data; s_vpi_time vpi_time; bool m_removed = false; }; class VpiSignalObjHdl; class VpiValueCbHdl : public VpiCbHdl { public: VpiValueCbHdl(GpiImplInterface *impl, VpiSignalObjHdl *sig, gpi_edge edge); int run() override; private: s_vpi_value m_vpi_value; GpiSignalObjHdl *m_signal; gpi_edge m_edge; }; class VpiTimedCbHdl : public VpiCbHdl { public: VpiTimedCbHdl(GpiImplInterface *impl, uint64_t time); }; class VpiReadOnlyCbHdl : public VpiCbHdl { public: VpiReadOnlyCbHdl(GpiImplInterface *impl); }; class VpiNextPhaseCbHdl : public VpiCbHdl { public: VpiNextPhaseCbHdl(GpiImplInterface *impl); }; class VpiReadWriteCbHdl : public VpiCbHdl { public: VpiReadWriteCbHdl(GpiImplInterface *impl); }; class VpiStartupCbHdl : public VpiCbHdl { public: VpiStartupCbHdl(GpiImplInterface *impl); // Too many sims get upset trying to remove startup callbacks so we just // don't try. TODO Is this still accurate? int run() override { int res = 0; if (!m_removed) { res = m_cb_func(m_cb_data); } delete this; return res; } int remove() override { m_removed = true; return 0; } }; class VpiShutdownCbHdl : public VpiCbHdl { public: VpiShutdownCbHdl(GpiImplInterface *impl); // Too many sims get upset trying to remove startup callbacks so we just // don't try. TODO Is this still accurate? int run() override { int res = 0; if (!m_removed) { res = m_cb_func(m_cb_data); } delete this; return res; } int remove() override { m_removed = true; return 0; } }; class VpiArrayObjHdl : public GpiObjHdl { public: VpiArrayObjHdl(GpiImplInterface *impl, vpiHandle hdl, gpi_objtype objtype) : GpiObjHdl(impl, hdl, objtype) {} int initialise(const std::string &name, const std::string &fq_name) override; }; class VpiObjHdl : public GpiObjHdl { public: VpiObjHdl(GpiImplInterface *impl, vpiHandle hdl, gpi_objtype objtype) : GpiObjHdl(impl, hdl, objtype) {} const char *get_definition_name() override; const char *get_definition_file() override; }; class VpiSignalObjHdl : public GpiSignalObjHdl { public: VpiSignalObjHdl(GpiImplInterface *impl, vpiHandle hdl, gpi_objtype objtype, bool is_const) : GpiSignalObjHdl(impl, hdl, objtype, is_const) {} const char *get_signal_value_binstr() override; const char *get_signal_value_str() override; double get_signal_value_real() override; long get_signal_value_long() override; int set_signal_value(const int32_t value, gpi_set_action action) override; int set_signal_value(const double value, gpi_set_action action) override; int set_signal_value_binstr(std::string &value, gpi_set_action action) override; int set_signal_value_str(std::string &value, gpi_set_action action) override; /* Value change callback accessor */ int initialise(const std::string &name, const std::string &fq_name) override; GpiCbHdl *register_value_change_callback(gpi_edge edge, int (*function)(void *), void *cb_data) override; private: int set_signal_value(s_vpi_value value, gpi_set_action action); }; class VpiIterator : public GpiIterator { public: VpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl); ~VpiIterator() override; Status next_handle(std::string &name, GpiObjHdl **hdl, void **raw_hdl) override; private: vpiHandle m_iterator; static std::map> iterate_over; /* Possible mappings */ std::vector *selected; /* Mapping currently in use */ std::vector::iterator one2many; }; // Base class for simple iterator that only iterates over a single type class VpiSingleIterator : public GpiIterator { public: VpiSingleIterator(GpiImplInterface *impl, GpiObjHdl *hdl, int32_t vpitype) : GpiIterator(impl, hdl) { vpiHandle vpi_hdl = m_parent->get_handle(); m_iterator = vpi_iterate(vpitype, vpi_hdl); if (NULL == m_iterator) { LOG_DEBUG("vpi_iterate returned NULL for type %d for object %s(%d)", vpitype, vpi_get_str(vpiType, vpi_hdl), vpi_get(vpiType, vpi_hdl)); return; } } Status next_handle(std::string &name, GpiObjHdl **hdl, void **raw_hdl) override; protected: vpiHandle m_iterator = nullptr; }; class VpiPackageIterator : public GpiIterator { public: VpiPackageIterator(GpiImplInterface *impl) : GpiIterator(impl, nullptr) { // Questa doesn't support iteration over vpiPackage but everything // supports vpiInstance which is a superset m_iterator = vpi_iterate(vpiInstance, nullptr); if (NULL == m_iterator) { LOG_WARN( "vpi_iterate returned NULL for type vpiInstance for object " "NULL"); return; } } Status next_handle(std::string &name, GpiObjHdl **hdl, void **raw_hdl) override; private: vpiHandle m_iterator = nullptr; }; class VpiImpl : public GpiImplInterface { public: VpiImpl(const std::string &name) : GpiImplInterface(name) {} /* Sim related */ void sim_end(void) override; void get_sim_time(uint32_t *high, uint32_t *low) override; void get_sim_precision(int32_t *precision) override; const char *get_simulator_product() override; const char *get_simulator_version() override; /* Hierarchy related */ GpiObjHdl *get_root_handle(const char *name) override; GpiIterator *iterate_handle(GpiObjHdl *obj_hdl, gpi_iterator_sel type) override; GpiObjHdl *next_handle(GpiIterator *iter); /* Callback related, these may (will) return the same handle*/ GpiCbHdl *register_timed_callback(uint64_t time, int (*function)(void *), void *cb_data) override; GpiCbHdl *register_readonly_callback(int (*function)(void *), void *cb_data) override; GpiCbHdl *register_nexttime_callback(int (*function)(void *), void *cb_data) override; GpiCbHdl *register_readwrite_callback(int (*function)(void *), void *cb_data) override; GpiObjHdl *get_child_by_name(const std::string &name, GpiObjHdl *parent) override; GpiObjHdl *get_child_by_index(int32_t index, GpiObjHdl *parent) override; GpiObjHdl *get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) override; const char *reason_to_string(int reason) override; GpiObjHdl *create_gpi_obj_from_handle(vpiHandle new_hdl, const std::string &name, const std::string &fq_name); static bool compare_generate_labels(const std::string &a, const std::string &b); const char *get_type_delimiter(GpiObjHdl *obj_hdl); void main() noexcept; private: // We store the shutdown callback handle here so sim_end() can remove() it // if it's called. VpiShutdownCbHdl *m_sim_finish_cb; }; #endif /*COCOTB_VPI_IMPL_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/vpi/VpiIterator.cpp0000644000175100017510000002676415106067236022140 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include #include "VpiImpl.h" #include "vpi_user_ext.h" decltype(VpiIterator::iterate_over) VpiIterator::iterate_over = [] { /* for reused lists */ // clang-format off // vpiInstance is the base class for module, program, interface, etc. std::vector instance_options = { vpiNet, vpiNetArray, vpiReg, vpiRegArray, }; std::vector module_options = { // vpiModule, // Aldec SEGV on mixed language // vpiModuleArray, // Aldec SEGV on mixed language vpiMemory, vpiIntegerVar, vpiRealVar, vpiRealNet, vpiStructVar, vpiStructNet, vpiVariables, vpiNamedEvent, vpiNamedEventArray, vpiParameter, vpiPrimitive, vpiPrimitiveArray, vpiInternalScope, // vpiInterface, // Aldec SEGV on mixed language // vpiInterfaceArray, // Aldec SEGV on mixed language }; // clang-format on // append base class vpiInstance members module_options.insert(module_options.begin(), instance_options.begin(), instance_options.end()); std::vector struct_options = { vpiNet, #ifndef IUS vpiNetArray, #endif vpiReg, vpiRegArray, vpiMemory, vpiParameter, vpiPrimitive, vpiPrimitiveArray, vpiMember, }; return decltype(VpiIterator::iterate_over){ {vpiModule, module_options}, {vpiInterface, instance_options}, {vpiGenScope, module_options}, {vpiStructVar, struct_options}, {vpiStructNet, struct_options}, {vpiNet, { vpiNetBit, }}, {vpiNetArray, { vpiNet, }}, {vpiRegArray, { vpiReg, }}, {vpiMemory, { vpiMemoryWord, }}, {vpiPackage, { vpiParameter, }}, }; }(); VpiIterator::VpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl) : GpiIterator(impl, hdl), m_iterator(NULL) { vpiHandle iterator; vpiHandle vpi_hdl = m_parent->get_handle(); int type = vpi_get(vpiType, vpi_hdl); try { selected = &iterate_over.at(type); } catch (std::out_of_range const &) { LOG_WARN("VPI: Implementation does not know how to iterate over %s(%d)", vpi_get_str(vpiType, vpi_hdl), type); selected = nullptr; return; } for (one2many = selected->begin(); one2many != selected->end(); one2many++) { /* GPI_GENARRAY are pseudo-regions and all that should be searched for * are the sub-regions */ if (m_parent->get_type() == GPI_GENARRAY && *one2many != vpiInternalScope) { LOG_DEBUG( "vpi_iterator vpiOneToManyT=%d skipped for GPI_GENARRAY type", *one2many); continue; } iterator = vpi_iterate(*one2many, vpi_hdl); if (iterator) { break; } LOG_DEBUG("vpi_iterate type=%d returned NULL", *one2many); } if (NULL == iterator) { LOG_DEBUG( "vpi_iterate return NULL for all relationships on %s (%d) type:%s", vpi_get_str(vpiName, vpi_hdl), type, vpi_get_str(vpiType, vpi_hdl)); selected = NULL; return; } LOG_DEBUG("Created iterator working from '%s' with type %s(%d)", vpi_get_str(vpiFullName, vpi_hdl), vpi_get_str(vpiType, vpi_hdl), type); m_iterator = iterator; } VpiIterator::~VpiIterator() { if (m_iterator) vpi_free_object(m_iterator); } #define VPI_TYPE_MAX (1000) GpiIterator::Status VpiSingleIterator::next_handle(std::string &name, GpiObjHdl **hdl, void **raw_hdl) { GpiObjHdl *new_obj; vpiHandle obj; if (NULL == m_iterator) return GpiIterator::END; obj = vpi_scan(m_iterator); if (NULL == obj) return GpiIterator::END; const char *c_name = vpi_get_str(vpiName, obj); if (!c_name) { int type = vpi_get(vpiType, obj); if (type >= VPI_TYPE_MAX) { *raw_hdl = (void *)obj; return GpiIterator::NOT_NATIVE_NO_NAME; } LOG_DEBUG("Unable to get the name for this object of type %d", type); return GpiIterator::NATIVE_NO_NAME; } std::string fq_name = c_name; LOG_DEBUG("vpi_scan found '%s = '%s'", name.c_str(), fq_name.c_str()); VpiImpl *vpi_impl = reinterpret_cast(m_impl); new_obj = vpi_impl->create_gpi_obj_from_handle(obj, name, fq_name); if (new_obj) { *hdl = new_obj; return GpiIterator::NATIVE; } else return GpiIterator::NOT_NATIVE; } GpiIterator::Status VpiPackageIterator::next_handle(std::string &, GpiObjHdl **hdl, void **) { GpiObjHdl *new_obj; vpiHandle obj; if (NULL == m_iterator) return GpiIterator::END; // obj might not be a package since we are forced to iterate over all // vpiInstance due to a limitation in Questa so we keep searching until we // find one // Check that an object has a non-NULL name during iteration, and pass over // it if it does. This happens with xcelium. std::string name; while (true) { obj = vpi_scan(m_iterator); check_vpi_error(); if (obj == nullptr) return GpiIterator::END; PLI_INT32 type = vpi_get(vpiType, obj); check_vpi_error(); if (type == vpiPackage) { auto name_cstr = vpi_get_str(vpiName, obj); check_vpi_error(); if (name_cstr != nullptr) { name = name_cstr; break; } } } VpiImpl *vpi_impl = reinterpret_cast(m_impl); std::string fq_name = vpi_get_str(vpiFullName, obj); LOG_DEBUG("VPI: package found '%s' = '%s'", name.c_str(), fq_name.c_str()); // '::' may or may not be included in the package vpiFullName: std::string package_delim = "::"; if (fq_name.compare(fq_name.length() - package_delim.length(), package_delim.length(), package_delim)) { fq_name += "::"; } new_obj = new VpiObjHdl(vpi_impl, obj, GPI_PACKAGE); new_obj->initialise(name, fq_name); *hdl = new_obj; return GpiIterator::NATIVE; } GpiIterator::Status VpiIterator::next_handle(std::string &name, GpiObjHdl **hdl, void **raw_hdl) { GpiObjHdl *new_obj; vpiHandle obj; vpiHandle iter_obj = m_parent->get_handle(); if (!selected) return GpiIterator::END; gpi_objtype obj_type = m_parent->get_type(); std::string parent_name = m_parent->get_name(); do { obj = NULL; if (m_iterator) { obj = vpi_scan(m_iterator); /* For GPI_GENARRAY, only allow the generate statements through that * match the name of the generate block. */ if (obj != NULL && obj_type == GPI_GENARRAY) { auto rgn_type = vpi_get(vpiType, obj); if (rgn_type == vpiGenScope || rgn_type == vpiModule) { std::string rgn_name = vpi_get_str(vpiName, obj); if (!VpiImpl::compare_generate_labels(rgn_name, parent_name)) { obj = NULL; continue; } } else { obj = NULL; continue; } } if (NULL == obj) { /* m_iterator will already be free'd internally here */ m_iterator = NULL; } else { break; } LOG_DEBUG("End of type=%d iteration", *one2many); } else { LOG_DEBUG("No valid type=%d iterator", *one2many); } if (++one2many >= selected->end()) { obj = NULL; break; } /* GPI_GENARRAY are pseudo-regions and all that should be searched for * are the sub-regions */ if (obj_type == GPI_GENARRAY && *one2many != vpiInternalScope) { LOG_DEBUG( "vpi_iterator vpiOneToManyT=%d skipped for GPI_GENARRAY type", *one2many); continue; } m_iterator = vpi_iterate(*one2many, iter_obj); } while (!obj); if (NULL == obj) { LOG_DEBUG("No more children, all relationships tested"); return GpiIterator::END; } /* Simulators vary here. Some will allow the name to be accessed across boundary. We can simply return this up and allow the object to be created. Others do not. In this case we see if the object is in our type range and if not return the raw_hdl up */ const char *c_name = vpi_get_str(vpiName, obj); if (!c_name) { /* This may be another type */ int type = vpi_get(vpiType, obj); if (type >= VPI_TYPE_MAX) { *raw_hdl = (void *)obj; return GpiIterator::NOT_NATIVE_NO_NAME; } LOG_DEBUG("Unable to get the name for this object of type %d", type); return GpiIterator::NATIVE_NO_NAME; } /* * If the parent is not a generate loop, then watch for generate handles and * create the pseudo-region. * * NOTE: Taking advantage of the "caching" to only create one pseudo-region * object. Otherwise a list would be required and checked while iterating */ if (*one2many == vpiInternalScope && obj_type != GPI_GENARRAY && vpi_get(vpiType, obj) == vpiGenScope) { std::string idx_str = c_name; std::size_t found = idx_str.rfind("["); if (found != std::string::npos && found != 0) { name = idx_str.substr(0, found); obj = m_parent->get_handle(); } else { name = c_name; } } else { name = c_name; } /* We try and create a handle internally, if this is not possible we return and GPI will try other implementations with the name */ std::string fq_name = m_parent->get_fullname(); VpiImpl *vpi_impl = reinterpret_cast(m_impl); if (obj_type == GPI_GENARRAY) { std::size_t found = name.rfind("["); if (found != std::string::npos) { fq_name += name.substr(found); } else { LOG_WARN("Unhandled Sub-Element Format - %s", name.c_str()); fq_name += "." + name; } } else if (obj_type == GPI_STRUCTURE) { std::size_t found = name.rfind("."); if (found != std::string::npos) { fq_name += name.substr(found); name = name.substr(found + 1); } else { LOG_WARN("Unhandled Sub-Element Format - %s", name.c_str()); fq_name += "." + name; } } else { fq_name += vpi_impl->get_type_delimiter(m_parent) + name; } LOG_DEBUG("vpi_scan found '%s'", fq_name.c_str()); new_obj = vpi_impl->create_gpi_obj_from_handle(obj, name, fq_name); if (new_obj) { *hdl = new_obj; return GpiIterator::NATIVE; } else return GpiIterator::NOT_NATIVE; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/vpi/VpiObj.cpp0000644000175100017510000000713615106067236021051 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include #include "VpiImpl.h" int VpiArrayObjHdl::initialise(const std::string &name, const std::string &fq_name) { vpiHandle hdl = GpiObjHdl::get_handle(); m_indexable = true; int range_idx = 0; /* Need to determine if this is a pseudo-handle to be able to select the * correct range */ std::string hdl_name = vpi_get_str(vpiName, hdl); /* Removing the hdl_name from the name will leave the pseudo-indices */ if (hdl_name.length() < name.length()) { // get the last index of hdl_name in name std::size_t idx_str = name.rfind(hdl_name); if (idx_str == std::string::npos) { LOG_ERROR("Unable to find name %s in %s", hdl_name.c_str(), name.c_str()); return -1; } // count occurrences of [ auto start = name.begin() + static_cast(idx_str); range_idx = static_cast(std::count(start, name.end(), '[')); } /* After determining the range_idx, get the range and set the limits */ vpiHandle iter = vpi_iterate(vpiRange, hdl); vpiHandle rangeHdl; if (iter != NULL) { rangeHdl = vpi_scan(iter); // Questa and VCS vpiRange iter always starts from the first index of the array. #if defined(MODELSIM) || defined(VCS) for (int i = 0; i < range_idx; ++i) { rangeHdl = vpi_scan(iter); if (rangeHdl == NULL) { break; } } #endif if (rangeHdl == NULL) { LOG_ERROR("Unable to get range for indexable array"); return -1; } vpi_free_object(iter); // Need to free iterator since exited early } else if (range_idx == 0) { rangeHdl = hdl; } else { LOG_ERROR("Unable to get range for indexable array or memory"); return -1; } s_vpi_value val; val.format = vpiIntVal; vpi_get_value(vpi_handle(vpiLeftRange, rangeHdl), &val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange, rangeHdl), &val); check_vpi_error(); m_range_right = val.value.integer; /* vpiSize will return a size that is incorrect for multi-dimensional arrays * so use the range to calculate the m_num_elems. * * For example: * wire [7:0] sig_t4 [0:3][7:4] * * The size of "sig_t4" will be reported as 16 through the vpi interface. */ if (m_range_left > m_range_right) { m_num_elems = m_range_left - m_range_right + 1; m_range_dir = GPI_RANGE_DOWN; } else { m_num_elems = m_range_right - m_range_left + 1; m_range_dir = GPI_RANGE_UP; } return GpiObjHdl::initialise(name, fq_name); } const char *VpiObjHdl::get_definition_name() { if (m_definition_name.empty()) { auto hdl = get_handle(); auto *str = vpi_get_str(vpiDefName, hdl); if (str != NULL) { m_definition_name = str; } } return m_definition_name.c_str(); } const char *VpiObjHdl::get_definition_file() { if (m_definition_file.empty()) { auto hdl = GpiObjHdl::get_handle(); auto *str = vpi_get_str(vpiDefFile, hdl); if (str != NULL) { m_definition_file = str; } } return m_definition_file.c_str(); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/share/lib/vpi/VpiSignal.cpp0000644000175100017510000001720415106067236021551 0ustar00runnerrunner// Copyright cocotb contributors // Copyright (c) 2013, 2018 Potential Ventures Ltd // Copyright (c) 2013 SolarFlare Communications Inc // Licensed under the Revised BSD License, see LICENSE for details. // SPDX-License-Identifier: BSD-3-Clause #include #include "VpiImpl.h" #include "gpi.h" #include "vpi_user_ext.h" int VpiSignalObjHdl::initialise(const std::string &name, const std::string &fq_name) { int32_t type = vpi_get(vpiType, GpiObjHdl::get_handle()); if ((vpiIntVar == type) || (vpiIntegerVar == type) || (vpiIntegerNet == type) || (vpiRealNet == type)) { m_num_elems = 1; } else { m_num_elems = vpi_get(vpiSize, GpiObjHdl::get_handle()); if (GpiObjHdl::get_type() == GPI_STRING || type == vpiConstant || type == vpiParameter) { m_indexable = false; // Don't want to iterate over indices m_range_left = 0; m_range_right = m_num_elems - 1; } else if (GpiObjHdl::get_type() == GPI_LOGIC || GpiObjHdl::get_type() == GPI_LOGIC_ARRAY) { vpiHandle hdl = GpiObjHdl::get_handle(); m_indexable = vpi_get(vpiVector, hdl); if (m_indexable) { s_vpi_value val; vpiHandle iter; val.format = vpiIntVal; iter = vpi_iterate(vpiRange, hdl); /* Only ever need the first "range" */ if (iter != NULL) { vpiHandle rangeHdl = vpi_scan(iter); vpi_free_object(iter); if (rangeHdl != NULL) { vpi_get_value(vpi_handle(vpiLeftRange, rangeHdl), &val); check_vpi_error(); m_range_left = val.value.integer; vpi_get_value(vpi_handle(vpiRightRange, rangeHdl), &val); check_vpi_error(); m_range_right = val.value.integer; } else { LOG_ERROR( "VPI: Unable to get range for %s of type %s (%d)", name.c_str(), vpi_get_str(vpiType, hdl), type); return -1; } } else { vpiHandle leftRange = vpi_handle(vpiLeftRange, hdl); check_vpi_error(); vpiHandle rightRange = vpi_handle(vpiRightRange, hdl); check_vpi_error(); if (leftRange != NULL and rightRange != NULL) { vpi_get_value(leftRange, &val); m_range_left = val.value.integer; vpi_get_value(rightRange, &val); m_range_right = val.value.integer; } else { LOG_WARN( "VPI: Cannot discover range bounds, guessing based " "on elements"); m_range_left = 0; m_range_right = m_num_elems - 1; } } LOG_DEBUG( "VPI: Indexable object initialized with range [%d:%d] and " "length >%d<", m_range_left, m_range_right, m_num_elems); } else { m_range_left = 0; m_range_right = m_num_elems - 1; } } } m_range_dir = m_range_left > m_range_right ? GPI_RANGE_DOWN : GPI_RANGE_UP; LOG_DEBUG("VPI: %s initialized with %d elements", name.c_str(), m_num_elems); return GpiObjHdl::initialise(name, fq_name); } const char *VpiSignalObjHdl::get_signal_value_binstr() { s_vpi_value value_s = {vpiBinStrVal, {NULL}}; vpi_get_value(GpiObjHdl::get_handle(), &value_s); check_vpi_error(); return value_s.value.str; } const char *VpiSignalObjHdl::get_signal_value_str() { s_vpi_value value_s = {vpiStringVal, {NULL}}; vpi_get_value(GpiObjHdl::get_handle(), &value_s); check_vpi_error(); return value_s.value.str; } double VpiSignalObjHdl::get_signal_value_real() { s_vpi_value value_s = {vpiRealVal, {NULL}}; vpi_get_value(GpiObjHdl::get_handle(), &value_s); check_vpi_error(); return value_s.value.real; } long VpiSignalObjHdl::get_signal_value_long() { s_vpi_value value_s = {vpiIntVal, {NULL}}; vpi_get_value(GpiObjHdl::get_handle(), &value_s); check_vpi_error(); return value_s.value.integer; } // Value related functions int VpiSignalObjHdl::set_signal_value(int32_t value, gpi_set_action action) { s_vpi_value value_s; value_s.value.integer = static_cast(value); value_s.format = vpiIntVal; return set_signal_value(value_s, action); } int VpiSignalObjHdl::set_signal_value(double value, gpi_set_action action) { s_vpi_value value_s; value_s.value.real = value; value_s.format = vpiRealVal; return set_signal_value(value_s, action); } int VpiSignalObjHdl::set_signal_value_binstr(std::string &value, gpi_set_action action) { s_vpi_value value_s; std::vector writable(value.begin(), value.end()); writable.push_back('\0'); value_s.value.str = &writable[0]; value_s.format = vpiBinStrVal; return set_signal_value(value_s, action); } int VpiSignalObjHdl::set_signal_value_str(std::string &value, gpi_set_action action) { s_vpi_value value_s; std::vector writable(value.begin(), value.end()); writable.push_back('\0'); value_s.value.str = &writable[0]; value_s.format = vpiStringVal; return set_signal_value(value_s, action); } int VpiSignalObjHdl::set_signal_value(s_vpi_value value_s, gpi_set_action action) { PLI_INT32 vpi_put_flag = -1; s_vpi_time vpi_time_s; vpi_time_s.type = vpiSimTime; vpi_time_s.high = 0; vpi_time_s.low = 0; switch (action) { case GPI_DEPOSIT: #if defined(MODELSIM) || defined(IUS) // Xcelium and Questa do not like setting string variables using // vpiInertialDelay. if (vpiStringVar == vpi_get(vpiType, GpiObjHdl::get_handle())) { vpi_put_flag = vpiNoDelay; } else { vpi_put_flag = vpiInertialDelay; } #else vpi_put_flag = vpiInertialDelay; #endif break; case GPI_FORCE: vpi_put_flag = vpiForceFlag; break; case GPI_RELEASE: // Best to pass its current value to the sim when releasing vpi_get_value(GpiObjHdl::get_handle(), &value_s); vpi_put_flag = vpiReleaseFlag; break; case GPI_NO_DELAY: vpi_put_flag = vpiNoDelay; break; default: assert(0); } if (vpi_put_flag == vpiNoDelay) { vpi_put_value(GpiObjHdl::get_handle(), &value_s, NULL, vpiNoDelay); } else { vpi_put_value(GpiObjHdl::get_handle(), &value_s, &vpi_time_s, vpi_put_flag); } check_vpi_error(); return 0; } GpiCbHdl *VpiSignalObjHdl::register_value_change_callback( gpi_edge edge, int (*cb_func)(void *), void *cb_data) { VpiValueCbHdl *cb_hdl = new VpiValueCbHdl(this->m_impl, this, edge); if (cb_hdl->arm()) { delete this; return NULL; } cb_hdl->set_cb_info(cb_func, cb_data); return cb_hdl; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/simtime.py0000644000175100017510000001473215106067236016527 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """Tools for dealing with simulated time.""" import warnings from decimal import Decimal from fractions import Fraction from functools import lru_cache from math import ceil, floor from typing import Union, cast, overload from cocotb import simulator from cocotb._py_compat import Literal, TypeAlias from cocotb._typing import RoundMode, TimeUnit __all__ = ( "convert", "get_sim_time", "time_precision", ) Steps: TypeAlias = Literal["step"] TimeUnitWithoutSteps: TypeAlias = Literal["fs", "ps", "ns", "us", "ms", "sec"] @overload def convert( value: Union[float, Fraction, Decimal], unit: TimeUnit, *, to: Steps, round_mode: RoundMode = "error", ) -> int: ... @overload def convert( value: Union[float, Fraction, Decimal], unit: TimeUnit, *, to: TimeUnitWithoutSteps, round_mode: RoundMode = "error", ) -> float: ... def convert( value: Union[float, Decimal, Fraction], unit: TimeUnit, *, to: TimeUnit, round_mode: RoundMode = "error", ) -> float: """Convert time values from one unit to another unit. Args: value: The time value. unit: The unit of *value* (one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``). to: The unit to convert *value* to (one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``). round_mode: How to handle non-integral step values (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``). When *round_mode* is ``"error"``, a :exc:`ValueError` is thrown if the value cannot be accurately represented in terms of simulator time steps. When *round_mode* is ``"round"``, ``"ceil"``, or ``"floor"``, the corresponding rounding function from the standard library will be used to round to a simulator time step. Returns: The value scaled by the difference in units. .. versionadded:: 2.0 """ if unit == "step": steps = cast("int", value) else: steps = _get_sim_steps(value, unit, round_mode=round_mode) if to == "step": return steps else: return _get_time_from_sim_steps(steps, to) @overload def get_sim_time(unit: Steps = "step", *, units: None = None) -> int: ... @overload def get_sim_time(unit: TimeUnitWithoutSteps, *, units: None = None) -> float: ... def get_sim_time(unit: TimeUnit = "step", *, units: None = None) -> float: """Retrieve the simulation time from the simulator. Args: unit: String specifying the unit of the result (one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``). ``'step'`` will return the raw simulation time. .. versionchanged:: 2.0 Passing ``None`` as the *unit* argument was removed, use ``'step'`` instead. .. versionchanged:: 2.0 Renamed from ``units``. Raises: ValueError: If *unit* is not a valid unit. Returns: The simulation time in the specified unit. .. versionchanged:: 1.6 Support ``'step'`` as the the *unit* argument to mean "simulator time step". .. versionchanged:: 2.0 Moved from :mod:`cocotb.utils` to :mod:`cocotb.simtime`. """ if units is not None: warnings.warn( "The 'units' argument has been renamed to 'unit'.", DeprecationWarning, stacklevel=2, ) unit = units timeh, timel = simulator.get_sim_time() steps = timeh << 32 | timel return _get_time_from_sim_steps(steps, unit) if unit != "step" else steps @overload def _ldexp10(frac: float, exp: int) -> float: ... @overload def _ldexp10(frac: Fraction, exp: int) -> Fraction: ... @overload def _ldexp10(frac: Decimal, exp: int) -> Decimal: ... def _ldexp10( frac: Union[float, Fraction, Decimal], exp: int ) -> Union[float, Fraction, Decimal]: """Like :func:`math.ldexp`, but base 10.""" # using * or / separately prevents rounding errors if `frac` is a # high-precision type if exp > 0: return frac * (10**exp) else: return frac / (10**-exp) def _get_time_from_sim_steps( steps: int, unit: TimeUnit, ) -> float: if unit == "step": return steps return _ldexp10(steps, time_precision - _get_log_time_scale(unit)) def _get_sim_steps( time: Union[float, Fraction, Decimal], unit: TimeUnit = "step", *, round_mode: RoundMode = "error", ) -> int: result: Union[float, Fraction, Decimal] if unit != "step": result = _ldexp10(time, _get_log_time_scale(unit) - time_precision) else: result = time if round_mode == "error": result_rounded = floor(result) if result_rounded != result: raise ValueError( f"Unable to accurately represent {time}({unit}) with the simulator precision of 1e{time_precision}" ) elif round_mode == "ceil": result_rounded = ceil(result) elif round_mode == "round": result_rounded = round(result) elif round_mode == "floor": result_rounded = floor(result) else: raise ValueError(f"Invalid round_mode specifier: {round_mode}") return result_rounded @lru_cache(maxsize=None) def _get_log_time_scale(unit: TimeUnitWithoutSteps) -> int: """Retrieve the ``log10()`` of the scale factor for a given time unit. Args: unit: String specifying the unit (one of ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``). .. versionchanged:: 2.0 Renamed from ``units``. Raises: ValueError: If *unit* is not a valid unit. Returns: The ``log10()`` of the scale factor for the time unit. """ scale = {"fs": -15, "ps": -12, "ns": -9, "us": -6, "ms": -3, "sec": 0} unit_lwr = unit.lower() if unit_lwr not in scale: raise ValueError(f"Invalid unit ({unit}) provided") else: return scale[unit_lwr] time_precision: int = _get_log_time_scale("fs") """The precision of time in the current simulation. The value is seconds in powers of tens, i.e. ``-15`` is ``10**-15`` seconds or 1 femtosecond. .. versionadded:: 2.0 """ def _init() -> None: global time_precision time_precision = simulator.get_precision() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/simulator.pyi0000644000175100017510000000717315106067236017251 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # generated with mypy's stubgen script from logging import Logger from typing import Any, Callable from cocotb.handle import GPIDiscovery DRIVERS: int ENUM: int GENARRAY: int INTEGER: int LOADS: int LOGIC: int LOGIC_ARRAY: int MEMORY: int MODULE: int NETARRAY: int OBJECTS: int PACKAGE: int REAL: int STRING: int STRUCTURE: int PACKED_STRUCTURE: int UNKNOWN: int RISING: int FALLING: int VALUE_CHANGE: int RANGE_UP: int RANGE_DOWN: int RANGE_NO_DIR: int class gpi_cb_hdl: def deregister(self) -> None: ... def __eq__(self, other: object) -> bool: ... def __ne__(self, other: object) -> bool: ... def __hash__(self) -> int: ... class gpi_iterator_hdl: def __eq__(self, other: object) -> bool: ... def __ne__(self, other: object) -> bool: ... def __hash__(self) -> int: ... def __iter__(self) -> gpi_iterator_hdl: ... def __next__(self) -> gpi_sim_hdl: ... class gpi_sim_hdl: def get_const(self) -> bool: ... def get_definition_file(self) -> str: ... def get_definition_name(self) -> str: ... def get_handle_by_index(self, index: int) -> gpi_sim_hdl | None: ... def get_handle_by_name( self, name: str, discovery_method: GPIDiscovery | None = GPIDiscovery.AUTO ) -> gpi_sim_hdl | None: ... def get_indexable(self) -> bool: ... def get_name_string(self) -> str: ... def get_num_elems(self) -> int: ... def get_range(self) -> tuple[int, int, int]: ... def get_signal_val_binstr(self) -> str: ... def get_signal_val_long(self) -> int: ... def get_signal_val_real(self) -> float: ... def get_signal_val_str(self) -> bytes: ... def get_type(self) -> int: ... def get_type_string(self) -> str: ... def iterate(self, mode: int) -> gpi_iterator_hdl: ... def set_signal_val_binstr(self, action: int, value: str) -> None: ... def set_signal_val_int(self, action: int, value: int) -> None: ... def set_signal_val_real(self, action: int, value: float) -> None: ... def set_signal_val_str(self, action: int, value: bytes) -> None: ... def __eq__(self, other: object) -> bool: ... def __ne__(self, other: object) -> bool: ... def __hash__(self) -> int: ... def get_precision() -> int: ... def get_root_handle(name: str | None) -> gpi_sim_hdl | None: ... def get_sim_time() -> tuple[int, int]: ... def get_simulator_product() -> str: ... def get_simulator_version() -> str: ... def is_running() -> bool: ... def set_gpi_log_level(level: int) -> None: ... def package_iterate() -> gpi_iterator_hdl: ... def register_nextstep_callback(func: Callable[..., Any], *args: Any) -> gpi_cb_hdl: ... def register_readonly_callback(func: Callable[..., Any], *args: Any) -> gpi_cb_hdl: ... def register_rwsynch_callback(func: Callable[..., Any], *args: Any) -> gpi_cb_hdl: ... def register_timed_callback( time: int, func: Callable[..., Any], *args: Any ) -> gpi_cb_hdl: ... def register_value_change_callback( signal: gpi_sim_hdl, func: Callable[..., Any], edge: int, *args: Any ) -> gpi_cb_hdl: ... def stop_simulator() -> None: ... class cpp_clock: def __init__(self, signal: gpi_sim_hdl) -> None: ... def start( self, period_steps: int, high_steps: int, start_high: bool, set_action: int ) -> None: ... def stop(self) -> None: ... def clock_create(hdl: gpi_sim_hdl) -> cpp_clock: ... def initialize_logger( log_func: Callable[[Logger, int, str, int, str, str], None], get_logger: Callable[[str], Logger], ) -> None: ... def set_sim_event_callback(sim_event_callback: Callable[[str], None]) -> None: ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/task.py0000644000175100017510000005000615106067236016014 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import collections.abc import inspect import logging import traceback from asyncio import CancelledError, InvalidStateError from bdb import BdbQuit from enum import auto from types import SimpleNamespace from typing import ( TYPE_CHECKING, Callable, Coroutine, Generator, Generic, List, Optional, TypeVar, Union, cast, ) import cocotb from cocotb._base_triggers import Trigger from cocotb._bridge import bridge, resume from cocotb._deprecation import deprecated from cocotb._outcomes import Error, Outcome, Value from cocotb._py_compat import Self, cached_property from cocotb._utils import DocEnum, extract_coro_stack, remove_traceback_frames if TYPE_CHECKING: from types import CoroutineType __all__ = ( "Join", "Task", "TaskComplete", "bridge", "current_task", "resume", ) # Set __module__ on re-exports bridge.__module__ = __name__ resume.__module__ = __name__ #: Task result type ResultType = TypeVar("ResultType") class _TaskState(DocEnum): """State of a Task.""" UNSTARTED = (auto(), "Task created, but never run and not scheduled") SCHEDULED = (auto(), "Task queued to run soon") PENDING = (auto(), "Task waiting for Trigger to fire") RUNNING = (auto(), "Task is currently running") FINISHED = (auto(), "Task has finished with a value or Exception") CANCELLED = (auto(), "Task was cancelled before it finished") class Task(Generic[ResultType]): """Concurrently executing task. This class is not intended for users to directly instantiate. Use :func:`cocotb.create_task` to create a Task object or :func:`cocotb.start_soon` to create a Task and schedule it to run. .. versionchanged:: 1.8 Moved to the ``cocotb.task`` module. .. versionchanged:: 2.0 The ``retval``, ``_finished``, and ``__bool__`` methods were removed. Use :meth:`result`, :meth:`done`, and :meth:`done` methods instead, respectively. """ _id_count = 0 # used by the scheduler for debug def __init__( self, inst: Coroutine[Trigger, None, ResultType], *, name: Optional[str] = None ) -> None: self._native_coroutine: bool if inspect.iscoroutinefunction(inst): raise TypeError( f"Coroutine function {inst} should be called prior to being scheduled." ) elif inspect.isasyncgen(inst): raise TypeError( f"{inst.__qualname__} is an async generator, not a coroutine. " "You likely used the yield keyword instead of await." ) elif inspect.iscoroutine(inst): self._native_coroutine = True elif isinstance(inst, collections.abc.Coroutine): self._native_coroutine = False else: raise TypeError(f"{inst} isn't a valid coroutine!") self._coro = inst self._state: _TaskState = _TaskState.UNSTARTED self._outcome: Union[Outcome[ResultType], None] = None self._trigger: Union[Trigger, None] = None self._done_callbacks: List[Callable[[Task[ResultType]], None]] = [] self._cancelled_msg: Union[str, None] = None self._must_cancel: bool = False self._locals = SimpleNamespace() self._task_id = self._id_count type(self)._id_count += 1 self._name = f"Task {self._task_id}" if name is None else name @property def locals(self) -> SimpleNamespace: '''Task-local variables. A modifiable namespace where any user-defined variables can be added. Use :func:`~cocotb.task.current_task` to access the current Task's locals. .. code-block:: python def get_rng() -> random.Random: """Get the random number generator for the current Task.""" try: return current_task().locals.rng except AttributeError: rng = random.Random() current_task().locals.rng = rng return rng # Use Task-local RNG to drive a signal rng = get_rng() for _ in range(10): await drive(rng.randint(0, 100)) .. versionadded:: 2.0 ''' return self._locals def get_name(self) -> str: """Return the name of the :class:`!Task`. If not set using :meth:`set_name` or passed during construction, a reasonable default name is generated. """ return self._name def set_name(self, value: object) -> None: """Set the name of the :class:`!Task`. Args: value: Any object which can be converted to a :class:`str` to use as the name. """ self._name = str(value) @cached_property def _cancelled_error(self) -> CancelledError: if self._cancelled_msg is None: return CancelledError() else: return CancelledError(self._cancelled_msg) @cached_property def _log(self) -> logging.Logger: coro_name: str if self._native_coroutine: coro_name = self._coro.__qualname__ else: coro_name = type(self._coro).__qualname__ return logging.getLogger(f"cocotb.{self._name}.{coro_name}") def __str__(self) -> str: # TODO Do we really need this? return f"<{self._name}>" def _get_coro_stack(self) -> traceback.StackSummary: """Get the coroutine callstack of this Task. Assumes :attr:`_coro` is a native Python coroutine object. Raises: TypeError: If :attr:`_coro` is not a native Python coroutine object. """ if not self._native_coroutine: raise TypeError( "Task._get_coro_stack() can only be called on native Python coroutines." ) coro_stack = extract_coro_stack( cast("CoroutineType[Trigger, None, ResultType]", self._coro) ) # Remove Trigger.__await__() from the stack, as it's not really useful if len(coro_stack) > 0 and coro_stack[-1].name == "__await__": coro_stack.pop() return coro_stack def __repr__(self) -> str: if self._native_coroutine: coro_stack = self._get_coro_stack() try: coro_name = coro_stack[-1].name # coro_stack may be empty if: # - exhausted generator # - finished coroutine except IndexError: try: coro_name = self._coro.__name__ except AttributeError: coro_name = type(self._coro).__name__ else: coro_name = type(self._coro).__name__ if self._state is _TaskState.RUNNING: return f"<{self._name} running coro={coro_name}()>" elif self._state is _TaskState.FINISHED: return f"<{self._name} finished coro={coro_name}() outcome={self._outcome}>" elif self._state is _TaskState.PENDING: return f"<{self._name} pending coro={coro_name}() trigger={self._trigger}>" elif self._state is _TaskState.SCHEDULED: return f"<{self._name} scheduled coro={coro_name}()>" elif self._state is _TaskState.UNSTARTED: return f"<{self._name} created coro={coro_name}()>" elif self._state is _TaskState.CANCELLED: return f"<{self._name} cancelled coro={coro_name} with={self._cancelled_error} outcome={self._outcome}" else: raise RuntimeError("Task in unknown state") def _set_outcome( self, result: Outcome[ResultType], state: _TaskState = _TaskState.FINISHED ) -> None: self._outcome = result self._state = state # Run done callbacks. for callback in self._done_callbacks: callback(self) # Wake up waiting Tasks. cocotb._scheduler_inst._react(self.complete) cocotb._scheduler_inst._react(self._join) def _advance(self, exc: Union[BaseException, None]) -> Union[Trigger, None]: """Resume execution of the Task. Runs until the coroutine ends, raises, or yields a Trigger. Can optionally throw an Exception into the Task. Args: exc: :exc:`BaseException` to throw into the coroutine or nothing. Returns: The object yielded from the coroutine or ``None`` if coroutine finished. """ self._state = _TaskState.RUNNING if self._must_cancel: exc = self._cancelled_error try: if exc is None: trigger = self._coro.send(None) else: trigger = self._coro.throw(exc) except StopIteration as e: outcome = Value(e.value) if self._must_cancel: self._set_outcome( Error( RuntimeError( "Task was cancelled, but exited normally. Did you forget to re-raise the CancelledError?" ) ) ) else: self._set_outcome(outcome) return None except (KeyboardInterrupt, SystemExit, BdbQuit) as e: # Allow these to bubble up to the execution root to fail the sim immediately. # This follows asyncio's behavior. self._set_outcome(Error(remove_traceback_frames(e, ["_advance"]))) raise except CancelledError as e: self._set_outcome( Error(remove_traceback_frames(e, ["_advance"])), _TaskState.CANCELLED ) return None except BaseException as e: self._set_outcome(Error(remove_traceback_frames(e, ["_advance"]))) return None else: if self._must_cancel: self._set_outcome( Error( RuntimeError( "Task was cancelled, but continued running. Did you forget to re-raise the CancelledError?" ) ) ) return None else: return trigger def _schedule_resume(self, exc: Optional[BaseException] = None) -> None: cocotb._scheduler_inst._unschedule(self) cocotb._scheduler_inst._schedule_task_internal(self, exc) @deprecated("`task.kill()` is deprecated in favor of `task.cancel()`") def kill(self) -> None: """Kill a coroutine.""" if self._state in (_TaskState.PENDING, _TaskState.SCHEDULED): # Unschedule if scheduled and unprime triggers if pending. cocotb._scheduler_inst._unschedule(self) elif self._state is _TaskState.UNSTARTED: # Don't need to unschedule. pass elif self._state in (_TaskState.FINISHED, _TaskState.CANCELLED): # Do nothing if already done. return else: raise RuntimeError("Can't kill currently running Task") # Close native coroutines if they were never resumed to prevent ResourceWarnings. if ( inspect.iscoroutine(self._coro) and inspect.getcoroutinestate(self._coro) == "CORO_CREATED" ): self._coro.close() self._set_outcome(Value(None)) # type: ignore # `kill()` sets the result to None regardless of the ResultType @cached_property def complete(self) -> "TaskComplete[ResultType]": r"""Trigger which fires when the Task completes. Unlike :meth:`join`, this Trigger does not return the result of the Task when :keyword:`await`\ ed. .. code-block:: python async def coro_inner(): await Timer(1, unit="ns") raise ValueError("Oops") task = cocotb.start_soon(coro_inner()) await task.complete # no exception raised here assert task.exception() == ValueError("Oops") """ return TaskComplete._make(self) @deprecated( "Using `task` directly is preferred to `task.join()` in all situations where the latter could be used." ) def join(self) -> "Join[ResultType]": r"""Block until the Task completes and return the result. Equivalent to calling :class:`Join(self) `. .. code-block:: python async def coro_inner(): await Timer(1, unit="ns") return "Hello world" task = cocotb.start_soon(coro_inner()) result = await task.join() assert result == "Hello world" Returns: Object that can be :keyword:`await`\ ed or passed into :class:`~cocotb.triggers.First` or :class:`~cocotb.triggers.Combine`; the result of which will be the result of the Task. .. deprecated:: 2.0 Using ``task`` directly is preferred to ``task.join()`` in all situations where the latter could be used. """ return self._join @cached_property def _join(self) -> "Join[ResultType]": return Join._make(self) def cancel(self, msg: Optional[str] = None) -> bool: """Cancel a Task's further execution. When a Task is cancelled, a :exc:`asyncio.CancelledError` is thrown into the Task. Returns: ``True`` if the Task was cancelled; ``False`` otherwise. """ if self._state in {_TaskState.PENDING, _TaskState.SCHEDULED}: self._schedule_resume() elif self._state in (_TaskState.UNSTARTED, _TaskState.RUNNING): # (Re)schedule to throw CancelledError cocotb._scheduler_inst._schedule_task_internal(self) else: # Already finished or cancelled return False self._cancelled_msg = msg self._must_cancel = True return True def _cancel_now(self, msg: Optional[str] = None) -> bool: """Like cancel(), but throws CancelledError into the Task and puts it into a "done" state immediately. Not safe to be called from a running Task. Only from done callbacks or scheduler or Task internals. """ if self.done(): return False self._cancelled_msg = msg self._must_cancel = True if self._state is _TaskState.UNSTARTED: # Must fail immediately as we can't start a coroutine with an exception. self._set_outcome(Error(self._cancelled_error), _TaskState.CANCELLED) else: # Unprime and unschedule the Task so it's out of the scheduler. cocotb._scheduler_inst._unschedule(self) # Force CancelledError to be thrown immediately. self._advance(None) return True def cancelled(self) -> bool: """Return ``True`` if the Task was cancelled.""" return self._state is _TaskState.CANCELLED def done(self) -> bool: """Return ``True`` if the Task has finished executing.""" return self._state in (_TaskState.FINISHED, _TaskState.CANCELLED) def result(self) -> ResultType: """Return the result of the Task. If the Task ran to completion, the result is returned. If the Task failed with an exception, the exception is re-raised. If the Task was cancelled, the :exc:`asyncio.CancelledError` is re-raised. If the coroutine is not yet complete, an :exc:`asyncio.InvalidStateError` is raised. """ if self._state is _TaskState.CANCELLED: raise self._cancelled_error elif self._state is _TaskState.FINISHED: return cast("Outcome[ResultType]", self._outcome).get() else: raise InvalidStateError("result is not yet available") def exception(self) -> Optional[BaseException]: """Return the exception of the Task. If the Task ran to completion, ``None`` is returned. If the Task failed with an exception, the exception is returned. If the Task was cancelled, the :exc:`asyncio.CancelledError` is re-raised. If the coroutine is not yet complete, an :exc:`asyncio.InvalidStateError` is raised. """ if self._state is _TaskState.CANCELLED: raise self._cancelled_error elif self._state is _TaskState.FINISHED: if isinstance(self._outcome, Error): return self._outcome.error else: return None else: raise InvalidStateError("result is not yet available") def _add_done_callback( self, callback: Callable[["Task[ResultType]"], None] ) -> None: """Add *callback* to the list of callbacks to be run once the Task becomes "done". Args: callback: The callback to run once "done". .. note:: If the task is already done, calling this function will call the callback immediately. """ if self.done(): callback(self) self._done_callbacks.append(callback) def __await__(self) -> Generator[Trigger, None, ResultType]: if self._state is _TaskState.UNSTARTED: cocotb._scheduler_inst._schedule_task_internal(self) yield self.complete elif not self.done(): yield self.complete return self.result() def current_task() -> Task[object]: """Return the currently running Task. Raises: RuntimeError: If no Task is running. .. versionadded:: 2.0 """ task = cocotb._scheduler_inst._current_task if task is None: raise RuntimeError("No Task is currently running") return task class TaskComplete(Trigger, Generic[ResultType]): r"""Fires when a :class:`~cocotb.task.Task` completes. Unlike :class:`~cocotb.task.Join`, this Trigger does not return the result of the Task when :keyword:`await`\ ed. See :attr:`.Task.complete` for more information. .. warning:: This class cannot be instantiated in the normal way. You must use :attr:`.Task.complete`. .. versionadded:: 2.0 """ _task: Task[ResultType] def __new__(cls, task: Task[ResultType]) -> "TaskComplete[ResultType]": raise NotImplementedError( "TaskComplete cannot be instantiated in this way. Use the `task.complete` attribute." ) @classmethod def _make(cls, task: Task[ResultType]) -> "Self": self = super().__new__(cls) super().__init__(self) self._task = task return self def _prime(self, callback: Callable[["Self"], None]) -> None: if self._task.done(): callback(self) else: super()._prime(callback) def __repr__(self) -> str: return f"{type(self).__qualname__}({self._task!s})" @property def task(self) -> Task[ResultType]: """The :class:`.Task` associated with this completion event.""" return self._task class Join(TaskComplete[ResultType]): r"""Fires when a :class:`~cocotb.task.Task` completes and returns the Task's result. Equivalent to calling :meth:`task.join() `. .. code-block:: python async def coro_inner(): await Timer(1, unit="ns") return "Hello world" task = cocotb.start_soon(coro_inner()) result = await Join(task) assert result == "Hello world" Args: task: The Task upon which to wait for completion. Returns: Object that can be :keyword:`await`\ ed or passed into :class:`~cocotb.triggers.First` or :class:`~cocotb.triggers.Combine`; the result of which will be the result of the Task. .. deprecated:: 2.0 Using ``task`` directly is preferred to ``Join(task)`` in all situations where the latter could be used. """ @deprecated( "Using `task` directly is preferred to `Join(task)` in all situations where the latter could be used." ) def __new__(cls, task: Task[ResultType]) -> "Join[ResultType]": return task._join def __init__(self, task: Task[ResultType]) -> None: pass def __await__(self) -> Generator["Self", None, ResultType]: # type: ignore[override] yield self return self._task.result() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/triggers.py0000644000175100017510000000254715106067236016707 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import warnings from cocotb._base_triggers import Event, Lock, NullTrigger, Trigger from cocotb._extended_awaitables import ( ClockCycles, Combine, First, SimTimeoutError, Waitable, with_timeout, ) from cocotb._gpi_triggers import ( Edge, FallingEdge, GPITrigger, NextTimeStep, ReadOnly, ReadWrite, RisingEdge, Timer, ValueChange, current_gpi_trigger, ) __all__ = ( "ClockCycles", "Combine", "Edge", "Event", "FallingEdge", "First", "GPITrigger", "Lock", "NextTimeStep", "NullTrigger", "ReadOnly", "ReadWrite", "RisingEdge", "SimTimeoutError", "Timer", "Trigger", "ValueChange", "Waitable", "current_gpi_trigger", "with_timeout", ) # Set __module__ on re-exports for name in __all__: obj = globals()[name] obj.__module__ = __name__ def __getattr__(name: str) -> object: if name == "Join": warnings.warn( "Join has been moved to `cocotb.task`.", DeprecationWarning, stacklevel=2, ) from cocotb.task import Join # noqa: PLC0415 return Join raise AttributeError(f"module {__name__!r} has no attribute {name!r}") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3527026 cocotb-2.0.1/src/cocotb/types/0000755000175100017510000000000015106070715015637 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/types/__init__.py0000644000175100017510000000163615106067236017762 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause from ._abstract_array import AbstractArray, AbstractMutableArray from ._array import Array from ._indexing import IndexingChangedWarning from ._logic import Bit, Logic from ._logic_array import LogicArray from ._range import Range # isort: split # These are imports for doctests in the submodules. Since we fix up the `__module__` # attribute, `--doctest-modules` thinks this is the module the types were defined in # and will evaluate this module first before running tests. from typing import Tuple # noqa: F401 __all__ = ( "AbstractArray", "AbstractMutableArray", "Array", "Bit", "IndexingChangedWarning", "Logic", "LogicArray", "Range", ) # Set __module__ on re-exports for name in __all__: obj = globals()[name] obj.__module__ = __name__ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/types/_abstract_array.py0000644000175100017510000000750415106067236021363 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause from abc import abstractmethod from typing import Generic, Iterable, Iterator, Optional, TypeVar, Union, overload from cocotb.types._range import Range T_co = TypeVar("T_co", covariant=True) T = TypeVar("T") class AbstractArray(Generic[T_co]): r"""Abstract base class for non-mutating Array-like collections. Arrays are similar to :class:`~collections.abc.Sequence`\ s, but their size cannot change after creation and they support arbitrary indexing schemes. Abstract methods ^^^^^^^^^^^^^^^^ * :attr:`range` * :meth:`!__getitem__` Mixin methods ^^^^^^^^^^^^^ * :attr:`left`, :attr:`right`, and :attr:`direction` * :meth:`!__len__` * :meth:`!__iter__` and :meth:`!__reversed__` * :meth:`!__contains__` * :meth:`index` and :meth:`count` """ @property def left(self) -> int: """Leftmost index of the array.""" return self.range.left @property def direction(self) -> str: """``"to"`` if indexes are ascending, ``"downto"`` otherwise.""" return self.range.direction @property def right(self) -> int: """Rightmost index of the array.""" return self.range.right @property @abstractmethod def range(self) -> Range: """:class:`Range` of the indexes of the array.""" @range.setter @abstractmethod def range(self, new_range: Range) -> None: """Set a new indexing scheme on the array. Must be the same size. """ def __len__(self) -> int: return len(self.range) def __iter__(self) -> Iterator[T_co]: for i in self.range: yield self[i] def __reversed__(self) -> Iterator[T_co]: for i in reversed(self.range): yield self[i] def __contains__(self, item: object) -> bool: return any(v == item for v in self) @overload def __getitem__(self, item: int) -> T_co: ... @overload def __getitem__(self, item: slice) -> "AbstractArray[T_co]": ... @abstractmethod def __getitem__( self, item: Union[int, slice] ) -> Union[T_co, "AbstractArray[T_co]"]: ... def index( self, value: object, start: Optional[int] = None, stop: Optional[int] = None, ) -> int: """Find first occurrence of value. Args: value: Value to search for. start: Index to start search at. stop: Index to stop search at. Returns: Index of first occurrence of *value*. Raises: ValueError: If the value is not present. """ if start is None: start = self.left if stop is None: stop = self.right for i in Range(start, self.direction, stop): if self[i] == value: return i raise IndexError(f"{value!r} not in array") def count(self, value: object) -> int: """Return number of occurrences of value. Args: value: Value to search for. Returns: Number of occurrences of *value*. """ count: int = 0 for v in self: if v == value: count += 1 return count class AbstractMutableArray(AbstractArray[T]): """Abstract base class for mutating Array-like collections. See :class:`.AbstractArray` for more details. Additional abstract methods: * :meth:`!__setitem__` """ @overload def __setitem__(self, item: int, value: T) -> None: ... @overload def __setitem__(self, item: slice, value: Iterable[T]) -> None: ... @abstractmethod def __setitem__( self, item: Union[int, slice], value: Union[T, Iterable[T]] ) -> None: ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/types/_array.py0000644000175100017510000002534015106067236017476 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import copy import warnings from typing import Any, Dict, Iterable, Iterator, List, TypeVar, Union, cast, overload from cocotb.types._abstract_array import AbstractMutableArray from cocotb.types._indexing import IndexingChangedWarning from cocotb.types._range import Range T = TypeVar("T") class Array(AbstractMutableArray[T]): r"""Fixed-size, arbitrarily-indexed, homogeneous collection type. Arrays are similar to, but different from Python :class:`list`\ s. An array can store values of any type or values of multiple types at a time, just like a :class:`!list`. Array constructor values can be any Iterable. .. code-block:: pycon3 >>> Array([1, False, "example", None]) Array([1, False, 'example', None], Range(0, 'to', 3)) >>> Array("Hello!") Array(['H', 'e', 'l', 'l', 'o', '!'], Range(0, 'to', 5)) Unlike :class:`!list`\ s, an array's size cannot change. This means they do not support methods like :meth:`~list.append` or :meth:`~list.insert`. The indexes of an Array can start or end at any integer value, they are not limited to 0-based indexing. Indexing schemes are selected using :class:`Range` objects. If *range* is not given, the range ``Range(0, "to", len(value)-1)`` is used. If an :class:`int` is passed for *range*, the range ``Range(0, "to", range-1)`` is used. .. code-block:: pycon3 >>> a = Array([0, 1, 2, 3], Range(-1, "downto", -4)) >>> a[-1] 0 >>> a[-4] 3 Arrays can also have 0 length using "null" :class:`Range`\ s. .. code-block:: pycon3 >>> Array([], Range(1, "to", 0)) # 1 to 0 is a null Range Array([], Range(1, 'to', 0)) Indexing and slicing is very similar to :class:`!list`\ s, but it uses the indexing scheme specified with the *range*. Unlike :class:`!list`, slicing uses an inclusive right bound, which is common in HDLs. But like :class:`!list`, if a start or stop index is not specified in the slice, it is inferred as the start or end of the array. Slicing an Array returns a new :class:`~cocotb.types.Array` object, whose bounds are the slice indexes. .. code-block:: pycon3 >>> a = Array("1234abcd") >>> a[7] 'd' >>> a[2:5] Array(['3', '4', 'a', 'b'], Range(2, 'to', 5)) >>> a[2:5] = reversed(a[2:5]) >>> "".join(a) '12ba43cd' >>> b = Array("1234", Range(0, -3)) >>> b[-2] '3' >>> b[-1:] Array(['2', '3', '4'], Range(-1, 'downto', -3)) >>> b[:] = reversed(b) >>> b Array(['4', '3', '2', '1'], Range(0, 'downto', -3)) .. warning:: Arrays behave differently in certain situations than Python's built-in sequence types (:class:`list`, :class:`tuple`, etc.). - Arrays are not necessarily 0-based and slices use inclusive right bounds, so many functions that work on Python sequences by index (like :mod:`bisect`) may not work on arrays. - Slice indexes must be specified in the same direction as the array and do not support specifying a "step". - When setting a slice, the new value must be an iterable of the same size as the slice. - Negative indexes are *not* treated as an offset from the end of the array, but are treated literally. Arrays are equal to other arrays of the same length with the same values (structural equality). Bounds do not matter for equality. .. code-block:: pycon3 >>> a = Array([1, 1, 2, 3, 5], Range(4, "downto", 0)) >>> b = Array([1, 1, 2, 3, 5], Range(-2, "to", 2)) >>> a == b True You can change the bounds of an array by setting the :attr:`range` to a new value. The new bounds must be the same length of the array. .. code-block:: pycon3 >>> a = Array("1234") >>> a.range Range(0, 'to', 3) >>> a.range = Range(3, "downto", 0) >>> a.range Range(3, 'downto', 0) Arrays support many of the methods and semantics defined by :class:`collections.abc.Sequence`. .. code-block:: pycon3 >>> a = Array("stuff", Range(2, "downto", -2)) >>> len(a) 5 >>> "t" in a True >>> a.index("u") 0 >>> for c in a: ... print(c) s t u f f Args: value: Initial value for the Array. range: The indexing scheme of the Array. Raises: ValueError: When argument values cannot be used to construct an Array. TypeError: When invalid argument types are used. """ __slots__ = ("_value", "_range", "_warn_indexing") def __init__( self, value: Iterable[T], range: Union[Range, int, None] = None ) -> None: self._warn_indexing = False self._value = list(value) if range is None: self._range = Range(0, "to", len(self._value) - 1) else: if isinstance(range, int): self._range = Range(0, "to", range - 1) elif isinstance(range, Range): self._range = range else: raise TypeError( f"Expected Range or int for parameter 'range', not {type(range).__qualname__}" ) if len(self._value) != len(self._range): raise ValueError( f"Value of length {len(self._value)!r} does not fit in {self._range!r}" ) @classmethod def _from_handle( cls, value: List[T], range: Range, warn_indexing: bool ) -> "Array[T]": self = cls.__new__(cls) self._warn_indexing = warn_indexing self._value = value self._range = range return self @property def range(self) -> Range: """:class:`Range` of the indexes of the array.""" return self._range @range.setter def range(self, new_range: Range) -> None: """Sets a new indexing scheme on the array, must be the same size""" if not isinstance(new_range, Range): raise TypeError("range argument must be of type 'Range'") if len(new_range) != len(self): raise ValueError( f"{new_range!r} not the same length as old range ({self._range!r})." ) self._range = new_range def __iter__(self) -> Iterator[T]: return iter(self._value) def __reversed__(self) -> Iterator[T]: return reversed(self._value) def __contains__(self, item: object) -> bool: return item in self._value def __eq__(self, other: object) -> bool: if isinstance(other, Array): return self._value == other._value elif isinstance(other, list): return self._value == other elif isinstance(other, tuple): return tuple(self._value) == other else: return NotImplemented @overload def __getitem__(self, item: int) -> T: ... @overload def __getitem__(self, item: slice) -> "Array[T]": ... def __getitem__(self, item: Union[int, slice]) -> Union[T, "Array[T]"]: if isinstance(item, int): if self._warn_indexing: warnings.warn( f"Update index {item} to {self.range[item]}", IndexingChangedWarning, stacklevel=2, ) idx = self._translate_index(item) return self._value[idx] elif isinstance(item, slice): if self._warn_indexing: start = item.start if item.start is not None else 0 stop = item.stop if item.stop is not None else len(self) - 1 warnings.warn( f"Update slice {start}:{stop} to {self.range[start]}:{self.range[stop]}", IndexingChangedWarning, stacklevel=2, ) start = item.start if item.start is not None else self.left stop = item.stop if item.stop is not None else self.right if item.step is not None: raise IndexError("do not specify step") start_i = self._translate_index(start) stop_i = self._translate_index(stop) if start_i > stop_i: raise IndexError( f"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]" ) value = self._value[start_i : stop_i + 1] range = Range(start, self.direction, stop) return Array(value=value, range=range) raise TypeError(f"indexes must be ints or slices, not {type(item).__name__}") @overload def __setitem__(self, item: int, value: T) -> None: ... @overload def __setitem__(self, item: slice, value: Iterable[T]) -> None: ... def __setitem__( self, item: Union[int, slice], value: Union[T, Iterable[T]] ) -> None: if isinstance(item, int): idx = self._translate_index(item) self._value[idx] = cast("T", value) elif isinstance(item, slice): start = item.start if item.start is not None else self.left stop = item.stop if item.stop is not None else self.right if item.step is not None: raise IndexError("do not specify step") start_i = self._translate_index(start) stop_i = self._translate_index(stop) if start_i > stop_i: raise IndexError( f"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]" ) value = list(cast("Iterable[T]", value)) if len(value) != (stop_i - start_i + 1): raise ValueError( f"value of length {len(value)!r} will not fit in slice [{start}:{stop}]" ) self._value[start_i : stop_i + 1] = value else: raise TypeError( f"indexes must be ints or slices, not {type(item).__name__}" ) def __repr__(self) -> str: return f"{type(self).__name__}({self._value!r}, {self._range!r})" def _translate_index(self, item: int) -> int: try: return self._range.index(item) except ValueError: raise IndexError(f"index {item} out of range") from None def __copy__(self) -> "Array": return Array(self._value, self._range) def __deepcopy__(self, memo: Dict[int, Any]) -> "Array": res = Array.__new__(Array) res._value = copy.deepcopy(self._value, memo=memo) res._range = copy.deepcopy(self._range, memo=memo) res._warn_indexing = self._warn_indexing return res ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/types/_indexing.py0000644000175100017510000000101615106067236020157 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import os from cocotb.types._range import Range do_indexing_changed_warning = os.environ.get("COCOTB_INDEXING_CHANGED_WARNING") def indexing_changed(range: Range) -> bool: return not (range.left == 0 and range.direction == "to") class IndexingChangedWarning(UserWarning): """Warning issued when a value is indexed in a way that is different between cocotb 1.x and 2.x.""" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/types/_logic.py0000644000175100017510000002543015106067236017455 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause from functools import lru_cache from typing import ( Dict, Union, ) from cocotb._py_compat import Self, TypeAlias from cocotb.types._resolve import RESOLVE_X, ResolverLiteral, get_str_resolver LogicLiteralT: TypeAlias = Union[str, int, bool] LogicConstructibleT: TypeAlias = Union[LogicLiteralT, "Logic"] _U = 0 _X = 1 _0 = 2 _1 = 3 _Z = 4 _W = 5 _L = 6 _H = 7 _D = 8 _literal_repr: Dict[LogicLiteralT, int] = { # unassigned "U": _U, "u": _U, # unknown "X": _X, "x": _X, # 0 0: _0, # Also `False` "0": _0, # 1 1: _1, # Also `True` "1": _1, # high impedance "Z": _Z, "z": _Z, # weak unknown "W": _W, "w": _W, # weak 0 "L": _L, "l": _L, # weak 1 "H": _H, "h": _H, # don't care "-": _D, } class Logic: r"""9-state digital signal value type. This type is modeled after VHDL's ``std_ulogic`` type. It can represent the values (``U``, ``X``, ``0``, ``1``, ``Z``, ``W``, ``L``, ``H``, ``-``). (System)Verilog's 4-state ``logic`` type is a subset which only utilizes the ``X``, ``0``, ``1``, and ``Z`` values. :class:`!Logic` can be converted to and from :class:`int`, :class:`str`, :class:`bool` and :class:`Bit`. String literals include ``"U"``, ``"X"``, ``"0"``, ``"1"``, ``"Z"``, ``"W"``, ``"L"``, ``"H"``, ``"-"``, and their lowercase values. .. code-block:: pycon3 >>> Logic("X") Logic('X') >>> Logic(True) Logic('1') >>> Logic(1) Logic('1') >>> str(Logic("Z")) 'Z' >>> bool(Logic(0)) False >>> int(Logic(1)) 1 .. note:: The :class:`int` and :class:`bool` conversions will raise :exc:`ValueError` if the value is not ``0``, ``1``, ``L``, or ``H``. :class:`Logic` supports the common logic operations ``&``, ``|``, ``^``, and ``~``. .. code-block:: pycon3 >>> def full_adder(a: Logic, b: Logic, carry: Logic) -> Tuple[Logic, Logic]: ... res = a ^ b ^ carry ... carry_out = (a & b) | (b & carry) | (a & carry) ... return res, carry_out >>> full_adder(a=Logic("0"), b=Logic("1"), carry=Logic("1")) (Logic('0'), Logic('1')) Args: value: value to construct into a :class:`!Logic`. Raises: ValueError: If the value if of the correct type, but cannot be constructed into a :class:`!Logic`. TypeError: If the value is of a type that can't be constructed into a :class:`!Logic`. """ _values = {_U, _X, _0, _1, _Z, _W, _L, _H, _D} _repr: int __slots__ = ("_repr",) @classmethod @lru_cache(maxsize=None) def _singleton(cls, _repr: int) -> Self: """Return the Logic object associated with the repr, enforcing singleton.""" self = object.__new__(cls) self._repr = _repr return self def __new__( cls, value: LogicConstructibleT, ) -> Self: if isinstance(value, Logic): _repr = value._repr elif isinstance(value, (str, int)): try: _repr = _literal_repr[value] except KeyError: raise ValueError( f"{value!r} is not convertible to {cls.__qualname__}" ) from None else: raise TypeError( f"Expected str, bool, or int, not {type(value).__qualname__}" ) if _repr not in cls._values: raise ValueError(f"{value!r} is not a valid {cls.__qualname__}") return cls._singleton(_repr) def __and__(self, other: Self) -> Self: if not isinstance(other, type(self)): return NotImplemented return type(self)( ( # ----------------------------------------------------- # U X 0 1 Z W L H - | | # ----------------------------------------------------- ("U", "U", "0", "U", "U", "U", "0", "U", "U"), # | U | ("U", "X", "0", "X", "X", "X", "0", "X", "X"), # | X | ("0", "0", "0", "0", "0", "0", "0", "0", "0"), # | 0 | ("U", "X", "0", "1", "X", "X", "0", "1", "X"), # | 1 | ("U", "X", "0", "X", "X", "X", "0", "X", "X"), # | Z | ("U", "X", "0", "X", "X", "X", "0", "X", "X"), # | W | ("0", "0", "0", "0", "0", "0", "0", "0", "0"), # | L | ("U", "X", "0", "1", "X", "X", "0", "1", "X"), # | H | ("U", "X", "0", "X", "X", "X", "0", "X", "X"), # | - | )[self._repr][other._repr] ) def __rand__(self, other: Self) -> Self: return self & other def __or__(self, other: Self) -> Self: if not isinstance(other, type(self)): return NotImplemented return type(self)( ( # ----------------------------------------------------- # U X 0 1 Z W L H - | | # ----------------------------------------------------- ("U", "U", "U", "1", "U", "U", "U", "1", "U"), # | U | ("U", "X", "X", "1", "X", "X", "X", "1", "X"), # | X | ("U", "X", "0", "1", "X", "X", "0", "1", "X"), # | 0 | ("1", "1", "1", "1", "1", "1", "1", "1", "1"), # | 1 | ("U", "X", "X", "1", "X", "X", "X", "1", "X"), # | Z | ("U", "X", "X", "1", "X", "X", "X", "1", "X"), # | W | ("U", "X", "0", "1", "X", "X", "0", "1", "X"), # | L | ("1", "1", "1", "1", "1", "1", "1", "1", "1"), # | H | ("U", "X", "X", "1", "X", "X", "X", "1", "X"), # | - | )[self._repr][other._repr] ) def __ror__(self, other: Self) -> Self: return self | other def __xor__(self, other: Self) -> Self: if not isinstance(other, type(self)): return NotImplemented return type(self)( ( # ----------------------------------------------------- # U X 0 1 Z W L H - | | # ----------------------------------------------------- ("U", "U", "U", "U", "U", "U", "U", "U", "U"), # | U | ("U", "X", "X", "X", "X", "X", "X", "X", "X"), # | X | ("U", "X", "0", "1", "X", "X", "0", "1", "X"), # | 0 | ("U", "X", "1", "0", "X", "X", "1", "0", "X"), # | 1 | ("U", "X", "X", "X", "X", "X", "X", "X", "X"), # | Z | ("U", "X", "X", "X", "X", "X", "X", "X", "X"), # | W | ("U", "X", "0", "1", "X", "X", "0", "1", "X"), # | L | ("U", "X", "1", "0", "X", "X", "1", "0", "X"), # | H | ("U", "X", "X", "X", "X", "X", "X", "X", "X"), # | - | )[self._repr][other._repr] ) def __rxor__(self, other: Self) -> Self: return self ^ other def __invert__(self) -> Self: return type(self)(("U", "X", "1", "0", "X", "X", "1", "0", "X")[self._repr]) def __eq__(self, other: object) -> bool: if isinstance(other, Logic): return self._repr == other._repr elif isinstance(other, (int, str, bool)): try: other = Logic(other) except ValueError: return False return self == other else: return NotImplemented __hash__: None # type: ignore[assignment] def __repr__(self) -> str: return f"{type(self).__qualname__}({str(self)!r})" def __str__(self) -> str: return ("U", "X", "0", "1", "Z", "W", "L", "H", "-")[self._repr] if RESOLVE_X is None: def __bool__(self) -> bool: if self._repr in (_0, _L): return False elif self._repr in (_1, _H): return True raise ValueError(f"Cannot convert {self!r} to bool") def __int__(self) -> int: if self._repr in (_0, _L): return 0 elif self._repr in (_1, _H): return 1 raise ValueError(f"Cannot convert {self!r} to int") else: def __bool__(self) -> bool: return self._repr in (_1, _H) def __int__(self) -> int: s = str(self) s = RESOLVE_X(s) return int(s, 2) def __index__(self) -> int: return int(self) def resolve(self, resolver: ResolverLiteral) -> Self: """Resolve non-``0``/``1`` values to ``0``/``1``. The possible values of the *resolver* argument are: * ``"weak"``: Weak values are resolved to their strong-valued equivalents. * ``"zeros"``: ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively. Remaining non-``0``/``1`` values are resolved to ``0``. * ``"ones"``: ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively. Remaining non-``0``/``1`` values are resolved to ``1``. * ``"random"``: ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively. Remaining non-``0``/``1`` values are randomly resolved to either ``0`` or ``1``. Args: resolver: How to resolve non-``0``/``1`` values. See possible values above. Returns: The resolved Logic. Raises: ValueError: Invalid *resolver* value. TypeError: Unsupported *value* type. """ return type(self)(get_str_resolver(resolver)(str(self))) def __len__(self) -> int: return 1 @property def is_resolvable(self) -> bool: """``True`` if value is ``0``, ``1``, ``L``, ``H``. .. versionadded:: 2.0 """ return (False, False, True, True, False, False, True, True, False)[self._repr] def __copy__(self) -> "Logic": return self def __deepcopy__(self, memo: Dict[int, object]) -> "Logic": return self class Bit(Logic): """2-state digital signal value type. This is modeled after (System)Verilog's and VHDL's ``bit`` type. It can represent only the values ``0`` and ``1``. It can be converted to and from :class:`int`, :class:`str`, :class:`bool`, or :class:`Logic` values. As a subtype of :class:`!Logic`, it supports all of the same operations and can be used in operations interchangeably with :class:`!Logic`. Args: value: value to construct into a :class:`!Bit`. Raises: ValueError: If the value if of the correct type, but cannot be constructed into a :class:`!Bit`. TypeError: If the value is of a type that can't be constructed into a :class:`!Bit`. """ _values = {_0, _1} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/types/_logic_array.py0000644000175100017510000010132315106067236020647 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import copy import warnings from math import ceil from typing import ( Any, Dict, Iterable, Iterator, List, Union, cast, overload, ) from cocotb._deprecation import deprecated from cocotb._py_compat import Literal, TypeAlias from cocotb.types._abstract_array import AbstractMutableArray from cocotb.types._indexing import IndexingChangedWarning from cocotb.types._logic import Logic, LogicConstructibleT from cocotb.types._range import Range from cocotb.types._resolve import RESOLVE_X, ResolverLiteral, get_str_resolver _resolve_lh_table = str.maketrans({"L": "0", "H": "1"}) _str_literals = frozenset("uUxX01zZwWlLhH-") ByteOrder: TypeAlias = Literal["big", "little"] class LogicArray(AbstractMutableArray[Logic]): r"""Fixed-sized, arbitrarily-indexed, :class:`.Array` of :class:`.Logic`\ s. An :class:`!Array`, where all elements are enforced to be :class:`!Logic`. Additionally, this type supports bit-wise logical operators, conversions to integers and bytes, and ``X`` testing and mapping. :class:`!LogicArray`\ s can be constructed from an iterable of :class:`!Logic`\ s, or values constructible into :class:`!Logic`, like :class:`bool`, :class:`str`, or :class:`int`. Alternatively, they can be constructed from :class:`!str` or :class:`!int` literals. Like :class:`!Array`, if *range* is not given, the range ``Range(len(value)-1, "downto", 0)`` is used; and if an :class:`int` is passed for *range*, the range ``Range(range-1, "downto", 0)`` is used. .. code-block:: pycon3 >>> LogicArray(0b0111, 4) LogicArray('0111', Range(3, 'downto', 0)) >>> LogicArray("01XZ", Range(0, "to", 3)) LogicArray('01XZ', Range(0, 'to', 3)) >>> LogicArray([0, True, "X", Logic("-")]) LogicArray('01X-', Range(3, 'downto', 0)) .. note:: If constructing from an unsigned :class:`!int` literal, *range* `must` be given. :class:`!LogicArray`\ s can be constructed from :class:`int`\ s using :meth:`from_unsigned` or :meth:`from_signed`. .. code-block:: pycon3 >>> LogicArray.from_unsigned(0xA, 4) LogicArray('1010', Range(3, 'downto', 0)) >>> LogicArray.from_signed(-4, Range(0, "to", 3)) # will sign-extend LogicArray('1100', Range(0, 'to', 3)) :class:`!LogicArray`\ s can be constructed from :class:`bytes` or :class:`bytearray` using :meth:`from_bytes`. Use the *byteorder* argument to control endianness. .. code-block:: pycon3 >>> LogicArray.from_bytes(b"1n", byteorder="big") LogicArray('0011000101101110', Range(15, 'downto', 0)) >>> LogicArray.from_bytes(b"1n", byteorder="little") LogicArray('0110111000110001', Range(15, 'downto', 0)) :class:`!LogicArray`\ s support the same :class:`list`-like operations as :class:`!Array`; however, it enforces the condition that all elements must be a :class:`!Logic`. .. code-block:: pycon3 >>> array = LogicArray("1010") >>> array[0] # is indexable Logic('0') >>> array[1:] # is slice-able LogicArray('10', Range(1, 'downto', 0)) >>> Logic("0") in array # is a collection True >>> list(array) # is an iterable [Logic('1'), Logic('0'), Logic('1'), Logic('0')] When setting an element or slice, the *value* is first constructed into a :class:`!Logic`. .. code-block:: pycon3 >>> array = LogicArray("1010") >>> array[3] = "Z" >>> array[3] Logic('Z') >>> array[2:] = ["X", True, 0] >>> array LogicArray('ZX10', Range(3, 'downto', 0)) >>> array[:] = 0b0101 >>> array LogicArray('0101', Range(3, 'downto', 0)) :class:`!LogicArray`\ s can be converted into their :class:`str` or :class:`int` literal values using casts. They can also be used in conditionals. .. code-block:: pycon3 >>> value = LogicArray("1010") >>> str(value) '1010' >>> int(value) 10 >>> if value: ... print("Not 0!") Not 0! .. warning:: The :class:`int` cast, :class:`bool` cast, and use in conditionals assumes the value is entirely ``0``, ``1``, ``L``, or ``H``, and will raise an exception otherwise. The :meth:`to_unsigned`, :meth:`to_signed`, and :meth:`to_bytes` methods can be used to convert the value into an unsigned or signed integer, or bytes, respectively. .. code-block:: pycon3 >>> value = LogicArray("1010") >>> value.to_unsigned() 10 >>> value.to_signed() -6 >>> value.to_bytes(byteorder="big") b'\n' .. warning:: These operations assume the value is entirely ``0``, ``1``, ``L``, or ``H``, and will raise an exception otherwise. You can also convert :class:`!LogicArray`\ s to hexadecimal or binary strings using the built-ins :func:`hex` and :func:`bin`, respectively. .. code-block:: pycon3 >>> value = LogicArray("01111010") >>> hex(value) '0x7a' >>> bin(value) '0b1111010' .. warning:: Using :func:`hex` or :func:`bin` first turns the :class:`!LogicArray` into an :class:`int`. This means the exact length of the :class:`!LogicArray` is lost. It also means that these expressions will raise an exception if the value is not entirely ``0``, ``1``, ``L``, or ``H``. :class:`!LogicArray`\ s also support element-wise logical operations: ``&``, ``|``, ``^``, and ``~``. .. code-block:: pycon3 >>> def big_mux(a: LogicArray, b: LogicArray, sel: Logic) -> LogicArray: ... s = LogicArray([sel] * len(a)) ... return (a & ~s) | (b & s) >>> a = LogicArray("0110") >>> b = LogicArray("1110") >>> sel = Logic("1") # choose second option >>> big_mux(a, b, sel) LogicArray('1110', Range(3, 'downto', 0)) Args: value: Initial value for the :class:`!LogicArray`. range: The indexing scheme of the :class:`!LogicArray`. Raises: TypeError: When invalid argument types are used. ValueError: When *value* will not fit in a :class:`!LogicArray` of the given *range*. """ # These three attribute contain the current value of the array in one or more of # three different implementations. This is done for performance reasons, as certain # implementations are faster for particular operations. # Each implementation can be present, or None if the implementation has not been # computed or has been invalidated by a mutating operation. _value_as_array: Union[List[Logic], None] _value_as_int: Union[int, None] _value_as_str: Union[str, None] _range: Range _warn_indexing: bool __slots__ = ( "_value_as_array", "_value_as_int", "_value_as_str", "_range", "_warn_indexing", ) def __init__( self, value: Union[int, str, Iterable[LogicConstructibleT]], range: Union[Range, int, None] = None, ) -> None: self._value_as_array = None self._value_as_int = None self._value_as_str = None self._warn_indexing = False if isinstance(range, int): range = Range(range - 1, "downto", 0) elif range is not None and not isinstance(range, Range): raise TypeError( f"Expected Range or int for parameter 'range', not {type(range).__qualname__}" ) if isinstance(value, str): if not (set(value) <= _str_literals): raise ValueError("Invalid str literal") self._value_as_str = value.upper() if range is not None: if len(value) != len(range): raise ValueError(f"Length of {value!r} does not match {range!r}") self._range = range else: self._range = Range(len(self._value_as_str) - 1, "downto", 0) elif isinstance(value, int): value = int(value) # force bool to int if value < 0: raise ValueError("Invalid int literal") if range is None: raise TypeError("Missing required arguments: 'range'") bitlen = max(1, int.bit_length(value)) if bitlen > len(range): raise ValueError( f"{value!r} is too large to fit in LogicArray with {range!r}" ) self._value_as_int = value self._range = range elif isinstance(value, LogicArray): array = value._value_as_array self._value_as_array = list(array) if array is not None else None self._value_as_int = value._value_as_int self._value_as_str = value._value_as_str if range is None: self._range = value._range else: if len(range) != len(value): raise ValueError(f"Length of {value!r} does not match {range!r}") self._range = range else: self._value_as_array = [Logic(v) for v in value] if range is not None: if len(self._value_as_array) != len(range): raise ValueError( f"Value of length {len(self._value_as_array)} does not match range: {range!r}" ) self._range = range else: self._range = Range(len(self._value_as_array) - 1, "downto", 0) def _get_array(self) -> List[Logic]: if self._value_as_array is None: # May convert int to str before to converting to array. self._value_as_array = [Logic(v) for v in self._get_str()] return self._value_as_array def _get_str(self) -> str: if self._value_as_str is None: if self._value_as_int is not None: self._value_as_str = format(self._value_as_int, f"0{len(self)}b") else: self._value_as_str = "".join( str(v) for v in cast("List[Logic]", self._value_as_array) ) return self._value_as_str def _get_int(self) -> int: if self._value_as_int is None: # May convert list to str before converting to int. value_as_str = self._get_str() # always resolve L and H to 0 and 1 value_as_str = value_as_str.translate(_resolve_lh_table) try: self._value_as_int = int(value_as_str, 2) except ValueError: if RESOLVE_X is None: raise ValueError( f"Can't convert {type(self).__qualname__} to int: it contains non-0/1 values" ) from None else: value_as_str = RESOLVE_X(value_as_str) return int(value_as_str, 2) return self._value_as_int @classmethod def from_unsigned( cls, value: int, range: Union[Range, int], ) -> "LogicArray": """Construct a :class:`!LogicArray` from an :class:`int` with unsigned representation. The :class:`int` is treated as an arbitrary-length bit vector with unsigned representation where the left-most bit is the most significant bit. This bit vector is then constructed into a :class:`!LogicArray`. Args: value: The integer to convert. range: Indexing scheme for the :class:`!LogicArray`. Returns: A :class:`!LogicArray` equivalent to the *value*. Raises: TypeError: When invalid argument types are used. ValueError: When a :class:`!LogicArray` of the given *range* can't hold the *value*, or *value* is negative. """ if value < 0: raise ValueError("Expected unsigned integer, got negative value") return LogicArray(value, range) @classmethod def from_signed( cls, value: int, range: Union[Range, int], ) -> "LogicArray": """Construct a :class:`!LogicArray` from an :class:`int` with two's complement representation. The :class:`int` is treated as an arbitrary-length bit vector with two's complement representation where the left-most bit is the most significant bit. This bit vector is then constructed into a :class:`!LogicArray`. Args: value: The integer to convert. range: Indexing scheme for the :class:`!LogicArray`. Returns: A :class:`!LogicArray` equivalent to the *value*. Raises: TypeError: When invalid argument types are used. ValueError: When a :class:`!LogicArray` of the given *range* can't hold the *value*. """ if isinstance(range, int): range = Range(range - 1, "downto", 0) elif not isinstance(range, Range): raise TypeError( f"Expected Range or int for parameter 'range', not {type(range).__qualname__}" ) # Prevent null range from blowing up the below code. if len(range) == 0: raise ValueError( f"Signed integer {value!r} will not fit in a LogicArray with bounds: {range!r}" ) limit = 1 << (len(range) - 1) if value < -limit or limit <= value: raise ValueError( f"Signed integer {value!r} will not fit in a LogicArray with bounds: {range!r}" ) value %= 2 * limit return LogicArray(value, range) @classmethod def from_bytes( cls, value: Union[bytes, bytearray], range: Union[Range, int, None] = None, *, byteorder: ByteOrder, ) -> "LogicArray": """Construct a :class:`!LogicArray` from :class:`bytes`. The :class:`bytes` is first converted to an unsigned integer using *byteorder*-endian representation, then is converted to a :class:`!LogicArray` as in :meth:`from_unsigned`. Args: value: The bytes to convert. range: Indexing scheme for the :class:`!LogicArray`. byteorder: The endianness used to construct the intermediate integer, either ``"big"`` or ``"little"``. Returns: A :class:`!LogicArray` equivalent to the *value*. Raises: ValueError: When a :class:`!LogicArray` of the given *range* can't hold the *value*. """ if range is None: range = Range(len(value) * 8 - 1, "downto", 0) else: if isinstance(range, int): range = Range(range - 1, "downto", 0) if len(value) * 8 != len(range): raise ValueError( f"Value of length {len(value)} will not fit in a LogicArray with bounds: {range!r}" ) value_as_int = int.from_bytes(value, byteorder=byteorder, signed=False) return LogicArray(value_as_int, range) @classmethod def _from_handle(cls, value: str, warn_indexing: bool) -> "LogicArray": # Used by cocotb.handle classes to make LogicArray from values gotten from the # simulator which we expect to be well-formed. # Values are required to be uppercase. self = cls.__new__(cls) self._value_as_array = None self._value_as_int = None self._value_as_str = value self._range = Range(len(value) - 1, "downto", 0) self._warn_indexing = warn_indexing return self @property def range(self) -> Range: """:class:`Range` of the indexes of the array.""" return self._range @range.setter def range(self, new_range: Range) -> None: """Set a new indexing scheme on the array. Must be the same size.""" if not isinstance(new_range, Range): raise TypeError("range argument must be of type 'Range'") if len(new_range) != len(self): raise ValueError( f"{new_range!r} not the same length as old range: {self._range!r}" ) self._range = new_range def __iter__(self) -> Iterator[Logic]: return iter(self._get_array()) def __reversed__(self) -> Iterator[Logic]: return reversed(self._get_array()) def __contains__(self, item: object) -> bool: return item in self._get_array() def __eq__( self, other: object, ) -> bool: if isinstance(other, int): if len(self) == 0: # Null arrays don't have a value and thus always compare False. return False try: return self.to_unsigned() == other except ValueError: return False elif isinstance(other, str): return str(self) == other.upper() elif isinstance(other, LogicArray): if len(self) != len(other): return False # Complex, but efficient chain of checking logic. # Avoid conversions if it can help it at first. # Prefers checking against str vs any type since that is going to be the # most common type and also the "middle" type for conversions. # Always converts away from ints to prevent issues with non-0/1 data. if self._value_as_str is not None and other._value_as_str is not None: # (STR, STR) return self._value_as_str == other._value_as_str elif self._value_as_array is not None and other._value_as_array is not None: # (ARRAY, ARRAY) return self._value_as_array == other._value_as_array elif self._value_as_int is not None and other._value_as_int is not None: # (INT, INT) return self._value_as_int == other._value_as_int elif self._value_as_str is not None: # (STR, INT) # (STR, ARRAY) return self._value_as_str == other._get_str() elif other._value_as_str is not None: # (INT, STR) # (ARRAY, STR) return self._get_str() == other._value_as_str elif self._value_as_array is not None: # (ARRAY, INT) return self._value_as_array == other._get_array() else: # (INT, ARRAY) return self._get_array() == other._value_as_array elif isinstance(other, (list, tuple)): try: other = LogicArray(other) except ValueError: return False return self == other else: return NotImplemented @property @deprecated( "`logic_array.binstr` getter is deprecated. Use `str(logic_array)` instead." ) def binstr(self) -> str: """The :class:`!LogicArray`'s value in :class:`str` literal representation. :getter: Return the :class:`!LogicArray`'s value in :class:`str` literal representation. .. deprecated:: 2.0 Use ``str(logic_array)`` instead. :setter: Set the :class:`!LogicArray`'s value using a :class:`str` literal representation. .. deprecated:: 2.0 Use ``logic_array[:] = value`` instead. """ return str(self) @binstr.setter @deprecated( "`logic_array.binstr = value` setter is deprecated. Use `logic_array[:] = value` instead." ) def binstr(self, value: str) -> None: self[:] = value @property def is_resolvable(self) -> bool: """``True`` if all elements are ``0``, ``1``, ``L``, ``H``.""" return all(bit.is_resolvable for bit in self) @property @deprecated( "`logic_array.integer` getter is deprecated. Use `logic_array.to_unsigned()` instead." ) def integer(self) -> int: """The :class:`!LogicArray`'s value as an unsigned :class:`int`. The :class:`!LogicArray` is treated as an arbitrary-length vector of bits with the left-most bit being the most significant bit in the integer value. The bit vector is then interpreted as an integer using unsigned representation. :getter: Return the :class:`!LogicArray`'s value as an unsigned integer. .. deprecated:: 2.0 Use :meth:`logic_array.to_unsigned() ` instead. :setter: Set the :class:`!LogicArray`'s value using an unsigned integer. .. deprecated:: 2.0 Use ``logic_array[:] = value`` instead. """ return self.to_unsigned() @integer.setter @deprecated( "`logic_array.integer = value` setter is deprecated. Use `logic_array[:] = value` instead." ) def integer(self, value: int) -> None: self[:] = value @property @deprecated( "`logic_array.signed_integer` getter is deprecated. Use `logic_array.to_signed()` instead." ) def signed_integer(self) -> int: """The :class:`!LogicArray`'s value as a signed :class:`int`. The :class:`!LogicArray` is treated as an arbitrary-length vector of bits with the left-most bit being the most significant bit in the integer value. The bit vector is then interpreted as an integer using two's complement representation. :getter: Return the :class:`!LogicArray`'s value as a signed integer. .. deprecated:: 2.0 Use :meth:`logic_array.to_signed() ` instead. :setter: Set the :class:`!LogicArray`'s value using a signed integer. .. deprecated:: 2.0 Use ``logic_array[:] = LogicArray.from_signed(value, len(logic_array))`` instead. """ return self.to_signed() @signed_integer.setter @deprecated( "`logic_array.signed_integer = value` setter is deprecated. " "Use `logic_array[:] = LogicArray.from_signed(value, len(logic_array))` instead." ) def signed_integer(self, value: int) -> None: self[:] = LogicArray.from_signed(value, len(self)) @property @deprecated( "`logic_array.buff` getter is deprecated. " 'Use `logic_array.to_bytes(byteorder="big")` instead.' ) def buff(self) -> bytes: """The :class:`!LogicArray`'s value as :class:`bytes`. The object is first converted to an :class:`int` as in :meth:`to_unsigned`. Then the object is converted to :class:`bytes` by converting the resulting integer value as in :meth:`int.to_bytes`. This assumes big-endian byte order and the minimal number of bytes necessary to hold any value of the current object. :getter: Return the :class:`!LogicArray`'s value as :class:`bytes`. .. deprecated:: 2.0 Use :meth:`logic_array.to_bytes(byteorder="big") ` instead. :setter: Set the :class:`!LogicArray`'s value using :class:`bytes`. .. deprecated:: 2.0 Use ``logic_array[:] = LogicArray.from_bytes(value, len(logic_array), byteorder="big")`` instead. """ return self.to_bytes(byteorder="big") @buff.setter @deprecated( "`logic_array.buff = value` setter is deprecated. " 'Use `logic_array[:] = LogicArray.from_bytes(value, len(logic_array), byteorder="big")` instead.' ) def buff(self, value: bytes) -> None: self[:] = LogicArray.from_bytes(value, len(self), byteorder="big") def to_unsigned(self) -> int: """Convert the value to an integer by interpreting it using unsigned representation. The :class:`!LogicArray` is treated as an arbitrary-length vector of bits with the left-most bit being the most significant bit in the integer value. The bit vector is then interpreted as an integer using unsigned representation. Returns: An integer equivalent to the value by interpreting it using unsigned representation. """ if len(self) == 0: raise ValueError("Cannot convert null vector to integer") return self._get_int() def to_signed(self) -> int: """Convert the value to an integer by interpreting it using two's complement representation. The :class:`!LogicArray` is treated as an arbitrary-length vector of bits with the left-most bit being the most significant bit in the integer value. The bit vector is then interpreted as an integer using two's complement representation. Returns: An integer equivalent to the value by interpreting it using two's complement representation. """ if len(self) == 0: raise ValueError("Cannot convert null vector to integer") value = self._get_int() limit = 1 << (len(self) - 1) if value >= limit: value -= 2 * limit return value def to_bytes( self, *, byteorder: ByteOrder, ) -> bytes: """Convert the value to bytes. The :class:`!LogicArray` is converted to an unsigned integer as in :meth:`to_unsigned`, then is converted to :class:`bytes` using *byteorder*-endian representation with the minimum number of bytes which can store all the bits in the original :class:`!LogicArray`. Args: byteorder: The endianness used to construct the intermediate integer, either ``"big"`` or ``"little"``. Returns: :class:`bytes` equivalent to the value. """ return self.to_unsigned().to_bytes(ceil(len(self) / 8), byteorder=byteorder) @overload def __getitem__(self, item: int) -> Logic: ... @overload def __getitem__(self, item: slice) -> "LogicArray": ... def __getitem__(self, item: Union[int, slice]) -> Union[Logic, "LogicArray"]: array = self._get_array() if isinstance(item, int): if self._warn_indexing: warnings.warn( f"Update index {item} to {self.range[item]}", IndexingChangedWarning, stacklevel=2, ) idx = self._translate_index(item) return array[idx] elif isinstance(item, slice): if self._warn_indexing: start = item.start if item.start is not None else 0 stop = item.stop if item.stop is not None else len(self) - 1 warnings.warn( f"Update slice {start}:{stop} to {self.range[start]}:{self.range[stop]}", IndexingChangedWarning, stacklevel=2, ) start = item.start if item.start is not None else self.left stop = item.stop if item.stop is not None else self.right if item.step is not None: raise IndexError("do not specify step") start_i = self._translate_index(start) stop_i = self._translate_index(stop) if start_i > stop_i: raise IndexError( f"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]" ) value = array[start_i : stop_i + 1] range = Range(start, self.direction, stop) return LogicArray(value=value, range=range) raise TypeError(f"indexes must be ints or slices, not {type(item).__name__}") @overload def __setitem__(self, item: int, value: LogicConstructibleT) -> None: ... @overload def __setitem__( self, item: slice, value: Union[str, Iterable[LogicConstructibleT], int] ) -> None: ... def __setitem__( self, item: Union[int, slice], value: Union[LogicConstructibleT, Iterable[LogicConstructibleT]], ) -> None: array = self._get_array() # invalid other impls self._value_as_str = None self._value_as_int = None if isinstance(item, int): idx = self._translate_index(item) array[idx] = Logic(cast("LogicConstructibleT", value)) elif isinstance(item, slice): start = item.start if item.start is not None else self.left stop = item.stop if item.stop is not None else self.right if item.step is not None: raise IndexError("do not specify step") start_i = self._translate_index(start) stop_i = self._translate_index(stop) if start_i > stop_i: raise IndexError( f"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]" ) value = cast("str | int | Iterable[LogicConstructibleT]", value) value_as_logics = LogicArray(value, stop_i - start_i + 1) array[start_i : stop_i + 1] = value_as_logics else: raise TypeError( f"indexes must be ints or slices, not {type(item).__name__}" ) def _translate_index(self, item: int) -> int: try: return self._range.index(item) except ValueError: raise IndexError(f"index {item} out of range") from None def __repr__(self) -> str: return f"{type(self).__qualname__}({str(self)!r}, {self.range!r})" def __str__(self) -> str: return self._get_str() def __int__(self) -> int: return self.to_unsigned() def __index__(self) -> int: return int(self) def __and__(self, other: "LogicArray") -> "LogicArray": if not isinstance(other, LogicArray): return NotImplemented if len(self) != len(other): raise ValueError( f"cannot perform bitwise & " f"between {type(self).__qualname__} of length {len(self)} " f"and {type(other).__qualname__} of length {len(other)}" ) return LogicArray(a & b for a, b in zip(self, other)) def __or__(self, other: "LogicArray") -> "LogicArray": if not isinstance(other, LogicArray): return NotImplemented if len(self) != len(other): raise ValueError( f"cannot perform bitwise | " f"between {type(self).__qualname__} of length {len(self)} " f"and {type(other).__qualname__} of length {len(other)}" ) return LogicArray(a | b for a, b in zip(self, other)) def __xor__(self, other: "LogicArray") -> "LogicArray": if not isinstance(other, LogicArray): return NotImplemented if len(self) != len(other): raise ValueError( f"cannot perform bitwise ^ " f"between {type(self).__qualname__} of length {len(self)} " f"and {type(other).__qualname__} of length {len(other)}" ) return LogicArray(a ^ b for a, b in zip(self, other)) def __invert__(self) -> "LogicArray": return LogicArray(~v for v in self) if RESOLVE_X is None: def __bool__(self) -> bool: if len(self) == 0: return False return bool(int(self)) else: def __bool__(self) -> bool: if len(self) == 0: return False return any(bool(bit) for bit in self) def resolve(self, resolver: ResolverLiteral) -> "LogicArray": """Resolves non-0/1 values to 0/1. The possible values of the *resolver* argument are: * ``"weak"``: Weak values are resolved to their strong-valued equivalents. * ``"zeros"``: ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively. Remaining non-``0``/``1`` values are resolved to ``0``. * ``"ones"``: ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively. Remaining non-``0``/``1`` values are resolved to ``1``. * ``"random"``: ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively. Remaining non-``0``/``1`` values are randomly resolved to either ``0`` or ``1``. Args: resolver: How to resolve non-``0``/``1`` values. See possible values above. Returns: The resolved Logic. Raises: ValueError: Invalid *resolver* value. TypeError: Unsupported *value* type. """ return LogicArray(get_str_resolver(resolver)(str(self)), self.range) def __copy__(self) -> "LogicArray": raise NotImplementedError("`copy.copy` on LogicArray is not supported") def __deepcopy__(self, memo: Dict[int, Any]) -> "LogicArray": res = LogicArray.__new__(LogicArray) res._value_as_array = copy.deepcopy(self._value_as_array, memo=memo) res._value_as_int = self._value_as_int res._value_as_str = self._value_as_str res._range = copy.deepcopy(self._range, memo=memo) res._warn_indexing = self._warn_indexing return res ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/types/_range.py0000644000175100017510000001412015106067236017446 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import copy from functools import lru_cache from typing import Any, Dict, Iterator, Sequence, Union, overload from cocotb._utils import cached_method class Range(Sequence[int]): r""" Variant of :class:`range` with inclusive right bound. In Python, :class:`range` and :class:`slice` have a non-inclusive right bound. In both Verilog and VHDL, ranges and arrays have an inclusive right bound. This type mimics Python's :class:`range` type, but implements HDL-like inclusive right bounds, using the names :attr:`left` and :attr:`right` as replacements for ``start`` and ``stop`` to match VHDL. Range directionality can be specified using ``'to'`` or ``'downto'`` between the left and right bounds. Not specifying directionality will cause the directionality to be inferred. .. code-block:: pycon3 >>> r = Range(-2, 3) >>> r.left, r.right, len(r) (-2, 3, 6) >>> s = Range(8, "downto", 1) >>> s.left, s.right, len(s) (8, 1, 8) :meth:`from_range` and :meth:`to_range` can be used to convert from and to :class:`range`. .. code-block:: pycon3 >>> r = Range(-2, 3) >>> r.to_range() range(-2, 4) :class:`Range` supports "null" ranges as seen in VHDL. "null" ranges occur when a left bound cannot reach a right bound with the given direction. They have a length of ``0``, but the :attr:`left`, :attr:`right`, and :attr:`direction` values remain as given. .. code-block:: pycon3 >>> r = Range(1, "to", 0) # no way to count from 1 'to' 0 >>> r.left, r.direction, r.right (1, 'to', 0) >>> len(r) 0 .. note:: This is only possible when specifying the direction. Ranges also support all the features of :class:`range` including, but not limited to: - ``value in range`` to see if a value is in the range, - ``range.index(value)`` to see what position in the range the value is, The typical use case of this type is in conjunction with :class:`~cocotb.types.Array`. Args: left: Leftmost bound of range. direction: ``'to'`` if values are ascending, ``'downto'`` if descending. right: Rightmost bound of range (inclusive). """ @overload def __init__(self, left: int, direction: int) -> None: ... @overload def __init__(self, left: int, direction: str, right: int) -> None: ... @overload def __init__(self, left: int, *, right: int) -> None: ... def __init__( self, left: int, direction: Union[int, str, None] = None, right: Union[int, None] = None, ) -> None: start = left stop: int step: int if isinstance(direction, int) and right is None: step = _guess_step(left, direction) stop = direction + step elif isinstance(direction, str) and isinstance(right, int): step = _direction_to_step(direction) stop = right + step elif direction is None and isinstance(right, int): step = _guess_step(left, right) stop = right + step else: raise TypeError("invalid arguments") self._range = range(start, stop, step) @classmethod def from_range(cls, range: range) -> "Range": """Convert :class:`range` to :class:`Range`.""" return cls( left=range.start, direction=_step_to_direction(range.step), right=(range.stop - range.step), ) def to_range(self) -> range: """Convert Range to :class:`range`.""" return self._range @property def left(self) -> int: """Leftmost value in a Range.""" return self._range.start @property def direction(self) -> str: """``'to'`` if Range is ascending, ``'downto'`` otherwise.""" return _step_to_direction(self._range.step) @property def right(self) -> int: """Rightmost value in a Range.""" return self._range.stop - self._range.step def __len__(self) -> int: return len(self._range) @overload def __getitem__(self, item: int) -> int: ... @overload def __getitem__(self, item: slice) -> "Range": ... def __getitem__(self, item: Union[int, slice]) -> Union[int, "Range"]: if isinstance(item, int): return self._range[item] elif isinstance(item, slice): return type(self).from_range(self._range[item]) raise TypeError( f"indices must be integers or slices, not {type(item).__name__}" ) def __contains__(self, item: object) -> bool: return item in self._range def __iter__(self) -> Iterator[int]: return iter(self._range) def __reversed__(self) -> Iterator[int]: return reversed(self._range) def __eq__(self, other: object) -> bool: if isinstance(other, type(self)): return self._range == other._range return NotImplemented # must not be in a type narrowing context to be ignored properly def __hash__(self) -> int: return hash(self._range) def __repr__(self) -> str: return f"{type(self).__qualname__}({self.left!r}, {self.direction!r}, {self.right!r})" index = cached_method(Sequence.index) def __copy__(self) -> "Range": return Range.from_range(self._range) def __deepcopy__(self, memo: Dict[int, Any]) -> "Range": return Range.from_range(copy.deepcopy(self._range, memo=memo)) def _guess_step(left: int, right: int) -> int: if left <= right: return 1 return -1 @lru_cache(maxsize=None) def _direction_to_step(direction: str) -> int: direction = direction.lower() if direction == "to": return 1 elif direction == "downto": return -1 raise ValueError("direction must be 'to' or 'downto'") def _step_to_direction(step: int) -> str: if step == 1: return "to" elif step == -1: return "downto" raise ValueError("step must be 1 or -1") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/types/_resolve.py0000644000175100017510000000400515106067236020032 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import os from functools import lru_cache from random import getrandbits from typing import Callable, Dict, Union from cocotb._py_compat import Final, Literal, TypeAlias ResolverLiteral: TypeAlias = Literal["weak", "zeros", "ones", "random"] _ord_0 = ord("0") class _random_resolve_table(Dict[int, int]): def __init__(self) -> None: self[ord("0")] = ord("0") self[ord("1")] = ord("1") self[ord("L")] = ord("0") self[ord("H")] = ord("1") def __missing__(self, _: str) -> int: return getrandbits(1) + _ord_0 _resolve_tables: Dict[str, Dict[int, int]] = { "error": {}, "weak": str.maketrans("LHW", "01X"), "zeros": str.maketrans("LHUXZW-", "0100000"), "ones": str.maketrans("LHUXZW-", "0111111"), "random": _random_resolve_table(), } _VALID_RESOLVERS = ("error", "weak", "zeros", "ones", "random") _VALID_RESOLVERS_ERR_MSG = ( "Valid values are 'error', 'weak', 'zeros', 'ones', or 'random'" ) @lru_cache(maxsize=None) def get_str_resolver(resolver: ResolverLiteral) -> Callable[[str], str]: if resolver not in _VALID_RESOLVERS: raise ValueError(f"Invalid resolver: {resolver!r}. {_VALID_RESOLVERS_ERR_MSG}") resolve_table = _resolve_tables[resolver] def resolve_func(value: str) -> str: return value.translate(resolve_table) return resolve_func def _init() -> Union[Callable[[str], str], None]: _envvar = os.getenv("COCOTB_RESOLVE_X", None) # no resolver if _envvar is None: return None # backwards compatibility resolver = _envvar.strip().lower() if resolver == "value_error": resolver = "error" # get resolver try: return get_str_resolver(resolver) except ValueError: raise ValueError( f"Invalid COCOTB_RESOLVE_X value: {_envvar!r}. {_VALID_RESOLVERS_ERR_MSG}" ) from None RESOLVE_X: Final = _init() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb/utils.py0000644000175100017510000000646515106067236016224 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """Tools for dealing with simulated time.""" import warnings from decimal import Decimal from fractions import Fraction from typing import Union from cocotb._typing import RoundMode, TimeUnit from cocotb.simtime import ( _get_sim_steps, _get_time_from_sim_steps, get_sim_time, ) __all__ = ( "get_sim_steps", "get_sim_time", "get_time_from_sim_steps", ) def get_time_from_sim_steps( steps: int, unit: Union[TimeUnit, None] = None, *, units: None = None, ) -> float: """Calculate simulation time in the specified *unit* from the *steps* based on the simulator precision. Args: steps: Number of simulation steps. unit: String specifying the unit of the result (one of ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``). .. versionchanged:: 2.0 Renamed from ``units``. Raises: ValueError: If *unit* is not a valid unit. Returns: The simulation time in the specified unit. """ if units is not None: warnings.warn( "The 'units' argument has been renamed to 'unit'.", DeprecationWarning, stacklevel=2, ) unit = units if unit is None: raise TypeError("Missing required argument 'unit'") return _get_time_from_sim_steps(steps, unit) def get_sim_steps( time: Union[float, Fraction, Decimal], unit: TimeUnit = "step", *, round_mode: RoundMode = "error", units: None = None, ) -> int: """Calculates the number of simulation time steps for a given amount of *time*. When *round_mode* is ``"error"``, a :exc:`ValueError` is thrown if the value cannot be accurately represented in terms of simulator time steps. When *round_mode* is ``"round"``, ``"ceil"``, or ``"floor"``, the corresponding rounding function from the standard library will be used to round to a simulator time step. Args: time: The value to convert to simulation time steps. unit: String specifying the unit of the result (one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``). ``'step'`` means *time* is already in simulation time steps. .. versionchanged:: 2.0 Renamed from ``units``. round_mode: String specifying how to handle time values that sit between time steps (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``). Returns: The number of simulation time steps. Raises: ValueError: if the value cannot be represented accurately in terms of simulator time steps when *round_mode* is ``"error"``. .. versionchanged:: 1.5 Support ``'step'`` as the *unit* argument to mean "simulator time step". .. versionchanged:: 1.6 Support rounding modes. """ if units is not None: warnings.warn( "The 'units' argument has been renamed to 'unit'.", DeprecationWarning, stacklevel=2, ) unit = units return _get_sim_steps(time, unit, round_mode=round_mode) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3587027 cocotb-2.0.1/src/cocotb.egg-info/0000755000175100017510000000000015106070715016165 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763209677.0 cocotb-2.0.1/src/cocotb.egg-info/PKG-INFO0000644000175100017510000000542015106070715017263 0ustar00runnerrunnerMetadata-Version: 2.4 Name: cocotb Version: 2.0.1 Summary: cocotb is a coroutine based cosimulation library for writing VHDL and Verilog testbenches in Python. Home-page: https://www.cocotb.org Author: Chris Higgs, Stuart Hodgson Maintainer: cocotb contributors Maintainer-email: cocotb@lists.librecores.org License: BSD-3-Clause Project-URL: Bug Tracker, https://github.com/cocotb/cocotb/issues Project-URL: Source Code, https://github.com/cocotb/cocotb Project-URL: Documentation, https://docs.cocotb.org Platform: any Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA) Classifier: Framework :: cocotb Requires-Python: >=3.6.2 Description-Content-Type: text/markdown License-File: LICENSE Requires-Dist: find_libpython Dynamic: author Dynamic: classifier Dynamic: description Dynamic: description-content-type Dynamic: home-page Dynamic: license Dynamic: license-file Dynamic: maintainer Dynamic: maintainer-email Dynamic: platform Dynamic: project-url Dynamic: requires-dist Dynamic: requires-python Dynamic: summary **cocotb** is a framework empowering users to write VHDL and Verilog testbenches in Python. [![Documentation Status](https://readthedocs.org/projects/cocotb/badge/?version=development)](https://docs.cocotb.org/en/stable/) [![CI](https://github.com/cocotb/cocotb/actions/workflows/build-test-dev.yml/badge.svg?branch=master)](https://github.com/cocotb/cocotb/actions/workflows/build-test-dev.yml) [![PyPI](https://img.shields.io/pypi/dm/cocotb.svg?label=PyPI%20downloads)](https://pypi.org/project/cocotb/) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/cocotb/cocotb) [![codecov](https://codecov.io/gh/cocotb/cocotb/branch/master/graph/badge.svg)](https://codecov.io/gh/cocotb/cocotb) * Check out the [tutorial](https://docs.cocotb.org/en/stable/quickstart.html) * Read the [docs](https://docs.cocotb.org/en/stable/) * Find more info in the [wiki](https://github.com/cocotb/cocotb/wiki) * Discover [useful extensions](https://github.com/cocotb/cocotb/wiki/Further-Resources#utility-libraries-and-frameworks) * Join the discussion in the [Gitter chat room](https://gitter.im/cocotb/Lobby) * [Ask a question](https://github.com/cocotb/cocotb/discussions) * [Raise a bug / request an enhancement](https://github.com/cocotb/cocotb/issues/new) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763209677.0 cocotb-2.0.1/src/cocotb.egg-info/SOURCES.txt0000644000175100017510000001063315106070715020054 0ustar00runnerrunnerLICENSE MANIFEST.in README.md cocotb_build_libs.py pyproject.toml setup.py src/cocotb/_ANSI.py src/cocotb/__init__.py src/cocotb/_base_triggers.py src/cocotb/_bridge.py src/cocotb/_decorators.py src/cocotb/_deprecation.py src/cocotb/_exceptions.py src/cocotb/_extended_awaitables.py src/cocotb/_gpi_triggers.py src/cocotb/_init.py src/cocotb/_outcomes.py src/cocotb/_profiling.py src/cocotb/_py_compat.py src/cocotb/_scheduler.py src/cocotb/_test.py src/cocotb/_test_factory.py src/cocotb/_test_functions.py src/cocotb/_typing.py src/cocotb/_utils.py src/cocotb/_version.py src/cocotb/_xunit_reporter.py src/cocotb/clock.py src/cocotb/debug.py src/cocotb/handle.py src/cocotb/logging.py src/cocotb/py.typed src/cocotb/queue.py src/cocotb/regression.py src/cocotb/result.py src/cocotb/simtime.py src/cocotb/simulator.pyi src/cocotb/task.py src/cocotb/triggers.py src/cocotb/utils.py src/cocotb.egg-info/PKG-INFO src/cocotb.egg-info/SOURCES.txt src/cocotb.egg-info/dependency_links.txt src/cocotb.egg-info/entry_points.txt src/cocotb.egg-info/requires.txt src/cocotb.egg-info/top_level.txt src/cocotb/_vendor/README.md src/cocotb/_vendor/fli/acc_user.h src/cocotb/_vendor/fli/acc_vhdl.h src/cocotb/_vendor/fli/mti.h src/cocotb/_vendor/tcl/license.terms src/cocotb/_vendor/tcl/tcl.h src/cocotb/_vendor/tcl/tclDecls.h src/cocotb/_vendor/tcl/tclPlatDecls.h src/cocotb/_vendor/vhpi/vhpi_user.h src/cocotb/_vendor/vpi/sv_vpi_user.h src/cocotb/_vendor/vpi/vpi_user.h src/cocotb/share/def/.gitignore src/cocotb/share/def/README.md src/cocotb/share/def/aldec.def src/cocotb/share/def/ghdl.def src/cocotb/share/def/icarus.def src/cocotb/share/def/modelsim.def src/cocotb/share/def/nvcvhpi.def src/cocotb/share/include/cocotb_utils.h src/cocotb/share/include/embed.h src/cocotb/share/include/exports.h src/cocotb/share/include/gpi.h src/cocotb/share/include/gpi_logging.h src/cocotb/share/include/py_gpi_logging.h src/cocotb/share/include/vhpi_user_ext.h src/cocotb/share/include/vpi_user_ext.h src/cocotb/share/lib/embed/embed.cpp src/cocotb/share/lib/embed/gpi_embed.cpp src/cocotb/share/lib/fli/FliCbHdl.cpp src/cocotb/share/lib/fli/FliImpl.cpp src/cocotb/share/lib/fli/FliImpl.h src/cocotb/share/lib/fli/FliObjHdl.cpp src/cocotb/share/lib/gpi/GpiCbHdl.cpp src/cocotb/share/lib/gpi/GpiCommon.cpp src/cocotb/share/lib/gpi/gpi_priv.h src/cocotb/share/lib/gpi_log/gpi_logging.cpp src/cocotb/share/lib/py_gpi_log/py_gpi_logging.cpp src/cocotb/share/lib/simulator/simulatormodule.cpp src/cocotb/share/lib/utils/cocotb_utils.cpp src/cocotb/share/lib/verilator/verilator.cpp src/cocotb/share/lib/vhpi/VhpiCbHdl.cpp src/cocotb/share/lib/vhpi/VhpiImpl.cpp src/cocotb/share/lib/vhpi/VhpiImpl.h src/cocotb/share/lib/vpi/VpiCbHdl.cpp src/cocotb/share/lib/vpi/VpiImpl.cpp src/cocotb/share/lib/vpi/VpiImpl.h src/cocotb/share/lib/vpi/VpiIterator.cpp src/cocotb/share/lib/vpi/VpiObj.cpp src/cocotb/share/lib/vpi/VpiSignal.cpp src/cocotb/types/__init__.py src/cocotb/types/_abstract_array.py src/cocotb/types/_array.py src/cocotb/types/_indexing.py src/cocotb/types/_logic.py src/cocotb/types/_logic_array.py src/cocotb/types/_range.py src/cocotb/types/_resolve.py src/cocotb_tools/__init__.py src/cocotb_tools/_coverage.py src/cocotb_tools/check_results.py src/cocotb_tools/combine_results.py src/cocotb_tools/config.py src/cocotb_tools/ipython_support.py src/cocotb_tools/py.typed src/cocotb_tools/runner.py src/cocotb_tools/sim_versions.py src/cocotb_tools/_vendor/__init__.py src/cocotb_tools/_vendor/distutils_version.py src/cocotb_tools/makefiles/Makefile.deprecations src/cocotb_tools/makefiles/Makefile.inc src/cocotb_tools/makefiles/Makefile.sim src/cocotb_tools/makefiles/simulators/Makefile.activehdl src/cocotb_tools/makefiles/simulators/Makefile.cvc src/cocotb_tools/makefiles/simulators/Makefile.dsim src/cocotb_tools/makefiles/simulators/Makefile.ghdl src/cocotb_tools/makefiles/simulators/Makefile.icarus src/cocotb_tools/makefiles/simulators/Makefile.ius src/cocotb_tools/makefiles/simulators/Makefile.modelsim src/cocotb_tools/makefiles/simulators/Makefile.nvc src/cocotb_tools/makefiles/simulators/Makefile.questa src/cocotb_tools/makefiles/simulators/Makefile.questa-compat src/cocotb_tools/makefiles/simulators/Makefile.questa-qisqrun src/cocotb_tools/makefiles/simulators/Makefile.riviera src/cocotb_tools/makefiles/simulators/Makefile.vcs src/cocotb_tools/makefiles/simulators/Makefile.verilator src/cocotb_tools/makefiles/simulators/Makefile.xcelium src/pygpi/__init__.py src/pygpi/entry.py src/pygpi/py.typed././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763209677.0 cocotb-2.0.1/src/cocotb.egg-info/dependency_links.txt0000644000175100017510000000000115106070715022233 0ustar00runnerrunner ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763209677.0 cocotb-2.0.1/src/cocotb.egg-info/entry_points.txt0000644000175100017510000000007315106070715021463 0ustar00runnerrunner[console_scripts] cocotb-config = cocotb_tools.config:main ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763209677.0 cocotb-2.0.1/src/cocotb.egg-info/requires.txt0000644000175100017510000000001715106070715020563 0ustar00runnerrunnerfind_libpython ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763209677.0 cocotb-2.0.1/src/cocotb.egg-info/top_level.txt0000644000175100017510000000111515106070715020715 0ustar00runnerrunnercocotb cocotb/libs/libcocotb cocotb/libs/libcocotbfli_modelsim cocotb/libs/libcocotbutils cocotb/libs/libcocotbvhpi_aldec cocotb/libs/libcocotbvhpi_ius cocotb/libs/libcocotbvhpi_modelsim cocotb/libs/libcocotbvhpi_nvc cocotb/libs/libcocotbvpi_aldec cocotb/libs/libcocotbvpi_dsim cocotb/libs/libcocotbvpi_ghdl cocotb/libs/libcocotbvpi_icarus cocotb/libs/libcocotbvpi_ius cocotb/libs/libcocotbvpi_modelsim cocotb/libs/libcocotbvpi_vcs cocotb/libs/libcocotbvpi_verilator cocotb/libs/libembed cocotb/libs/libgpi cocotb/libs/libgpilog cocotb/libs/libpygpilog cocotb/simulator cocotb_tools pygpi ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3547027 cocotb-2.0.1/src/cocotb_tools/0000755000175100017510000000000015106070715015713 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/__init__.py0000644000175100017510000000000015106067236020016 0ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/_coverage.py0000644000175100017510000000232015106067236020220 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause import os def start_cocotb_library_coverage(_: object) -> None: # pragma: no cover if "COCOTB_LIBRARY_COVERAGE" not in os.environ: return try: import coverage # noqa: PLC0415 except (ImportError, ModuleNotFoundError): raise RuntimeError( "cocotb library coverage collection requested but coverage package not available. Install it using `pip install coverage`." ) from None else: library_coverage = coverage.coverage( data_file=".coverage.cocotb", config_file=False, branch=True, source=["cocotb"], ) library_coverage.start() def stop_library_coverage() -> None: library_coverage.stop() library_coverage.save() # pragma: no cover # This must come after `library_coverage.start()` to ensure coverage is being # collected on the cocotb library before importing from it. from cocotb._init import _register_shutdown_callback # noqa: PLC0415 _register_shutdown_callback(stop_library_coverage) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3547027 cocotb-2.0.1/src/cocotb_tools/_vendor/0000755000175100017510000000000015106070715017347 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/_vendor/__init__.py0000644000175100017510000000021315106067236021460 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/_vendor/distutils_version.py0000644000175100017510000003104715106067236023523 0ustar00runnerrunner# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation; # All Rights Reserved # Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # # distutils/version.py # # Implements multiple version numbering conventions for the # Python Module Distribution Utilities. # # $Id$ # """Provides classes to represent module version numbers (one class for each style of version numbering). There are currently two such classes implemented: StrictVersion and LooseVersion. Every version number class implements the following interface: * the 'parse' method takes a string and parses it to some internal representation; if the string is an invalid version number, 'parse' raises a ValueError exception * the class constructor takes an optional string argument which, if supplied, is passed to 'parse' * __str__ reconstructs the string that was passed to 'parse' (or an equivalent string -- ie. one that will generate an equivalent version number instance) * __repr__ generates Python code to recreate the version number instance * _cmp compares the current instance with either another instance of the same class or a string (which will be parsed to an instance of the same class, thus must follow the same rules) """ import re class Version: """Abstract base class for version numbering classes. Just provides constructor (__init__) and reproducer (__repr__), because those seem to be the same for all version numbering classes; and route rich comparisons to _cmp. """ def __init__ (self, vstring=None): if vstring: self.parse(vstring) def __repr__ (self): return "%s ('%s')" % (self.__class__.__name__, str(self)) def __eq__(self, other): c = self._cmp(other) if c is NotImplemented: return c return c == 0 def __lt__(self, other): c = self._cmp(other) if c is NotImplemented: return c return c < 0 def __le__(self, other): c = self._cmp(other) if c is NotImplemented: return c return c <= 0 def __gt__(self, other): c = self._cmp(other) if c is NotImplemented: return c return c > 0 def __ge__(self, other): c = self._cmp(other) if c is NotImplemented: return c return c >= 0 # Interface for version-number classes -- must be implemented # by the following classes (the concrete ones -- Version should # be treated as an abstract class). # __init__ (string) - create and take same action as 'parse' # (string parameter is optional) # parse (string) - convert a string representation to whatever # internal representation is appropriate for # this style of version numbering # __str__ (self) - convert back to a string; should be very similar # (if not identical to) the string supplied to parse # __repr__ (self) - generate Python code to recreate # the instance # _cmp (self, other) - compare two version numbers ('other' may # be an unparsed version string, or another # instance of your version class) class StrictVersion (Version): """Version numbering for anal retentives and software idealists. Implements the standard interface for version number classes as described above. A version number consists of two or three dot-separated numeric components, with an optional "pre-release" tag on the end. The pre-release tag consists of the letter 'a' or 'b' followed by a number. If the numeric components of two version numbers are equal, then one with a pre-release tag will always be deemed earlier (lesser) than one without. The following are valid version numbers (shown in the order that would be obtained by sorting according to the supplied cmp function): 0.4 0.4.0 (these two are equivalent) 0.4.1 0.5a1 0.5b3 0.5 0.9.6 1.0 1.0.4a3 1.0.4b1 1.0.4 The following are examples of invalid version numbers: 1 2.7.2.2 1.3.a4 1.3pl1 1.3c4 The rationale for this version numbering system will be explained in the distutils documentation. """ version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$', re.VERBOSE | re.ASCII) def parse (self, vstring): match = self.version_re.match(vstring) if not match: raise ValueError("invalid version number '%s'" % vstring) (major, minor, patch, prerelease, prerelease_num) = \ match.group(1, 2, 4, 5, 6) if patch: self.version = tuple(map(int, [major, minor, patch])) else: self.version = tuple(map(int, [major, minor])) + (0,) if prerelease: self.prerelease = (prerelease[0], int(prerelease_num)) else: self.prerelease = None def __str__ (self): if self.version[2] == 0: vstring = '.'.join(map(str, self.version[0:2])) else: vstring = '.'.join(map(str, self.version)) if self.prerelease: vstring = vstring + self.prerelease[0] + str(self.prerelease[1]) return vstring def _cmp (self, other): if isinstance(other, str): other = StrictVersion(other) elif not isinstance(other, StrictVersion): return NotImplemented if self.version != other.version: # numeric versions don't match # prerelease stuff doesn't matter if self.version < other.version: return -1 else: return 1 # have to compare prerelease # case 1: neither has prerelease; they're equal # case 2: self has prerelease, other doesn't; other is greater # case 3: self doesn't have prerelease, other does: self is greater # case 4: both have prerelease: must compare them! if (not self.prerelease and not other.prerelease): return 0 elif (self.prerelease and not other.prerelease): return -1 elif (not self.prerelease and other.prerelease): return 1 elif (self.prerelease and other.prerelease): if self.prerelease == other.prerelease: return 0 elif self.prerelease < other.prerelease: return -1 else: return 1 else: assert False, "never get here" # end class StrictVersion # The rules according to Greg Stein: # 1) a version number has 1 or more numbers separated by a period or by # sequences of letters. If only periods, then these are compared # left-to-right to determine an ordering. # 2) sequences of letters are part of the tuple for comparison and are # compared lexicographically # 3) recognize the numeric components may have leading zeroes # # The LooseVersion class below implements these rules: a version number # string is split up into a tuple of integer and string components, and # comparison is a simple tuple comparison. This means that version # numbers behave in a predictable and obvious way, but a way that might # not necessarily be how people *want* version numbers to behave. There # wouldn't be a problem if people could stick to purely numeric version # numbers: just split on period and compare the numbers as tuples. # However, people insist on putting letters into their version numbers; # the most common purpose seems to be: # - indicating a "pre-release" version # ('alpha', 'beta', 'a', 'b', 'pre', 'p') # - indicating a post-release patch ('p', 'pl', 'patch') # but of course this can't cover all version number schemes, and there's # no way to know what a programmer means without asking him. # # The problem is what to do with letters (and other non-numeric # characters) in a version number. The current implementation does the # obvious and predictable thing: keep them as strings and compare # lexically within a tuple comparison. This has the desired effect if # an appended letter sequence implies something "post-release": # eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002". # # However, if letters in a version number imply a pre-release version, # the "obvious" thing isn't correct. Eg. you would expect that # "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison # implemented here, this just isn't so. # # Two possible solutions come to mind. The first is to tie the # comparison algorithm to a particular set of semantic rules, as has # been done in the StrictVersion class above. This works great as long # as everyone can go along with bondage and discipline. Hopefully a # (large) subset of Python module programmers will agree that the # particular flavour of bondage and discipline provided by StrictVersion # provides enough benefit to be worth using, and will submit their # version numbering scheme to its domination. The free-thinking # anarchists in the lot will never give in, though, and something needs # to be done to accommodate them. # # Perhaps a "moderately strict" version class could be implemented that # lets almost anything slide (syntactically), and makes some heuristic # assumptions about non-digits in version number strings. This could # sink into special-case-hell, though; if I was as talented and # idiosyncratic as Larry Wall, I'd go ahead and implement a class that # somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is # just as happy dealing with things like "2g6" and "1.13++". I don't # think I'm smart enough to do it right though. # # In any case, I've coded the test suite for this module (see # ../test/test_version.py) specifically to fail on things like comparing # "1.2a2" and "1.2". That's not because the *code* is doing anything # wrong, it's because the simple, obvious design doesn't match my # complicated, hairy expectations for real-world version numbers. It # would be a snap to fix the test suite to say, "Yep, LooseVersion does # the Right Thing" (ie. the code matches the conception). But I'd rather # have a conception that matches common notions about version numbers. class LooseVersion (Version): """Version numbering for anarchists and software realists. Implements the standard interface for version number classes as described above. A version number consists of a series of numbers, separated by either periods or strings of letters. When comparing version numbers, the numeric components will be compared numerically, and the alphabetic components lexically. The following are all valid version numbers, in no particular order: 1.5.1 1.5.2b2 161 3.10a 8.02 3.4j 1996.07.12 3.2.pl0 3.1.1.6 2g6 11g 0.960923 2.2beta29 1.13++ 5.5.kw 2.0b1pl0 In fact, there is no such thing as an invalid version number under this scheme; the rules for comparison are simple and predictable, but may not always give the results you want (for some definition of "want"). """ component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) def __init__ (self, vstring=None): if vstring: self.parse(vstring) def parse (self, vstring): # I've given up on thinking I can reconstruct the version string # from the parsed tuple -- so I just store the string here for # use by __str__ self.vstring = vstring components = [x for x in self.component_re.split(vstring) if x and x != '.'] for i, obj in enumerate(components): try: components[i] = int(obj) except ValueError: pass self.version = components def __str__ (self): return self.vstring def __repr__ (self): return "LooseVersion ('%s')" % str(self) def _cmp (self, other): if isinstance(other, str): other = LooseVersion(other) elif not isinstance(other, LooseVersion): return NotImplemented if self.version == other.version: return 0 if self.version < other.version: return -1 if self.version > other.version: return 1 # end class LooseVersion ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/check_results.py0000644000175100017510000000325015106067236021127 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """Checks if a JUnit results file exists and whether there was failing tests.""" import argparse import sys from pathlib import Path from typing import Tuple from xml.etree import ElementTree def get_results(results_xml_file: Path) -> Tuple[int, int]: """Return number of tests and fails in *results_xml_file*. Returns: Tuple of number of tests and number of fails. Raises: RuntimeError: If *results_xml_file* is non-existent. """ __tracebackhide__ = True # Hide the traceback when using PyTest. if not results_xml_file.is_file(): raise RuntimeError( f"ERROR: Simulation terminated abnormally. Results file {results_xml_file} not found." ) num_tests = 0 num_failed = 0 tree = ElementTree.parse(results_xml_file) for ts in tree.iter("testsuite"): for tc in ts.iter("testcase"): num_tests += 1 for _ in tc.iter("failure"): num_failed += 1 return (num_tests, num_failed) def _get_parser() -> argparse.ArgumentParser: """Return the cmdline parser""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "results_file", help="Path to XML file holding JUnit test results.", type=Path ) return parser def main() -> int: parser = _get_parser() args = parser.parse_args() try: (_, num_failed) = get_results(args.results_file) except RuntimeError: return 1 return num_failed if __name__ == "__main__": rc = main() sys.exit(rc) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/combine_results.py0000755000175100017510000001202215106067236021466 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause #!/usr/bin/env python """ Simple script to combine JUnit test results into a single XML file. """ import argparse import os import re import sys from pathlib import Path from typing import Iterable, Pattern from xml.etree import ElementTree as ET def _find_all(name: Pattern, path: Path) -> Iterable[Path]: for obj in path.iterdir(): if obj.is_file() and re.match(name, obj.name): yield obj elif obj.is_dir(): yield from _find_all(name, obj) def _get_parser() -> argparse.ArgumentParser: """Return the cmdline parser""" parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument( "directories", nargs="*", type=lambda args: [Path(arg) for arg in args], default=[Path()], help="Directories to search for input files.", ) parser.add_argument( "-i", "--input-filename", default=r"results.*\.xml", help="A regular expression to match input filenames.", ) parser.add_argument( "-o", "--output-file", default="combined_results.xml", help="Path of output XML file.", ) parser.add_argument( "--output-testsuites-name", default="results", help="Name of 'testsuites' element in output XML file.", ) parser.add_argument( "--verbose", action="store_true", help="Enables verbose output.", ) parser.add_argument( "--repo-root", type=Path, help="Specify root of cocotb repo the regression is run from (CI only).", ) return parser def main() -> int: parser = _get_parser() args = parser.parse_args() rc = 0 result = ET.Element("testsuites", name=args.output_testsuites_name) input_pattern = re.compile(args.input_filename) for directory in args.directories: if args.verbose: print(f"Searching in {directory} for results.xml files.") for fname in _find_all(input_pattern, directory): if args.verbose: print(f"Reading file {fname}.") tree = ET.parse(fname) for ts in tree.iter("testsuite"): if args.verbose: print( "Testsuite name: {!r}, package: {!r}".format( ts.get("name"), ts.get("package") ) ) for existing in result: if (existing.get("name") == ts.get("name")) and ( existing.get("package") == ts.get("package") ): if args.verbose: print( "Testsuite already exists in combined results. Extending it." ) existing.extend(list(ts)) break else: if args.verbose: print( "Testsuite does not already exist in combined results. Adding it." ) result.append(ts) testsuite_count = 0 testcase_count = 0 for testsuite in result.iter("testsuite"): testsuite_count += 1 for testcase in testsuite.iter("testcase"): testcase_count += 1 for _ in testcase.iter("failure"): rc = 1 print( "Failure in testsuite: '{}' classname: '{}' testcase: '{}' with parameters '{}'".format( testsuite.get("name"), testcase.get("classname"), testcase.get("name"), testsuite.get("package"), ) ) if ( os.getenv("GITHUB_ACTIONS") is not None and args.repo_root is not None ): # Get test file relative to root of repo file = testcase.get("file") # if this file was output by cocotb, it has this attribute assert file is not None relative_file = Path(file).relative_to(args.repo_root) print( "::error file={},line={}::Test {}:{} failed".format( relative_file, testcase.get("lineno"), testcase.get("classname"), testcase.get("name"), ) ) print(f"Ran a total of {testsuite_count} TestSuites and {testcase_count} TestCases") if args.verbose: print(f"Writing combined results to {args.output_file}") ET.ElementTree(result).write(args.output_file, encoding="UTF-8") return rc if __name__ == "__main__": rc = main() sys.exit(rc) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/config.py0000755000175100017510000001705515106067236017551 0ustar00runnerrunner#!/usr/bin/env python # Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """ Module for querying the cocotb configuration This module provides information in module global variables and through a ``main()`` function that is used in the cocotb-config script. Global variables: share_dir: str, path where the cocotb data is stored makefiles_dir: str, path where the cocotb makefiles are installed libs_dir: str, path where the cocotb interface libraries are located """ import argparse import os import sys import textwrap from pathlib import Path import find_libpython import cocotb_tools base_tools_dir = Path(cocotb_tools.__file__).parent.resolve() base_cocotb_dir = (base_tools_dir.parent / "cocotb").resolve() if not (base_cocotb_dir.exists() and (base_cocotb_dir / "libs").exists()): import cocotb base_cocotb_dir = Path(cocotb.__file__).parent.resolve() share_dir = base_cocotb_dir.joinpath("share") libs_dir = base_cocotb_dir.joinpath("libs") makefiles_dir = base_tools_dir.joinpath("makefiles") def _get_version() -> str: import cocotb # noqa: PLC0415 return cocotb.__version__ def _help_vars_text() -> str: if "dev" in _get_version(): doclink = "https://docs.cocotb.org/en/development/library_reference.html" else: doclink = f"https://docs.cocotb.org/en/v{_get_version()}/library_reference.html" # NOTE: make sure to keep "helpmsg" aligned with docs/source/library_reference.rst helpmsg = textwrap.dedent( """\ The following variables are environment variables: cocotb ------ COCOTB_TOPLEVEL Instance in the hierarchy to use as the DUT COCOTB_RANDOM_SEED Random seed, to recreate a previous test stimulus COCOTB_ANSI_OUTPUT Force cocotb to print or not print in color COCOTB_REDUCED_LOG_FMT Display log lines shorter COCOTB_ATTACH Pause time value in seconds before the simulator start COCOTB_ENABLE_PROFILING Performance analysis of the Python portion of cocotb COCOTB_LOG_LEVEL Default logging level (default INFO) COCOTB_RESOLVE_X How to resolve X, Z, U, W, - on integer conversion LIBPYTHON_LOC Absolute path to libpython Regression Manager ------------------ COCOTB_PDB_ON_EXCEPTION Drop into the Python debugger (pdb) on exception COCOTB_TEST_MODULES Module(s) to search for test functions (comma-separated) COCOTB_TESTCASE Test function(s) to run (comma-separated list) COCOTB_RESULTS_FILE File name for xUnit XML tests results COCOTB_USER_COVERAGE Collect Python user coverage (HDL for some simulators) COVERAGE_RCFILE Configuration for user code coverage GPI --- GPI_EXTRA Extra libraries to load at runtime (comma-separated) Scheduler --------- COCOTB_SCHEDULER_DEBUG Enable additional output of coroutine scheduler COCOTB_TRUST_INERTIAL_WRITES Trust inertial writes rather than mock them using scheduler For details, see {}""" ).format(doclink) return helpmsg def lib_name(interface: str, simulator: str) -> str: """ Return the name of interface library for given interface (VPI/VHPI/FLI) and simulator. """ interface_name = interface.lower() supported_interfaces = ["vpi", "vhpi", "fli"] if interface_name not in supported_interfaces: raise ValueError( "Wrong interface used. Supported: " + ", ".join(supported_interfaces) ) simulator_name = simulator.lower() supported_sims = [ "icarus", "verilator", "questa", "modelsim", "ius", "xcelium", "vcs", "ghdl", "riviera", "activehdl", "cvc", "nvc", "dsim", ] if simulator not in supported_sims: raise ValueError( "Wrong simulator name. Supported: " + ", ".join(supported_sims) ) if simulator_name in ["questa", "cvc"]: library_name = "modelsim" elif simulator_name == "xcelium": library_name = "ius" elif simulator_name in ["riviera", "activehdl"]: library_name = "aldec" else: library_name = simulator_name if library_name == "icarus": lib_ext = "" elif os.name == "nt": lib_ext = ".dll" else: lib_ext = ".so" # check if compiled with msvc if (libs_dir / "cocotb.dll").is_file(): lib_prefix = "" else: lib_prefix = "lib" return lib_prefix + "cocotb" + interface_name + "_" + library_name + lib_ext def lib_name_path(interface: str, simulator: str) -> Path: """ Return the absolute path of interface library for given interface (VPI/VHPI/FLI) and simulator """ return libs_dir / lib_name(interface, simulator) def _get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) group = parser.add_mutually_exclusive_group() group.add_argument( "--share", action="store_true", help="Print the path to cocotb's share directory", ) group.add_argument( "--makefiles", action="store_true", help="Print the path to cocotb's makefile directory", ) group.add_argument( "--python-bin", action="store_true", help="Print the path to the Python executable associated with the environment that cocotb is installed in.", ) group.add_argument( "--help-vars", action="store_true", help="Print help about supported Makefile variables", ) group.add_argument( "--libpython", action="store_true", help="Print the absolute path to the libpython associated with the current Python installation", ) group.add_argument( "--lib-dir", action="store_true", help="Print the absolute path to the interface libraries location", ) group.add_argument( "--lib-name", help="Print the name of interface library for given interface (VPI/VHPI/FLI) and simulator", nargs=2, metavar=("INTERFACE", "SIMULATOR"), ) group.add_argument( "--lib-name-path", help="Print the absolute path of interface library for given interface (VPI/VHPI/FLI) and simulator", nargs=2, metavar=("INTERFACE", "SIMULATOR"), ) group.add_argument( "--version", action="store_true", help="Print the version of cocotb", ) return parser def main() -> None: parser = _get_parser() args = parser.parse_args() if args.share: print(share_dir.as_posix()) elif args.makefiles: print(makefiles_dir.as_posix()) elif args.python_bin: print(Path(sys.executable).as_posix()) elif args.help_vars: print(_help_vars_text()) elif args.libpython: libpython_path = find_libpython.find_libpython() if libpython_path is None: sys.exit(1) print(Path(libpython_path).as_posix()) elif args.lib_dir: print(libs_dir.as_posix()) elif args.lib_name: print(lib_name(*args.lib_name)) elif args.lib_name_path: print(lib_name_path(*args.lib_name_path).as_posix()) elif args.version: print(_get_version()) if __name__ == "__main__": main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/ipython_support.py0000644000175100017510000000642115106067236021562 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause from typing import Any, Dict, TypeVar import IPython from IPython.terminal.ipapp import load_default_config from IPython.terminal.prompts import Prompts from pygments.token import Token import cocotb from cocotb.task import bridge from cocotb.utils import get_sim_time T = TypeVar("T") class SimTimePrompt(Prompts): """custom prompt that shows the sim time after a trigger fires""" _show_time = 1 def in_prompt_tokens(self): tokens = super().in_prompt_tokens() if self._show_time == self.shell.execution_count: tokens = [ (Token.Comment, f"sim time: {get_sim_time()}"), (Token.Text, "\n"), *tokens, ] return tokens async def embed(user_ns: Dict[str, Any] = {}) -> None: """ Start an IPython shell in the current coroutine. Unlike using :func:`IPython.embed` directly, the :keyword:`await` keyword can be used directly from the shell to wait for triggers. The :keyword:`yield` keyword from the legacy :ref:`yield-syntax` is not supported. This coroutine will complete only when the user exits the interactive session. Args: user_ns: The variables to have made available in the shell. Passing ``locals()`` is often a good idea. ``cocotb`` will automatically be included. .. note:: If your simulator does not provide an appropriate ``stdin``, you may find you cannot type in the resulting shell. Using simulators in batch or non-GUI mode may resolve this. This feature is experimental, and not all simulators are supported. """ # ensure cocotb is in the namespace, for convenience default_ns = {"cocotb": cocotb} default_ns.update(user_ns) def _runner(x): """Handler for async functions""" nonlocal shell ret = cocotb._scheduler_inst._queue_function(x) shell.prompts._show_time = shell.execution_count return ret # build the config to enable `await` c = load_default_config() c.TerminalInteractiveShell.loop_runner = _runner c.TerminalInteractiveShell.autoawait = True # Python3 checks SQLite DB accesses to ensure process ID matches the one that opened the DB and is not propagated # because we launch IPython in a different process, this will cause unnecessary warnings, so disable the PID check c.HistoryAccessor.connection_options = {"check_same_thread": False} # create a shell with access to the dut, and cocotb pre-imported shell = IPython.terminal.embed.InteractiveShellEmbed( user_ns=default_ns, config=c, ) # add our custom prompts shell.prompts = SimTimePrompt(shell) # start the shell in a background thread @bridge def run_shell() -> None: shell() await run_shell() @cocotb.test() async def run_ipython(dut: Any) -> None: """A test that launches an interactive Python shell. Do not call this directly - use this as ``make COCOTB_TEST_MODULES=cocotb.ipython_support``. Within the shell, a global ``dut`` variable pointing to the design will be present. """ await embed(user_ns={"dut": dut}) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3557026 cocotb-2.0.1/src/cocotb_tools/makefiles/0000755000175100017510000000000015106070715017653 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/Makefile.deprecations0000644000175100017510000000153315106067236024000 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause ifdef VERILATOR_TRACE $(warning VERILATOR_TRACE is deprecated, see the "Simulator Support" section in the documentation.) endif ifeq ($(SIM_LOWERCASE),aldec) $(warning Using SIM=aldec is deprecated, please use SIM=riviera instead.) SIM_LOWERCASE := riviera endif # Use this function to warn users about deprecated environment variables deprecate = $(if $($(1)),$(if $(filter $($(2)),$($(1))),$($(2)),$(warning Using $(1) is deprecated, please use $(2) instead.)$($(1))),$($(2))) ifneq ($(COCOTB_TOPLEVEL),$(TOPLEVEL)) ifneq ($(TOPLEVEL),) COCOTB_TOPLEVEL := $(TOPLEVEL) endif endif ifneq ($(COCOTB_USER_COVERAGE),$(COVERAGE)) ifneq ($(COVERAGE),) COCOTB_USER_COVERAGE := $(COVERAGE) endif endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/Makefile.inc0000644000175100017510000001220015106067236022062 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Common makefile included by everything ifndef COCOTB_MAKEFILE_INC_INCLUDED # Protect against multiple includes COCOTB_MAKEFILE_INC_INCLUDED = 1 # Default sim rule will force a re-run of the simulation (though the cocotb library # and RTL compilation phases are still evaluated by makefile dependencies) .PHONY: sim sim: $(RM) $(COCOTB_RESULTS_FILE) "$(MAKE)" -f $(firstword $(MAKEFILE_LIST)) $(COCOTB_RESULTS_FILE) # Make sure to use bash for the pipefail option used in many simulator Makefiles SHELL := bash OS=$(shell uname) ifneq (, $(findstring MINGW, $(OS))) OS := Msys else ifneq (, $(findstring MSYS, $(OS))) OS := Msys endif export OS export PYGPI_PYTHON_BIN := $(shell $(PYTHON_BIN) -m cocotb_tools.config --python-bin) # Directory containing the cocotb Makefiles COCOTB_MAKEFILES_DIR := $(shell $(PYTHON_BIN) -m cocotb_tools.config --makefiles) include $(COCOTB_MAKEFILES_DIR)/Makefile.deprecations PYTHON_ARCH := $(shell $(PYTHON_BIN) -c 'from platform import architecture; print(architecture()[0])') ifeq ($(filter $(PYTHON_ARCH),64bit 32bit),) $(error Unknown Python architecture: $(PYTHON_ARCH)) endif ifeq ($(OS),Msys) to_tcl_path = $(shell cygpath -m $(1) ) else to_tcl_path = $(1) endif # Check that the COCOTB_RESULTS_FILE was created, since we can't set an exit code from cocotb. define check_for_results_file @test -f $(COCOTB_RESULTS_FILE) || (echo "ERROR: $(COCOTB_RESULTS_FILE) was not written by the simulation!" >&2 && exit 1) endef # Check that the COCOTB_RESULTS_FILE was created and has no failures define check_results @$(PYTHON_BIN) -m cocotb_tools.check_results $(COCOTB_RESULTS_FILE) endef SIM_BUILD ?= sim_build export SIM_BUILD COCOTB_RESULTS_FILE ?= results.xml COCOTB_HDL_TIMEUNIT ?= 1ns COCOTB_HDL_TIMEPRECISION ?= 1ps export COCOTB_RESULTS_FILE $(SIM_BUILD): mkdir -p $@ # Regression rule uses Make dependencies to determine whether to run the simulation .PHONY: regression regression: $(COCOTB_RESULTS_FILE) # Attempt to detect TOPLEVEL_LANG based on available sources if not set ifeq ($(TOPLEVEL_LANG),) ifneq ($(VHDL_SOURCES),) ifeq ($(VERILOG_SOURCES),) TOPLEVEL_LANG := vhdl endif else ifneq ($(VERILOG_SOURCES),) ifeq ($(VHDL_SOURCES),) TOPLEVEL_LANG := verilog endif endif endif define find_libpython_errmsg = find_libpython was not able to find a libpython in the current Python environment. Ensure the Python development packages are installed. If they are installed and find_libpython is not finding the path to libpython, file an upstream bug in find_libpython; then manually override the LIBPYTHON_LOC make variable with the absolute path to libpython.so (or python.dll on Windows). endef ifndef LIBPYTHON_LOC # get the path to libpython and the return code from the script # adapted from https://stackoverflow.com/a/24658961/6614127 FIND_LIBPYTHON_RES := $(shell $(PYTHON_BIN) -m cocotb_tools.config --libpython; echo $$?) FIND_LIBPYTHON_RC := $(lastword $(FIND_LIBPYTHON_RES)) LIBPYTHON_LOC := $(strip $(subst $(FIND_LIBPYTHON_RC)QQQQ,,$(FIND_LIBPYTHON_RES)QQQQ)) # complain if libpython isn't found, and export otherwise ifneq ($(FIND_LIBPYTHON_RC),0) $(error $(find_libpython_errmsg)) endif endif export LIBPYTHON_LOC define check_vhdl_sources if [ "$(VHDL_SOURCES_$(LIB))" == "" ]; then \ >&2 echo "ERROR: VHDL_SOURCES_$(LIB) is empty or undefined, but '$(LIB)' is present in VHDL_LIB_ORDER."; \ exit 1; \ fi; endef define check_lib_order if [ "$(filter $(SOURCES_VAR:VHDL_SOURCES_%=%), $(VHDL_LIB_ORDER))" == "" ]; then \ >&2 echo "ERROR: $(SOURCES_VAR) defined, but library $(SOURCES_VAR:VHDL_SOURCES_%=%) not present in VHDL_LIB_ORDER."; \ exit 1; \ fi; endef # NOTE: if the following simulator list is modified, update the sentence # "This flag is enabled by default for the GHDL, NVC and Verilator simulators." # in docs/source/building.rst accordingly. ifneq ($(filter $(SIM),nvc ghdl verilator),) COCOTB_TRUST_INERTIAL_WRITES ?= 1 else COCOTB_TRUST_INERTIAL_WRITES ?= 0 endif export COCOTB_TRUST_INERTIAL_WRITES # Universal clean:: @$(RM) -rf $(SIM_BUILD) @$(RM) -f $(COCOTB_RESULTS_FILE) # Active-HDL clean:: @$(RM) -rf work @$(RM) -rf wave.asdb # IUS clean:: @$(RM) -rf irun.* @$(RM) -rf ncsim.* @$(RM) -rf gdb_cmd_ncsim # VCS clean:: @$(RM) -rf simv.daidir @$(RM) -rf cm.log @$(RM) -rf ucli.key # Riviera clean:: @$(RM) -rf compile @$(RM) -rf library.cfg @$(RM) -rf dataset.asdb # Verilator clean:: @$(RM) -f dump.vcd @$(RM) -f dump.fst # Xcelium clean:: @$(RM) -rf xrun.* @$(RM) -rf xmsim.* @$(RM) -rf gdb_cmd_xmsim @$(RM) -f qrun* @$(RM) -f visualizer.log @$(RM) -f design.bin @$(RM) -f qwave.db @$(RM) -f transcript # DSim clean:: @$(RM) -rf dsim.* @$(RM) -rf metrics.db @$(RM) -rf file.vcd else $(warning Including Makefile.inc from a user makefile is a no-op and deprecated. Remove the Makefile.inc inclusion from your makefile, and only leave the Makefile.sim include.) endif # COCOTB_MAKEFILE_INC_INCLUDED ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/Makefile.sim0000644000175100017510000000775315106067236022122 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013, 2018 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # This file includes an appropriate makefile depending on the SIM variable. .PHONY: all all: sim # NOTE: keep this at 80 chars. define help_targets = Targets ======= sim Unconditionally re-run the simulator (default) regression Run simulator when dependencies have changes clean Remove build and simulation artefacts help This help text endef # NOTE: keep this at 80 chars. define help_makevars = Variables ========= The following variables are makefile variables: Makefile-based Test Scripts --------------------------- GUI Set this to 1 to enable the GUI mode in the simulator SIM Selects which simulator Makefile to use WAVES Enable wave traces dump for Riviera-PRO and Questa VERILOG_SOURCES A list of the Verilog source files to include VHDL_SOURCES A list of the VHDL source files to include VHDL_SOURCES_ VHDL source files to include in *lib* (GHDL/NVC/ModelSim/Questa/Xcelium/Incisive/Riviera-PRO only) VHDL_LIB_ORDER Compilation order of VHDL libraries (needed for NVC/ModelSim/Questa/Xcelium/Incisive/Riviera-PRO) SIM_CMD_PREFIX Prefix for simulation command invocations COMPILE_ARGS Arguments to pass to compile (analysis) stage of simulation SIM_ARGS Arguments to pass to execution of compiled simulation EXTRA_ARGS Arguments for compile and execute phases COCOTB_PLUSARGS Plusargs to pass to the simulator COCOTB_HDL_TIMEUNIT Default time unit for simulation COCOTB_HDL_TIMEPRECISION Default time precision for simulation CUSTOM_COMPILE_DEPS Add additional dependencies to the compilation target CUSTOM_SIM_DEPS Add additional dependencies to the simulation target SIM_BUILD Define a scratch directory for use by the simulator SCRIPT_FILE Simulator script to run (for e.g. wave traces) endef # NOTE: keep *two* empty lines between "define" and "endef": define newline endef # this ensures we use the same python as the one cocotb was installed into # attempts to use cocotb_config entry script to get that info, falls back to "python" PYTHON_BIN_RES := $(shell cocotb-config --python-bin 2>>/dev/null; echo $$?) PYTHON_BIN_RC := $(lastword $(PYTHON_BIN_RES)) PYTHON_BIN := $(strip $(subst $(PYTHON_BIN_RC)QQQQ,,$(PYTHON_BIN_RES)QQQQ)) ifneq ($(PYTHON_BIN_RC),0) PYTHON_BIN := python3 endif # this cannot be a regular target because of the way Makefile.$(SIM) is included ifeq ($(MAKECMDGOALS),help) $(info $(help_targets)) $(info $(help_makevars)) # hack to get newlines in output, see https://stackoverflow.com/a/54539610 # NOTE: the output of the command must not include a '%' sign, otherwise the formatting will break help_envvars := $(subst %,${newline},$(shell $(PYTHON_BIN) -m cocotb.config --help-vars | tr \\n %)) $(info ${help_envvars}) # is there a cleaner way to exit here? $(error Stopping after printing help) endif include $(shell $(PYTHON_BIN) -m cocotb_tools.config --makefiles)/Makefile.inc # Default to Icarus if no simulator is defined SIM ?= icarus # Maintain backwards compatibility by supporting upper and lower case SIM variable SIM_LOWERCASE := $(shell echo $(SIM) | tr A-Z a-z) HAVE_SIMULATOR = $(shell if [ -f $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.$(SIM_LOWERCASE) ]; then echo 1; else echo 0; fi;) AVAILABLE_SIMULATORS = $(patsubst .%,%,$(suffix $(wildcard $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.*))) ifeq ($(HAVE_SIMULATOR),0) $(error Couldn't find makefile for simulator: "$(SIM_LOWERCASE)"! Available simulators: $(AVAILABLE_SIMULATORS)) endif include $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.$(SIM_LOWERCASE) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3577027 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/0000755000175100017510000000000015106070715022055 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.activehdl0000644000175100017510000000566415106067236025476 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Common Makefile for the Aldec Active-HDL simulator CMD_BIN := vsimsa ifdef ACTIVEHDL_BIN_DIR CMD := $(shell :; command -v $(ACTIVEHDL_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) ACTIVEHDL_BIN_DIR := $(shell dirname $(CMD)) endif ALOG_ARGS += -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) # below allows for maintaining legacy syntax as well as enables using cross-simulator vars COMPILE_ARGS/SIM_ARGS ALOG_ARGS += $(COMPILE_ARGS) ACOM_ARGS += $(COMPILE_ARGS) ASIM_ARGS += $(SIM_ARGS) ifdef RTL_LIBRARY $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.) TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY) else TOPLEVEL_LIBRARY ?= work endif ALOG_ARGS += -dbg ACOM_ARGS += -dbg GPI_EXTRA:= ifeq ($(TOPLEVEL_LANG),verilog) # backslashes needed because we embed in `echo` below GPI_ARGS = -pli \"$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi activehdl)\" ifneq ($(VHDL_SOURCES),) GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi activehdl):cocotbvhpi_entry_point endif else ifeq ($(TOPLEVEL_LANG),vhdl) # backslashes needed because we embed in `echo` below GPI_ARGS = -loadvhpi \"$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi activehdl):vhpi_startup_routines_bootstrap\" ifneq ($(VERILOG_SOURCES),) GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi activehdl):cocotbvpi_entry_point endif else $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG)) endif # Create a DO script (Tcl-like but not fully compatible) based on the list of $(VERILOG_SOURCES) $(SIM_BUILD)/runsim.do : $(VERILOG_SOURCES) $(VHDL_SOURCES) | $(SIM_BUILD) @echo "alib $(TOPLEVEL_LIBRARY)" > $@ @echo "set worklib $(TOPLEVEL_LIBRARY)" >> $@ ifneq ($(VHDL_SOURCES),) @echo "acom $(ACOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES))" >> $@ endif ifneq ($(VERILOG_SOURCES),) @echo "alog $(ALOG_ARGS) $(call to_tcl_path,$(VERILOG_SOURCES))" >> $@ endif @echo "asim $(ASIM_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) +access +w_nets -interceptcoutput $(GPI_ARGS) $(COCOTB_TOPLEVEL) $(EXTRA_TOPS)" >> $@ @echo "run -all" >> $@ @echo "endsim" >> $@ $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/runsim.do $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS) $(RM) $(COCOTB_RESULTS_FILE) set -o pipefail; GPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) $(SIM_CMD_PREFIX) $(CMD) $(RUN_ARGS) -do $(SIM_BUILD)/runsim.do $(SIM_CMD_SUFFIX) $(call check_results) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.cvc0000644000175100017510000000553315106067236024301 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2014 Potential Ventures Ltd # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause ifneq ($(VHDL_SOURCES),) $(COCOTB_RESULTS_FILE): @echo "Skipping simulation as VHDL is not supported on simulator=$(SIM)" debug: $(COCOTB_RESULTS_FILE) else CMD_BIN := cvc64 ifdef CVC_BIN_DIR CMD := $(shell :; command -v $(CVC_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) CVC_BIN_DIR := $(shell dirname $(CMD)) endif #only interpreted mode works for the moment CVC_ITERP ?= 1 ifeq ($(CVC_ITERP),1) CVC_ARGS += +interp endif # Compilation phase $(SIM_BUILD)/sim.vvp: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) | $(SIM_BUILD) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \ COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(CMD) $(CVC_ARGS) +acc+2 -o $(SIM_BUILD)/sim.vvp +loadvpi=$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi cvc):vlog_startup_routines_bootstrap $(COMPILE_ARGS) $(EXTRA_ARGS) $(VERILOG_SOURCES) # Execution phase ifeq ($(CVC_ITERP),1) $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/sim.vvp else $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/sim.vvp $(CUSTOM_SIM_DEPS) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \ COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) $(SIM_BUILD)/sim.vvp $(SIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX) endif # Execution phase ifeq ($(CVC_ITERP),1) debug: $(CUSTOM_SIM_DEPS) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \ COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) gdb --args $(CMD) $(CVC_ARGS) +acc+2 -o $(SIM_BUILD)/sim.vvp +loadvpi=$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi cvc):vlog_startup_routines_bootstrap $(COMPILE_ARGS) $(EXTRA_ARGS) $(VERILOG_SOURCES) else debug: $(SIM_BUILD)/sim.vvp $(CUSTOM_SIM_DEPS) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \ COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ gdb --args $(SIM_BUILD)/sim.vvp $(SIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) endif endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.dsim0000644000175100017510000000271015106067236024454 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause CMD_BIN := dsim ifdef DSIM_BIN_DIR CMD := $(shell :; command -v $(DSIM_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) endif ifeq (, $(CMD)) $(error Unable to locate command >$(CMD_BIN)<) endif ifeq ($(WAVES), 1) WAVE_ARG := -waves file.vcd else WAVE_ARG := endif TOPMODULE_ARG = -top $(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) DSIM_ARGS = -work $(SIM_BUILD) -pli_lib $(shell cocotb-config --lib-name-path vpi dsim) +acc+rwcbfsWF COMP_ARGS = $(DSIM_ARGS) -genimage image -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) RUN_ARGS = $(DSIM_ARGS) -image image $(WAVE_ARG) $(SIM_BUILD)/image.so: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) $(SIM_CMD_PREFIX) $(CMD) $(COMP_ARGS) $(TOPMODULE_ARG) $(EXTRA_ARGS) $(VERILOG_SOURCES) $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/image.so $(CUSTOM_SIM_DEPS) $(RM) $(COCOTB_RESULTS_FILE) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) \ GPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) $(CMD) $(RUN_ARGS) $(TOPMODULE_ARG) $(EXTRA_ARGS) $(VERILOG_SOURCES) $(call check_results) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.ghdl0000644000175100017510000000645015106067236024443 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2014 Potential Ventures Ltd # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause TOPLEVEL_LANG ?= vhdl ifneq ($(or $(filter-out $(TOPLEVEL_LANG),vhdl),$(VERILOG_SOURCES)),) $(COCOTB_RESULTS_FILE): @echo "Skipping simulation as only VHDL is supported on simulator=$(SIM)" else CMD_BIN := ghdl ifdef GHDL_BIN_DIR CMD := $(shell :; command -v $(GHDL_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) GHDL_BIN_DIR := $(shell dirname $(CMD)) endif ifdef RTL_LIBRARY $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.) TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY) else TOPLEVEL_LIBRARY ?= work endif GHDL_ARGS ?= GHDL_ARGS += $(EXTRA_ARGS) # On Windows add GHDL lib folder to PATH to find libraries ifeq ($(OS),Msys) export PATH := $(GHDL_BIN_DIR)/../lib:$(PATH) endif GHDL_RUN_ARGS ?= ifeq ($(shell $(CMD) --version | grep -q mcode; echo $$?),0) ifneq ($(COCOTB_HDL_TIMEPRECISION),) # Convert the time precision to a format string supported by GHDL, if # possible. # GHDL only supports setting the time precision if the mcode backend is # used, using the --time-resolution argument causes GHDL to error out # otherwise. # https://ghdl.github.io/ghdl/using/InvokingGHDL.html#cmdoption-ghdl-time-resolution ifeq ($(COCOTB_HDL_TIMEPRECISION),1fs) GHDL_TIME_RESOLUTION=fs else ifeq ($(COCOTB_HDL_TIMEPRECISION),1ps) GHDL_TIME_RESOLUTION=ps else ifeq ($(COCOTB_HDL_TIMEPRECISION),1us) GHDL_TIME_RESOLUTION=us else ifeq ($(COCOTB_HDL_TIMEPRECISION),1ms) GHDL_TIME_RESOLUTION=ms else ifeq ($(COCOTB_HDL_TIMEPRECISION),1s) GHDL_TIME_RESOLUTION=sec else $(error GHDL only supports the following values for COCOTB_HDL_TIMEPRECISION: 1fs, 1ps, 1us, 1ms, 1s) endif GHDL_RUN_ARGS += --time-resolution=$(GHDL_TIME_RESOLUTION) endif endif .PHONY: analyse # Compilation phase analyse: $(VHDL_SOURCES) $(CUSTOM_COMPILE_DEPS) | $(SIM_BUILD) $(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), \ $(CMD) -i $(GHDL_ARGS) $(COMPILE_ARGS) --workdir=$(SIM_BUILD) --work=$(SOURCES_VAR:VHDL_SOURCES_%=%) $($(SOURCES_VAR)) && ) \ $(CMD) -i $(GHDL_ARGS) $(COMPILE_ARGS) --workdir=$(SIM_BUILD) --work=$(TOPLEVEL_LIBRARY) $(VHDL_SOURCES) && \ $(CMD) -m $(GHDL_ARGS) $(COMPILE_ARGS) --workdir=$(SIM_BUILD) -P$(SIM_BUILD) --work=$(TOPLEVEL_LIBRARY) $(COCOTB_TOPLEVEL) $(ARCH) $(COCOTB_RESULTS_FILE): analyse $(CUSTOM_SIM_DEPS) $(RM) $(COCOTB_RESULTS_FILE) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) $(CMD) -r $(GHDL_ARGS) $(GHDL_RUN_ARGS) --workdir=$(SIM_BUILD) -P$(SIM_BUILD) --work=$(TOPLEVEL_LIBRARY) $(COCOTB_TOPLEVEL) $(ARCH) --vpi=$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi ghdl) $(SIM_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX) $(call check_results) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.icarus0000644000175100017510000000611215106067236025006 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause TOPLEVEL_LANG ?= verilog ifneq ($(or $(filter-out $(TOPLEVEL_LANG),verilog),$(VHDL_SOURCES)),) $(COCOTB_RESULTS_FILE): @echo "Skipping simulation as only Verilog is supported on simulator=$(SIM)" debug: $(COCOTB_RESULTS_FILE) else CMD_BIN := iverilog ifdef ICARUS_BIN_DIR CMD := $(shell :; command -v $(ICARUS_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) ICARUS_BIN_DIR := $(shell dirname $(CMD)) endif ifdef COCOTB_TOPLEVEL TOPMODULE_ARG := -s $(COCOTB_TOPLEVEL) else TOPMODULE_ARG := endif COMPILE_ARGS += -f $(SIM_BUILD)/cmds.f ifdef VERILOG_INCLUDE_DIRS COMPILE_ARGS += $(addprefix -I, $(VERILOG_INCLUDE_DIRS)) endif # Compilation phase ifeq ($(WAVES), 1) VERILOG_SOURCES += $(SIM_BUILD)/cocotb_iverilog_dump.v COMPILE_ARGS += -s cocotb_iverilog_dump FST = -fst else ifeq ($(WAVES),0) # Disable waveform output FST = -none endif $(SIM_BUILD)/sim.vvp: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) | $(SIM_BUILD) @echo "+timescale+$(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION)" > $(SIM_BUILD)/cmds.f $(CMD) -o $(SIM_BUILD)/sim.vvp $(TOPMODULE_ARG) -g2012 $(COMPILE_ARGS) $(EXTRA_ARGS) $(VERILOG_SOURCES) $(SIM_BUILD)/cocotb_iverilog_dump.v: | $(SIM_BUILD) @echo 'module cocotb_iverilog_dump();' > $@ @echo 'initial begin' >> $@ @echo ' $$dumpfile("$(SIM_BUILD)/$(COCOTB_TOPLEVEL).fst");' >> $@ @echo ' $$dumpvars(0, $(COCOTB_TOPLEVEL));' >> $@ @echo 'end' >> $@ @echo 'endmodule' >> $@ # Execution phase $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/sim.vvp $(CUSTOM_SIM_DEPS) $(RM) $(COCOTB_RESULTS_FILE) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) $(ICARUS_BIN_DIR)/vvp -M $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-dir) -m $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name vpi icarus) $(SIM_ARGS) $(EXTRA_ARGS) $(SIM_BUILD)/sim.vvp $(FST) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX) $(call check_results) debug: $(SIM_BUILD)/sim.vvp $(CUSTOM_SIM_DEPS) $(RM) -r $(COCOTB_RESULTS_FILE) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) gdb --args $(ICARUS_BIN_DIR)/vvp -M $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-dir) -m $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name vpi icarus) $(SIM_ARGS) $(EXTRA_ARGS) $(SIM_BUILD)/sim.vvp $(FST) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX) $(call check_results) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.ius0000644000175100017510000000676415106067236024335 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Common Makefile for Cadence Incisive CMD_BIN := irun ifdef IUS_BIN_DIR CMD := $(shell :; command -v $(IUS_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) IUS_BIN_DIR := $(shell dirname $(CMD)) endif ifdef VERILOG_INCLUDE_DIRS COMPILE_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS)) endif EXTRA_ARGS += $(COMPILE_ARGS) EXTRA_ARGS += $(SIM_ARGS) EXTRA_ARGS += -licqueue ifeq ($(PYTHON_ARCH),64bit) EXTRA_ARGS += -64 endif EXTRA_ARGS += -nclibdirpath $(SIM_BUILD) EXTRA_ARGS += -plinowarn ifeq ($(GUI),1) EXTRA_ARGS += -gui else EXTRA_ARGS += endif # IUS errors out if multiple timescales are specified on the command line. ifneq (,$(findstring timescale,$(EXTRA_ARGS))) $(error Please use COCOTB_HDL_TIMEUNIT and COCOTB_HDL_TIMEPRECISION to specify timescale.) endif # Loading the VHPI library causes an error, so we always load the VPI library and supply # GPI_EXTRA=$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi ius) if needed. # Xcelium will use default vlog_startup_routines symbol only if vpi library name is libvpi.so GPI_ARGS = -loadvpi $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi ius):vlog_startup_routines_bootstrap ifeq ($(TOPLEVEL_LANG),verilog) EXTRA_ARGS += -v93 HDL_SOURCES = $(VERILOG_SOURCES) ROOT_LEVEL = $(COCOTB_TOPLEVEL) ifneq ($(VHDL_SOURCES),) HDL_SOURCES += $(VHDL_SOURCES) GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi ius):cocotbvhpi_entry_point endif else ifeq ($(TOPLEVEL_LANG),vhdl) GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi ius):cocotbvhpi_entry_point EXTRA_ARGS += -v93 EXTRA_ARGS += -top $(COCOTB_TOPLEVEL) ifdef RTL_LIBRARY $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.) TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY) else TOPLEVEL_LIBRARY ?= work endif MAKE_LIB = -makelib $(TOPLEVEL_LIBRARY) HDL_SOURCES = $(VHDL_SOURCES) ifneq ($(VERILOG_SOURCES),) HDL_SOURCES += $(VERILOG_SOURCES) endif else $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG)) endif # Builds a list of arguments to support VHDL libraries specified in VHDL_SOURCES_*: LIBS := $(foreach LIB, $(VHDL_LIB_ORDER),-makelib $(LIB) $(VHDL_SOURCES_$(LIB)) -endlib) $(COCOTB_RESULTS_FILE): $(HDL_SOURCES) $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS) | $(SIM_BUILD) $(RM) $(COCOTB_RESULTS_FILE) # Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa $(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources)) $(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order)) set -o pipefail; \ COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) GPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) $(CMD) -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) \ $(EXTRA_ARGS) $(GPI_ARGS) +access+rwc $(LIBS) $(MAKE_LIB) $(HDL_SOURCES) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX) $(call check_results) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.modelsim0000644000175100017510000000053215106067236025331 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Identical to Questa with the compat flow. include $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.questa-compat ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.nvc0000644000175100017510000000502715106067236024312 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause ifneq ($(VERILOG_SOURCES),) $(COCOTB_RESULTS_FILE): @echo "Skipping simulation as Verilog is not supported on simulator=$(SIM)" else CMD_BIN := nvc ifdef NVC_BIN_DIR CMD := $(shell :; command -v $(NVC_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) NVC_BIN_DIR := $(shell dirname $(CMD)) endif PRESERVE_CASE := $(shell $(CMD) --version | $(PYTHON_BIN) -c "from cocotb_tools.sim_versions import NvcVersion; import sys; print('--preserve-case' if NvcVersion.from_commandline(sys.stdin.read()) > NvcVersion('1.16') else '')") ifdef RTL_LIBRARY $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.) TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY) else TOPLEVEL_LIBRARY ?= work endif .PHONY: analyse # Split SIM_ARGS into those options that need to be passed to -e and # those that need to be passed to -r NVC_E_FILTER := -g% --cover --cover=% NVC_E_ARGS := $(filter $(NVC_E_FILTER),$(SIM_ARGS)) NVC_R_ARGS := $(filter-out $(NVC_E_FILTER),$(SIM_ARGS)) # Compilation phase analyse: $(VHDL_SOURCES) $(SIM_BUILD) $(CUSTOM_COMPILE_DEPS) # Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa $(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources)) $(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order)) $(foreach LIB_VAR,$(VHDL_LIB_ORDER), \ $(CMD) $(EXTRA_ARGS) --work=$(LIB_VAR):$(SIM_BUILD)/$(LIB_VAR) -L $(SIM_BUILD) -a $(VHDL_SOURCES_$(LIB_VAR)) $(PRESERVE_CASE) $(COMPILE_ARGS) && ) \ $(CMD) $(EXTRA_ARGS) --work=$(TOPLEVEL_LIBRARY):$(SIM_BUILD)/$(TOPLEVEL_LIBRARY) -L $(SIM_BUILD) -a $(VHDL_SOURCES) $(PRESERVE_CASE) $(COMPILE_ARGS) $(COCOTB_RESULTS_FILE): analyse $(CUSTOM_SIM_DEPS) $(RM) $(COCOTB_RESULTS_FILE) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) $(CMD) $(EXTRA_ARGS) --work=$(TOPLEVEL_LIBRARY):$(SIM_BUILD)/$(TOPLEVEL_LIBRARY) -L $(SIM_BUILD) \ -e $(COCOTB_TOPLEVEL) --no-save $(NVC_E_ARGS) \ -r --load $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi nvc) $(TRACE) $(NVC_R_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX) $(call check_results) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.questa0000644000175100017510000000270315106067236025024 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Detect the version of Questa in use to choose the best flow. CMD_BIN := vsim ifdef MODELSIM_BIN_DIR CMD := $(shell :; command -v $(MODELSIM_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) endif # Determine the version of Questa being used. QUESTA_VERSION := $(shell $(CMD) -version | $(PYTHON_BIN) -c 'import re,sys; print(re.sub(r".+vsim (\d+)\.(\d).+", "\\1 \\2", sys.stdin.read()))') QUESTA_VERSION_MAJOR := $(firstword $(QUESTA_VERSION)) QUESTA_VERSION_MINOR := $(lastword $(QUESTA_VERSION)) # Use the QIS/Qrun flow for Questa >= 2025.2 (the first version which fully # passes the cocotb regression suite). Use the compat flow otherwise. ifeq ($(shell test $(QUESTA_VERSION_MAJOR)$(QUESTA_VERSION_MINOR) -lt 20252; echo $$?),0) $(info Using the Questa compat flow for Questa version $(QUESTA_VERSION_MAJOR).$(QUESTA_VERSION_MINOR) < 2025.2. Run make with SIM=questa-qisqrun to force the newer QIS/Qrun flow.) include $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.questa-compat else $(info Using the Questa QIS/Qrun flow for Questa $(QUESTA_VERSION_MAJOR).$(QUESTA_VERSION_MINOR) >= 2025.2. Run make with SIM=questa-compat for the compat flow.) include $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.questa-qisqrun endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.questa-compat0000644000175100017510000001163615106067236026312 0ustar00runnerrunner# Copyright (c) 2013, 2018 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Questa compatibility flow using the vlog and vsim commands with the +acc # switch for design access. CMD_BIN := vsim ifdef MODELSIM_BIN_DIR CMD := $(shell :; command -v $(MODELSIM_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) MODELSIM_BIN_DIR := $(shell dirname $(CMD)) endif ifdef RTL_LIBRARY $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.) TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY) else TOPLEVEL_LIBRARY ?= work endif COCOTB_TOPLEVEL := "$(TOPLEVEL_LIBRARY).$(COCOTB_TOPLEVEL)" ifndef VLOG_ARGS VLOG_ARGS = -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) -mfcu endif COMPILE_ARGS += +acc ifdef VERILOG_INCLUDE_DIRS VLOG_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS)) endif # below allows for maintaining legacy syntax as well as enables using cross-simulator vars COMPILE_ARGS/SIM_ARGS VLOG_ARGS += $(COMPILE_ARGS) VCOM_ARGS += $(COMPILE_ARGS) VSIM_ARGS += $(SIM_ARGS) ifeq ($(GUI),1) CMD += -gui VSIM_ARGS += -onfinish stop else CMD += -c VSIM_ARGS += -onfinish exit endif FLI_LIB := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path fli questa) VHPI_LIB := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi questa) GPI_EXTRA := VHDL_GPI_INTERFACE ?= fli ifeq ($(filter vhpi fli,$(VHDL_GPI_INTERFACE)),) $(error A valid value (fli or vhpi) was not provided for VHDL_GPI_INTERFACE=$(VHDL_GPI_INTERFACE)) endif ifeq ($(TOPLEVEL_LANG),vhdl) VSIM_ARGS += -t $(COCOTB_HDL_TIMEPRECISION) ifeq ($(VHDL_GPI_INTERFACE),fli) CUSTOM_COMPILE_DEPS += $(FLI_LIB) VSIM_ARGS += -foreign \"cocotb_init $(FLI_LIB)\" else VSIM_ARGS += -voptargs="-access=rw+/." -foreign \"vhpi_startup_routines_bootstrap $(call to_tcl_path,$(VHPI_LIB))\" endif ifneq ($(VERILOG_SOURCES),) GPI_EXTRA := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi questa):cocotbvpi_entry_point endif else ifeq ($(TOPLEVEL_LANG),verilog) VSIM_ARGS += -pli $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi questa) ifneq ($(VHDL_SOURCES),) GPI_EXTRA := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path $(VHDL_GPI_INTERFACE) questa):cocotb$(VHDL_GPI_INTERFACE)_entry_point endif else $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG)) endif define make_lib echo "if [file exists $(SIM_BUILD)/$(LIB)] {vdel -lib $(SIM_BUILD)/$(LIB) -all}" >> $@; echo "vlib $(SIM_BUILD)/$(LIB)" >> $@; echo "vmap $(LIB) $(SIM_BUILD)/$(LIB)" >> $@; echo "vcom -work $(LIB) $(VCOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES_$(LIB)))" >> $@; endef $(SIM_BUILD)/runsim.do : $(VHDL_SOURCES) $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS) | $(SIM_BUILD) # Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa $(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources)) $(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order)) @echo "# Autogenerated file" > $@ @echo "onerror {" >> $@ @echo " quit -f -code 1" >> $@ @echo "}" >> $@ @echo "vmap -c" >> $@ $(foreach LIB, $(VHDL_LIB_ORDER), $(make_lib)) @echo "if [file exists $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)] {vdel -lib $(SIM_BUILD)/$(TOPLEVEL_LIBRARY) -all}" >> $@ @echo "vlib $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)" >> $@ @echo "vmap $(TOPLEVEL_LIBRARY) $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)" >> $@ ifneq ($(VHDL_SOURCES),) @echo "vcom -work $(TOPLEVEL_LIBRARY) $(VCOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES))" >> $@ endif ifneq ($(VERILOG_SOURCES),) @echo "vlog -work $(TOPLEVEL_LIBRARY) -sv $(VLOG_ARGS) $(EXTRA_ARGS) $(call to_tcl_path,$(VERILOG_SOURCES))" >> $@ endif ifdef SCRIPT_FILE @echo "do $(SCRIPT_FILE)" >> $@ endif @echo "vsim $(VSIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(COCOTB_TOPLEVEL)" >> $@ ifeq ($(WAVES),1) @echo "log -recursive /*" >> $@ endif ifeq ($(GUI),1) @echo "add log -r *" >> $@ else @echo "onbreak resume" >> $@ @echo "run -all" >> $@ @echo "quit" >> $@ endif ifeq ($(PYTHON_ARCH),64bit) CMD += -64 endif $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/runsim.do $(RM) $(COCOTB_RESULTS_FILE) set -o pipefail; \ COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \ COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) \ COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) \ COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) \ GPI_EXTRA=$(GPI_EXTRA) \ TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ VHDL_GPI_INTERFACE=$(VHDL_GPI_INTERFACE) \ COCOTB__QUESTA_MODE=compat \ $(SIM_CMD_PREFIX) $(CMD) $(RUN_ARGS) -do $(SIM_BUILD)/runsim.do $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX) $(call check_results) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.questa-qisqrun0000644000175100017510000001140415106067236026522 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Questa QIS/Qrun flow using the Questa Information System (QIS) for design # access and qrun to build and run the simulation. QRUN_BIN := qrun VIS_BIN := vis ifdef MODELSIM_BIN_DIR QRUN_CMD := $(shell :; command -v $(MODELSIM_BIN_DIR)/$(QRUN_BIN) 2>/dev/null) VIS_CMD := $(shell :; command -v $(MODELSIM_BIN_DIR)/$(VIS_BIN) 2>/dev/null) else # auto-detect bin dir from system path QRUN_CMD := $(shell :; command -v $(QRUN_BIN) 2>/dev/null) VIS_CMD := $(shell :; command -v $(VIS_BIN) 2>/dev/null) endif ifeq (,$(QRUN_CMD)) $(error Unable to locate command >$(QRUN_BIN)<) endif ifeq (,$(VIS_CMD)) $(error Unable to locate command >$(VIS_BIN)<) endif DESIGNFILE ?= design.bin WAVEFILE ?= qwave.db TOPLEVEL_LIBRARY ?= work COCOTB_TOPLEVEL := "$(TOPLEVEL_LIBRARY).$(COCOTB_TOPLEVEL)" ifndef VLOG_ARGS VLOG_ARGS = -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) -mfcu endif ifdef VERILOG_INCLUDE_DIRS VLOG_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS)) endif # below allows for maintaining legacy syntax as well as enables using cross-simulator vars COMPILE_ARGS/SIM_ARGS VLOG_ARGS += $(COMPILE_ARGS) VCOM_ARGS += VOPT_ARGS += -access=rw+/. VSIM_ARGS += $(SIM_ARGS) ifdef GUI # Run in GUI mode. # Two modes are supported: # - GUI=livesim: Open the Visualizer GUI before running the simulation. # GUI=1 is a backwards-compatible alias for livesim. # - GUI=postsim: Open the Visualizer GUI after the simulation has finished. ifeq ($(filter livesim postsim 1,$(GUI)),) $(error A valid value (livesim, postsim, or 1) was not provided for GUI=$(GUI)) endif # Map GUI=1 to GUI=livesim. ifeq ($(GUI),1) GUI := livesim endif VOPT_ARGS += -designfile $(DESIGNFILE) VSIM_ARGS += -onfinish stop -qwavedb=+signal+memory=all+class+assertion+uvm_schematic+msg+wavefile=$(WAVEFILE) ifeq ($(GUI),livesim) QRUN_CMD += -gui -visualizer VOPT_ARGS += -debug,livesim endif # For GUI=postsim Visualizer is called in the $(COCOTB_RESULTS_FILE) target. else # Run in batch mode (no GUI). QRUN_CMD += -c VSIM_ARGS += -onfinish exit endif # ifdef GUI FLI_LIB := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path fli questa) VHPI_LIB := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi questa) GPI_EXTRA := VHDL_GPI_INTERFACE ?= fli ifeq ($(filter vhpi fli,$(VHDL_GPI_INTERFACE)),) $(error A valid value (fli or vhpi) was not provided for VHDL_GPI_INTERFACE=$(VHDL_GPI_INTERFACE)) endif ifeq ($(TOPLEVEL_LANG),vhdl) VSIM_ARGS += -t $(COCOTB_HDL_TIMEPRECISION) ifeq ($(VHDL_GPI_INTERFACE),fli) CUSTOM_COMPILE_DEPS += $(FLI_LIB) VSIM_ARGS += -foreign "cocotb_init $(FLI_LIB)" else VSIM_ARGS += -foreign "vhpi_startup_routines_bootstrap $(call to_tcl_path,$(VHPI_LIB))" endif ifneq ($(VERILOG_SOURCES),) GPI_EXTRA := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi questa):cocotbvpi_entry_point endif else ifeq ($(TOPLEVEL_LANG),verilog) VSIM_ARGS += -pli $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi questa) ifneq ($(VHDL_SOURCES),) GPI_EXTRA := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path $(VHDL_GPI_INTERFACE) questa):cocotb$(VHDL_GPI_INTERFACE)_entry_point endif else $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG)) endif ifdef SCRIPT_FILE VSIM_ARGS += -do $(SCRIPT_FILE) endif ifeq ($(PYTHON_ARCH),64bit) QRUN_CMD += -64 endif define make_lib -makelib $(LIB) $(VHDL_SOURCES_$(LIB)) -end endef $(COCOTB_RESULTS_FILE): # Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa $(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources)) $(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order)) $(RM) $(COCOTB_RESULTS_FILE) mkdir -p $(SIM_BUILD) set -o pipefail; \ COCOTB_TEST_MODULES=$(COCOTB_TEST_MODULES) \ COCOTB_TESTCASE=$(COCOTB_TESTCASE) \ COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) \ COCOTB_TOPLEVEL=$(COCOTB_TOPLEVEL) \ GPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ VHDL_GPI_INTERFACE=$(VHDL_GPI_INTERFACE) \ COCOTB__QUESTA_MODE=qisqrun \ $(SIM_CMD_PREFIX) $(QRUN_CMD) $(RUN_ARGS) -outdir $(SIM_BUILD) \ $(foreach LIB, $(VHDL_LIB_ORDER), $(make_lib)) \ -makelib $(TOPLEVEL_LIBRARY) $(VERILOG_SOURCES) $(VHDL_SOURCES) $(VLOG_ARGS) $(VCOM_ARGS) -end \ $(VOPT_ARGS) $(VSIM_ARGS) $(EXTRA_ARGS) $(COCOTB_PLUSARGS) -sv \ -top $(COCOTB_TOPLEVEL) 2>&1 | tee $(SIM_BUILD)/sim.log ifeq ($(GUI),postsim) $(VIS_CMD) -designfile $(DESIGNFILE) -wavefile $(WAVEFILE) endif $(call check_results) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.riviera0000644000175100017510000001234715106067236025170 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Common Makefile for Aldec Riviera-PRO simulator ifeq ($(GUI),1) CMD_BIN := riviera else CMD_BIN := vsimsa endif ifdef ALDEC_BIN_DIR CMD := $(shell :; command -v $(ALDEC_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) ALDEC_BIN_DIR := $(shell dirname $(CMD)) endif ifeq ($(GUI),1) CMD += -nosplash endif ALOG_ARGS += -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) ifdef VERILOG_INCLUDE_DIRS ALOG_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS)) endif # below allows for maintaining legacy syntax as well as enables using cross-simulator vars COMPILE_ARGS/SIM_ARGS ALOG_ARGS += $(COMPILE_ARGS) ACOM_ARGS += $(COMPILE_ARGS) ASIM_ARGS += $(SIM_ARGS) # Plusargs need to be passed to ASIM command not vsimsa ASIM_ARGS += $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) ifdef RTL_LIBRARY $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.) TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY) else TOPLEVEL_LIBRARY ?= work endif # Pass the VPI library to the Verilog compilation to get extended checking. ALOG_ARGS += -pli $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi riviera) # Aldec-specific coverage types: # - (s)tatement # - (b)ranch # - (e)xpression # - (c)ondition # - (a)ssertion # - (p)ath # - finite state (m)achine # Documentation: Riviera Pro 2017.02 Documentation - Page 359 COVERAGE_TYPES ?= sb ifeq ($(COCOTB_USER_COVERAGE),1) ALOG_ARGS += -dbg -coverage $(COVERAGE_TYPES) ACOM_ARGS += -dbg -coverage $(COVERAGE_TYPES) ASIM_ARGS += -dbg -acdb -acdb_cov $(COVERAGE_TYPES) endif GPI_EXTRA:= ifeq ($(TOPLEVEL_LANG),verilog) GPI_ARGS = -pli $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi riviera) ifneq ($(VHDL_SOURCES),) GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi riviera):cocotbvhpi_entry_point endif else ifeq ($(TOPLEVEL_LANG),vhdl) GPI_ARGS = -loadvhpi $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi riviera):vhpi_startup_routines_bootstrap ifneq ($(VERILOG_SOURCES),) GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi riviera):cocotbvpi_entry_point endif else $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG)) endif define make_lib echo "if [file exists $(SIM_BUILD)/$(LIB)] {adel -lib $(SIM_BUILD)/$(LIB) -all}" >> $@; echo "alib $(SIM_BUILD)/$(LIB)" >> $@; echo "amap $(LIB) $(SIM_BUILD)/$(LIB)" >> $@; echo "acom -work $(LIB) $(ACOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES_$(LIB)))" >> $@; endef # Create a TCL script based on the list of $(VERILOG_SOURCES) $(SIM_BUILD)/runsim.tcl : $(VERILOG_SOURCES) $(VHDL_SOURCES) | $(SIM_BUILD) @echo "onerror {" > $@ @echo " puts [read [open sim.log r]]" >> $@ @echo " quit -code 1" >> $@ @echo "}" >> $@ @echo "amap -c" >> $@ $(foreach LIB, $(VHDL_LIB_ORDER), $(make_lib)) @echo "@if [string length [array get env LICENSE_QUEUE]] {" >> $@ @echo " set LICENSE_QUEUE $$::env(LICENSE_QUEUE)" >> $@ @echo "}" >> $@ @echo "if [file exists $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)] {adel -lib $(SIM_BUILD)/$(TOPLEVEL_LIBRARYRTL_LIBRARY) -all}" >> $@; @echo "alib $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)" >> $@ @echo "amap $(TOPLEVEL_LIBRARY) $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)" >> $@; @echo "set worklib $(TOPLEVEL_LIBRARY)" >> $@; ifneq ($(VHDL_SOURCES),) @echo "acom -work $(TOPLEVEL_LIBRARY) $(ACOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES))" >> $@ endif ifneq ($(VERILOG_SOURCES),) @echo "alog -work $(TOPLEVEL_LIBRARY) $(ALOG_ARGS) $(call to_tcl_path,$(VERILOG_SOURCES))" >> $@ endif ifdef SCRIPT_FILE @echo "do $(SCRIPT_FILE)" >> $@ endif ifneq ($(CFG_TOPLEVEL),) @echo "asim $(ASIM_ARGS) +access +w_nets -interceptcoutput $(GPI_ARGS) $(CFG_TOPLEVEL) $(EXTRA_TOPS)" >> $@ else @echo "asim $(ASIM_ARGS) +access +w_nets -interceptcoutput $(GPI_ARGS) $(COCOTB_TOPLEVEL) $(EXTRA_TOPS)" >> $@ endif ifeq ($(WAVES),1) @echo "log -recursive *" >> $@ endif ifeq ($(GUI),1) @echo "wave -rec *" >> $@ else @echo "run -all" >> $@ @echo "endsim" >> $@ ifeq ($(COCOTB_USER_COVERAGE),1) @echo "acdb report -cov $(COVERAGE_TYPES) -db $(TOPLEVEL_LIBRARY).acdb -html -o coverage/acdb_report.html" >> $@ @echo "acdb report -cov $(COVERAGE_TYPES) -db $(TOPLEVEL_LIBRARY).acdb -txt -o coverage/acdb_report.txt" >> $@ endif @echo "exit" >> $@ endif # Note it's the redirection of the output rather than the 'do' command # that turns on batch mode (i.e. exit on completion/error) $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/runsim.tcl $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS) $(RM) $(COCOTB_RESULTS_FILE) set -o pipefail; GPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) $(SIM_CMD_PREFIX) $(CMD) $(RUN_ARGS) -do $(SIM_BUILD)/runsim.tcl $(SIM_CMD_SUFFIX) $(call check_results) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.vcs0000644000175100017510000000415215106067236024315 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause ifneq ($(VHDL_SOURCES),) $(COCOTB_RESULTS_FILE): @echo "Skipping simulation as VHDL is not supported on simulator=$(SIM)" else CMD_BIN := vcs ifdef VCS_BIN_DIR CMD := $(shell :; command -v $(VCS_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) VCS_BIN_DIR := $(shell dirname $(CMD)) endif ifdef VERILOG_INCLUDE_DIRS COMPILE_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS)) endif ifeq ($(PYTHON_ARCH),64bit) COMPILE_ARGS += -full64 endif ifeq ($(GUI),1) EXTRA_ARGS += -gui -kdb endif # Avoid linker "undefined reference to" error COMPILE_ARGS += -LDFLAGS -Wl,--no-as-needed # Enables globally access for read, write, and callback capabilities. COMPILE_ARGS += +acc+3 # Enables globally debug capabilities. COMPILE_ARGS += -debug_access+all # TODO: # investigate +vpi+1 option which reduces memory requirements # Compilation phase $(SIM_BUILD)/simv: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) | $(SIM_BUILD) cd $(SIM_BUILD) && \ COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) \ $(CMD) -top $(COCOTB_TOPLEVEL) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) -sverilog \ -timescale=$(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) \ $(EXTRA_ARGS) -load $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi vcs) $(COMPILE_ARGS) $(VERILOG_SOURCES) # Execution phase $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/simv $(CUSTOM_SIM_DEPS) $(RM) $(COCOTB_RESULTS_FILE) COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) $(SIM_BUILD)/simv $(SIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX) $(call check_results) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.verilator0000644000175100017510000000527715106067236025542 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause TOPLEVEL_LANG ?= verilog ifneq ($(or $(filter-out $(TOPLEVEL_LANG),verilog),$(VHDL_SOURCES)),) results.xml: @echo "Skipping simulation as only Verilog is supported on simulator=$(SIM)" debug: results.xml else CMD_BIN := verilator ifdef VERILATOR_BIN_DIR CMD := $(shell :; command -v $(VERILATOR_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) VERILATOR_BIN_DIR := $(shell dirname $(CMD)) endif VLT_MIN := 5.036 VLT_VERSION := $(shell $(CMD) --version | cut -d " " -f 2) MIN_VERSION := $(shell printf "%s\n%s\n" "$(VLT_MIN)" "$(VLT_VERSION)" | sort -g | head -1) ifneq ($(MIN_VERSION),$(VLT_MIN)) $(error cocotb requires Verilator $(VLT_MIN) or later, but using $(VLT_VERSION)) endif ifdef COCOTB_TOPLEVEL TOPMODULE_ARG := --top-module $(COCOTB_TOPLEVEL) else TOPMODULE_ARG := endif ifeq ($(VERILATOR_SIM_DEBUG), 1) COMPILE_ARGS += --debug -CFLAGS "-DVL_DEBUG -DVERILATOR_SIM_DEBUG -g -Og" DEBUG = +verilator+debug BUILD_ARGS += OPT_FAST=-Og OPT_SLOW=-Og OPT_GLOBAL=-Og endif ifeq ($(VERILATOR_TRACE),1) COMPILE_ARGS += --trace --trace-structs SIM_ARGS += --trace endif COMPILE_ARGS += --timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) _COCOTB_LIB_DIR = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-dir) COMPILE_ARGS += --vpi --public-flat-rw --prefix Vtop -o Vtop -LDFLAGS "-Wl,-rpath,$(_COCOTB_LIB_DIR) -L$(_COCOTB_LIB_DIR) -lcocotbvpi_verilator" ifdef VERILOG_INCLUDE_DIRS COMPILE_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS)) endif VERILATOR_CPP := $(shell $(PYTHON_BIN) -m cocotb_tools.config --share)/lib/verilator/verilator.cpp $(SIM_BUILD)/Vtop.mk: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) $(VERILATOR_CPP) | $(SIM_BUILD) $(CMD) -cc --exe -Mdir $(SIM_BUILD) $(TOPMODULE_ARG) $(COMPILE_ARGS) $(EXTRA_ARGS) $(VERILOG_SOURCES) $(VERILATOR_CPP) # Compilation phase $(SIM_BUILD)/Vtop: $(SIM_BUILD)/Vtop.mk $(MAKE) -C $(SIM_BUILD) $(BUILD_ARGS) -f Vtop.mk $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/Vtop $(CUSTOM_SIM_DEPS) $(RM) $(COCOTB_RESULTS_FILE) -COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) $< $(SIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(DEBUG) $(SIM_CMD_SUFFIX) $(call check_results) debug: $(MAKE) VERILATOR_SIM_DEBUG=1 SIM_CMD_PREFIX="gdb --args" $(COCOTB_RESULTS_FILE) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/makefiles/simulators/Makefile.xcelium0000644000175100017510000001023215106067236025164 0ustar00runnerrunner# Copyright cocotb contributors # Copyright (c) 2013, 2018 Potential Ventures Ltd # Copyright (c) 2013 SolarFlare Communications Inc # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # Common Makefile for Cadence Xcelium CMD_BIN := xrun ifdef XCELIUM_BIN_DIR CMD := $(shell :; command -v $(XCELIUM_BIN_DIR)/$(CMD_BIN) 2>/dev/null) else # auto-detect bin dir from system path CMD := $(shell :; command -v $(CMD_BIN) 2>/dev/null) XCELIUM_BIN_DIR := $(shell dirname $(CMD)) endif ifdef VERILOG_INCLUDE_DIRS COMPILE_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS)) endif EXTRA_ARGS += $(COMPILE_ARGS) EXTRA_ARGS += $(SIM_ARGS) EXTRA_ARGS += -licqueue ifeq ($(PYTHON_ARCH),64bit) EXTRA_ARGS += -64 endif EXTRA_ARGS += -xmlibdirpath $(SIM_BUILD) ifeq ($(DEBUG),1) EXTRA_ARGS += -pliverbose EXTRA_ARGS += -messages EXTRA_ARGS += -plidebug # Enhance the profile output with PLI info EXTRA_ARGS += -plierr_verbose # Expand handle info in PLI/VPI/VHPI messages EXTRA_ARGS += -vpicompat 1800v2005 # <1364v1995|1364v2001|1364v2005|1800v2005> Specify the IEEE VPI else EXTRA_ARGS += -plinowarn endif ifeq ($(GUI),1) EXTRA_ARGS += -gui else EXTRA_ARGS += endif # Xcelium errors out if multiple timescales are specified on the command line. ifneq (,$(filter -timescale%,$(EXTRA_ARGS))) $(error Please use COCOTB_HDL_TIMEUNIT and COCOTB_HDL_TIMEPRECISION to specify timescale.) endif # Loading the VHPI library causes an error, so we always load the VPI library and supply # GPI_EXTRA=$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi xcelium) if needed. # Xcelium will use default vlog_startup_routines symbol only if VPI library name is libvpi.so GPI_ARGS = -loadvpi $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi xcelium):vlog_startup_routines_bootstrap ifeq ($(TOPLEVEL_LANG),verilog) HDL_SOURCES = $(VERILOG_SOURCES) ROOT_LEVEL = $(COCOTB_TOPLEVEL) EXTRA_ARGS += -top $(COCOTB_TOPLEVEL) ifneq ($(VHDL_SOURCES),) HDL_SOURCES += $(VHDL_SOURCES) GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi xcelium):cocotbvhpi_entry_point endif else ifeq ($(TOPLEVEL_LANG),vhdl) GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi xcelium):cocotbvhpi_entry_point EXTRA_ARGS += -top $(COCOTB_TOPLEVEL) # Xcelium 23.09.004 fixes cocotb issue #1076 as long as the following define # is set. EXTRA_ARGS += -NEW_VHPI_PROPAGATE_DELAY ifdef RTL_LIBRARY $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.) TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY) else TOPLEVEL_LIBRARY ?= work endif MAKE_LIB = -makelib $(TOPLEVEL_LIBRARY) END_LIB = -endlib HDL_SOURCES = $(VHDL_SOURCES) ifneq ($(VERILOG_SOURCES),) HDL_SOURCES += $(VERILOG_SOURCES) endif else $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG)) endif # Builds a list of arguments to support VHDL libraries specified in VHDL_SOURCES_*: LIBS := $(foreach LIB, $(VHDL_LIB_ORDER),-makelib $(LIB) $(VHDL_SOURCES_$(LIB)) -endlib) $(COCOTB_RESULTS_FILE): $(HDL_SOURCES) $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS) | $(SIM_BUILD) $(RM) $(COCOTB_RESULTS_FILE) # Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa $(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources)) $(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order)) set -o pipefail; \ COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) GPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \ $(SIM_CMD_PREFIX) $(CMD) -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) \ -vhdl_time_precision "$(COCOTB_HDL_TIMEPRECISION)" \ $(EXTRA_ARGS) $(GPI_ARGS) $(INCDIRS) -access +rwc -createdebugdb $(LIBS) $(MAKE_LIB) $(HDL_SOURCES) $(END_LIB) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX) $(call check_results) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/py.typed0000644000175100017510000000000015106067236017404 0ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/runner.py0000644000175100017510000021610215106067236017604 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause """Build HDL and run cocotb tests.""" # TODO: maybe do globbing and expanduser/expandvars in --include, --vhdl-sources, --verilog-sources # TODO: create a short README and a .gitignore (content: "*") in both build_dir and test_dir? (Some other tools do this.) # TODO: support timescale on all simulators # TODO: support custom dependencies import logging import multiprocessing import os import re import shlex import shutil import subprocess import sys import tempfile import warnings from abc import ABC, abstractmethod from contextlib import suppress from itertools import chain from pathlib import Path from typing import ( Dict, Generic, Iterable, List, Mapping, Optional, Sequence, TextIO, Tuple, Type, TypeVar, Union, ) import find_libpython import cocotb_tools.config from cocotb_tools.check_results import get_results from cocotb_tools.sim_versions import NvcVersion if sys.version_info >= (3, 10): from typing import TypeAlias PathLike: "TypeAlias" = Union["os.PathLike[str]", str] "A path that can be passed to :class:`pathlib.Path` or :func:`open`" _Command: "TypeAlias" = List[str] _magic_re = re.compile(r"([\\{}])") _space_re = re.compile(r"([\s])", re.ASCII) MAX_PARALLEL_BUILD_JOBS: int = 4 """The maximum number of parallel build threads in calls to :meth:`.Runner.build`. If the number of CPU cores is less than this value, it uses the CPU core count. Set this variable to globally change the number of parallel build jobs. """ def _get_max_parallel_build_jobs() -> int: return min(MAX_PARALLEL_BUILD_JOBS, multiprocessing.cpu_count()) def _as_tcl_value(value: str) -> str: # add '\' before special characters and spaces value = _magic_re.sub(r"\\\1", value) value = value.replace("\n", r"\n") value = _space_re.sub(r"\\\1", value) if value[:1] == '"': value = "\\" + value return value _sv_escapes = { "\n": "\\n", "\t": "\\t", "\\": "\\\\", '"': '\\"', "\v": "\\v", "\f": "\\f", "\xff": "\\xFF", } for i in range(32): if chr(i) not in _sv_escapes: _sv_escapes[chr(i)] = f"\\x{i:02x}" _sv_escape_translate_table = str.maketrans(_sv_escapes) def _as_sv_literal(value: object) -> str: if isinstance(value, (int, float)): return str(value) elif isinstance(value, str): return '"' + value.translate(_sv_escape_translate_table) + '"' else: raise TypeError("Can't serialize this type as an SV literal") def _shlex_join(split_command: Iterable[str]) -> str: """ Return a shell-escaped string from *split_command* This is here more for compatibility purposes """ return " ".join(shlex.quote(arg) for arg in split_command) _T = TypeVar("_T") class _Tag(Generic[_T]): def __init__(self, value: _T) -> None: self.value = value def __repr__(self) -> str: return f"{type(self).__qualname__}({self.value!r})" class _ValueAndTag(Generic[_T]): def __init__(self, value: _T, tag: Type[_Tag]) -> None: self.value = value self.tag = tag class _ValueAndOptionalTag(Generic[_T]): def __init__(self, value: _T, tag: Union[Type[_Tag], None]) -> None: self.value = value self.tag = tag class VHDL(_Tag): """Tags source files and build arguments to :meth:`Runner.build() ` as VHDL-specific.""" class Verilog(_Tag): """Tags source files and build arguments to :meth:`Runner.build() ` as Verilog-specific.""" class VerilatorControlFile(_Tag): """Tags source files to :meth:`Runner.build() ` as Verilator control files.""" _verilog_extensions = (".v", ".sv", ".vh", ".svh") _vhdl_extensions = (".vhd", ".vhdl") def _determine_file_type( filename: PathLike, ) -> Union[Type[Verilog], Type[VHDL], Type[VerilatorControlFile]]: ext = Path(filename).suffix if ext in _verilog_extensions: return Verilog elif ext in _vhdl_extensions: return VHDL elif ext == "vlt": return VerilatorControlFile else: raise ValueError( f"Can't determine source file type of {filename}. Use the `VHDL`, `Verilog`, or `VerilatorControlFile` tags." ) class Runner(ABC): supported_gpi_interfaces: Dict[str, List[str]] = {} def __init__(self) -> None: self._simulator_in_path() self.env: Dict[str, str] = {} # for running test() independently of build() self.build_dir: Path = get_abs_path("sim_build") self.parameters: Mapping[str, object] = {} self.log = logging.getLogger(type(self).__qualname__) self.log.setLevel(logging.INFO) @abstractmethod def _simulator_in_path(self) -> None: """Raise exception if the simulator executable does not exist in :envvar:`PATH`. Raises: SystemExit: Simulator executable does not exist in :envvar:`PATH`. """ def _check_hdl_toplevel_lang(self, hdl_toplevel_lang: Optional[str]) -> str: """Return *hdl_toplevel_lang* if supported by simulator, raise exception otherwise. Returns: *hdl_toplevel_lang* if supported by the simulator. Raises: ValueError: *hdl_toplevel_lang* is not supported by the simulator. """ if hdl_toplevel_lang is None: if self._vhdl_sources and not self._verilog_sources and not self._sources: lang = "vhdl" elif self._verilog_sources and not self._vhdl_sources and not self._sources: lang = "verilog" elif self._sources and not self._vhdl_sources and not self._verilog_sources: top_source = self._sources[-1] if top_source.tag is VHDL: lang = "vhdl" elif top_source.tag is Verilog: lang = "verilog" else: raise ValueError( "First argument to *sources* must be a VHDL or Verilog file. " f"Got a {top_source.tag.__qualname__} file: {top_source.value}" ) else: raise ValueError( f"{type(self).__qualname__}: Must specify a hdl_toplevel_lang in a mixed-language design" ) else: lang = hdl_toplevel_lang if lang in self.supported_gpi_interfaces: return lang else: raise ValueError( f"{type(self).__qualname__}: hdl_toplevel_lang {hdl_toplevel_lang!r} is not " f"in supported list: {', '.join(self.supported_gpi_interfaces)}" ) def _set_env(self) -> None: """Set environment variables for sub-processes.""" for e in os.environ: self.env[e] = os.environ[e] if "LIBPYTHON_LOC" not in self.env: libpython_path = find_libpython.find_libpython() if not libpython_path: raise ValueError( "Unable to find libpython, please make sure the appropriate libpython is installed" ) self.env["LIBPYTHON_LOC"] = libpython_path self.env["PATH"] += os.pathsep + str(cocotb_tools.config.libs_dir) self.env["PYTHONPATH"] = os.pathsep.join(sys.path) self.env["PYGPI_PYTHON_BIN"] = sys.executable self.env["COCOTB_TOPLEVEL"] = self.sim_hdl_toplevel self.env["COCOTB_TEST_MODULES"] = self.test_module self.env["TOPLEVEL_LANG"] = self.hdl_toplevel_lang @abstractmethod def _build_command(self) -> Sequence[_Command]: """Return command to build the HDL sources.""" @abstractmethod def _test_command(self) -> Sequence[_Command]: """Return command to run a test.""" def _use_external_viewer(self) -> bool: """Return if an external viewer should be called after simulation when ``gui=True``.""" return False def _waves_file(self) -> Optional[str]: """Return file name of the generated waveform file for use with external viewer.""" return None def build( self, hdl_library: str = "top", verilog_sources: Sequence[Union[PathLike, Verilog]] = [], vhdl_sources: Sequence[Union[PathLike, VHDL]] = [], sources: Sequence[Union[PathLike, VHDL, Verilog, VerilatorControlFile]] = [], includes: Sequence[PathLike] = [], defines: Mapping[str, object] = {}, parameters: Mapping[str, object] = {}, build_args: Sequence[Union[str, VHDL, Verilog]] = [], hdl_toplevel: Optional[str] = None, always: bool = False, build_dir: PathLike = "sim_build", clean: bool = False, verbose: bool = False, timescale: Optional[Tuple[str, str]] = None, waves: bool = False, log_file: Optional[PathLike] = None, ) -> None: """Build the HDL sources. With mixed language simulators, *sources* will be built, followed by *vhdl_sources*, then *verilog_sources*. With simulators that only support either VHDL or Verilog, *sources* will be built, followed by *vhdl_sources* and *verilog_sources*, respectively. If your source files use an atypical file extension, use :class:`VHDL`, :class:`Verilog`, or :class:`VerilatorControlFile` to tag the path as a VHDL, Verilog, or Verilator control file source file, respectively. If the filepaths aren't tagged, the extension is used to determine if they are VHDL or Verilog files. +----------+------------------------------------+ | Language | File Extensions | +==========+====================================+ | VHDL | ``.vhd``, ``.vhdl`` | +----------+------------------------------------+ | Verilog | ``.v``, ``.sv``, ``.vh``, ``.svh`` | +----------+------------------------------------+ .. code-block:: python runner.build( sources=[ VHDL("/my/file.is_actually_vhdl"), Verilog("/other/file.verilog"), ], ) The same tagging works for *build_args*. Tagged *build_args* only supply that option to the compiler when building the source file for the tagged language. Non-tagged *build_args* are supplied when compiling any language. Args: hdl_library: The library name to compile into. verilog_sources: Verilog source files to build. vhdl_sources: VHDL source files to build. sources: Language-agnostic list of source files to build. includes: Verilog include directories. defines: Defines to set. parameters: Verilog parameters or VHDL generics. build_args: Extra build arguments for the simulator. hdl_toplevel: The name of the HDL toplevel module. always: Always run the build step. build_dir: Directory to run the build step in. clean: Delete *build_dir* before building. verbose: Enable verbose messages. timescale: Tuple containing time unit and time precision for simulation. waves: Record signal traces. Overridden by the :envvar:`WAVES` environment variable. log_file: File to write the build log to. .. deprecated:: 2.0 Uses of the *verilog_sources* and *vhdl_sources* parameters should be replaced with the language-agnostic *sources* argument. """ self.clean: bool = clean self.build_dir = get_abs_path(build_dir) if self.clean: self.rm_build_folder(self.build_dir) self.build_dir.mkdir(parents=True, exist_ok=True) # note: to avoid mutating argument defaults, we ensure that no value # is written without a copy. This is much more concise and leads to # a better docstring than using `None` as a default in the parameters # list. self.hdl_library: str = hdl_library if verilog_sources: warnings.warn( "Simulator.build *verilog_sources* parameter is deprecated. Use the language-agnostic *sources* parameter instead.", DeprecationWarning, stacklevel=2, ) self._set_verilog_sources(verilog_sources) if vhdl_sources: warnings.warn( "Simulator.build *vhdl_sources* parameter is deprecated. Use the language-agnostic *sources* parameter instead.", DeprecationWarning, stacklevel=2, ) self._set_vhdl_sources(vhdl_sources) self._set_sources(sources) self.includes: List[Path] = [ get_abs_path(include_dir) for include_dir in includes ] self.defines = dict(defines) self.parameters = dict(parameters) self._set_build_args(build_args) self.always: bool = always self.hdl_toplevel: Optional[str] = hdl_toplevel self.verbose: bool = verbose self.timescale: Optional[Tuple[str, str]] = timescale self.log_file: Optional[PathLike] = log_file self.waves = bool(os.getenv("WAVES", waves)) self.env.update(os.environ) cmds: Sequence[_Command] = self._build_command() self._execute(cmds, cwd=self.build_dir) def test( self, test_module: Union[str, Sequence[str]], hdl_toplevel: str, hdl_toplevel_library: str = "top", hdl_toplevel_lang: Optional[str] = None, gpi_interfaces: Optional[List[str]] = None, testcase: Optional[Union[str, Sequence[str]]] = None, seed: Optional[Union[str, int]] = None, elab_args: Sequence[str] = [], test_args: Sequence[str] = [], plusargs: Sequence[str] = [], extra_env: Mapping[str, str] = {}, waves: bool = False, gui: bool = False, parameters: Optional[Mapping[str, object]] = None, build_dir: Optional[PathLike] = None, test_dir: Optional[PathLike] = None, results_xml: Optional[str] = None, pre_cmd: Optional[List[str]] = None, verbose: bool = False, timescale: Optional[Tuple[str, str]] = None, log_file: Optional[PathLike] = None, test_filter: Optional[str] = None, ) -> Path: """Run the tests. Args: test_module: Name(s) of the Python module(s) containing the tests to run. Can be a comma-separated list. hdl_toplevel: Name of the HDL toplevel module. hdl_toplevel_library: The library name for HDL toplevel module. hdl_toplevel_lang: Language of the HDL toplevel module. gpi_interfaces: List of GPI interfaces to use, with the first one being the entry point. testcase: Name(s) of a specific testcase(s) to run. If not set, run all testcases found in *test_module*. Can be a comma-separated list. seed: A specific random seed to use. elab_args: A list of elaboration arguments for the simulator. test_args: A list of extra arguments for the simulator. plusargs: 'plusargs' to set for the simulator. extra_env: Extra environment variables to set. waves: Record signal traces. Overridden by the :envvar:`WAVES` environment variable. gui: Run with simulator GUI. Overridden by the :envvar:`GUI` environment variable. parameters: Verilog parameters or VHDL generics. build_dir: Directory the build step has been run in. test_dir: Directory to run the tests in. results_xml: Name of xUnit XML file to store test results in. If an absolute path is provided it will be used as-is, :file:`{build_dir}/results.xml` otherwise. This argument should not be set when run with ``pytest``. verbose: Enable verbose messages. pre_cmd: Commands to run before simulation begins. Typically Tcl commands for simulators that support them. timescale: Tuple containing time unit and time precision for simulation. log_file: File to write the test log to. test_filter: Regular expression which matches test names. Only matched tests are run if this argument if given. Returns: The absolute location of the results XML file which can be defined by the *results_xml* argument. """ __tracebackhide__ = True # Hide the traceback when using pytest if build_dir is not None: self.build_dir = get_abs_path(build_dir) if parameters is not None: self.parameters = dict(parameters) if test_dir is None: self.test_dir = self.build_dir else: self.test_dir = get_abs_path(test_dir) self.test_dir.mkdir(parents=True, exist_ok=True) if isinstance(test_module, str): self.test_module = test_module else: self.test_module = ",".join(test_module) # note: to avoid mutating argument defaults, we ensure that no value # is written without a copy. This is much more concise and leads to # a better docstring than using `None` as a default in the parameters # list. self.sim_hdl_toplevel = hdl_toplevel self.hdl_toplevel_library: str = hdl_toplevel_library self.hdl_toplevel_lang = self._check_hdl_toplevel_lang(hdl_toplevel_lang) if gpi_interfaces: self.gpi_interfaces = gpi_interfaces else: self.gpi_interfaces = [] for gpi_if in self.supported_gpi_interfaces.values(): self.gpi_interfaces.append(gpi_if[0]) self.pre_cmd = pre_cmd self.elab_args = list(elab_args) self.test_args = list(test_args) self.plusargs = list(plusargs) self.env = dict(extra_env) if testcase is not None: if isinstance(testcase, str): self.env["COCOTB_TESTCASE"] = testcase else: self.env["COCOTB_TESTCASE"] = ",".join(testcase) if test_filter is not None: self.env["COCOTB_TEST_FILTER"] = test_filter if seed is not None: self.env["COCOTB_RANDOM_SEED"] = str(seed) self.log_file = log_file self.waves = bool(int(os.getenv("WAVES", waves))) self.gui = bool(int(os.getenv("GUI", gui))) self.timescale = timescale if verbose is not None: self.verbose = verbose # Pytest test name is used by the next couple sections. pytest_current_test = os.getenv("PYTEST_CURRENT_TEST", None) if pytest_current_test is not None: self.current_test_name = pytest_current_test.split(":")[-1].split(" ")[0] else: self.current_test_name = "test" results_xml_path: Union[None, Path] = ( Path(results_xml) if results_xml is not None else None ) # result.xml filename precedence: # 1. absolute path # 2. pytest test name # 3. relative path # 4. default name if results_xml_path is not None and results_xml_path.is_absolute(): results_xml_file = results_xml_path elif pytest_current_test is not None: if results_xml_path is not None: raise NotImplementedError( "Relative result_xml paths aren't supported when using pytest" ) results_xml_file = self.test_dir / f"{self.current_test_name}.result.xml" elif results_xml_path is not None: results_xml_file = self.test_dir / results_xml_path else: results_xml_file = self.test_dir / "results.xml" with suppress(OSError): results_xml_file.unlink() # transport the settings to cocotb via environment variables self._set_env() self.env["COCOTB_RESULTS_FILE"] = str(results_xml_file) cmds: Sequence[_Command] = self._test_command() simulator_exit_code: int = 0 try: self._execute(cmds, cwd=self.test_dir) except subprocess.CalledProcessError as e: # It is possible for the simulator to fail but still leave results. self.log.error("Simulation failed: %d", e.returncode) simulator_exit_code = e.returncode # Only when running under pytest, check the results file here, # potentially raising an exception with failing testcases, # otherwise return the results file for later analysis. if pytest_current_test: try: (num_tests, num_failed) = get_results(results_xml_file) except RuntimeError as e: self.log.error("%s", e.args[0]) sys.exit(simulator_exit_code) else: if num_failed: self.log.error( "ERROR: Failed %d of %d tests.", num_failed, num_tests ) sys.exit(1 if simulator_exit_code == 0 else simulator_exit_code) if simulator_exit_code != 0: sys.exit(simulator_exit_code) if pytest_current_test and self._use_external_viewer() and self.gui: viewer = os.getenv("COCOTB_WAVEFORM_VIEWER") if viewer is not None: viewer_path = shutil.which(viewer) if viewer_path is None: raise ValueError(f"Cannot find {viewer} in the system path") else: viewer_path = shutil.which("surfer") if viewer_path is None: viewer_path = shutil.which("gtkwave") if viewer_path is None: raise SystemError( "Cannot find any viewer (surfer or gtkwave) in the system path" ) subprocess.run( [f"{viewer_path} {self._waves_file()}"], cwd=self.test_dir, check=True, shell=True, ) self.log.info("Results file: %s", results_xml_file) return results_xml_file @abstractmethod def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: """Return simulator-specific formatted option strings with *includes* directories.""" @abstractmethod def _get_define_options(self, defines: Mapping[str, object]) -> _Command: """Return simulator-specific formatted option strings with *defines* macros.""" @abstractmethod def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: """Return simulator-specific formatted option strings with *parameters*/generics.""" def _execute(self, cmds: Sequence[_Command], cwd: PathLike) -> None: __tracebackhide__ = True # Hide the traceback when using PyTest. if self.log_file is None: self._execute_cmds(cmds, cwd) else: with open(self.log_file, "w") as f: self._execute_cmds(cmds, cwd, f) def _execute_cmds( self, cmds: Sequence[_Command], cwd: PathLike, stdout: Optional[TextIO] = None ) -> None: __tracebackhide__ = True # Hide the traceback when using PyTest. for cmd in cmds: self.log.info("Running command %s in directory %s", _shlex_join(cmd), cwd) # TODO: create a thread to handle stderr and log as error? # TODO: log forwarding stderr = None if stdout is None else subprocess.STDOUT subprocess.run( cmd, cwd=cwd, env=self.env, check=True, stdout=stdout, stderr=stderr ) def rm_build_folder(self, build_dir: Path) -> None: if build_dir.is_dir(): self.log.info("Removing: %s", build_dir) shutil.rmtree(build_dir, ignore_errors=True) @property def verilog_sources(self) -> List[Path]: return [source.value for source in self._verilog_sources] @verilog_sources.setter def verilog_sources(self, value: List[Path]) -> None: self._set_verilog_sources(value) def _set_verilog_sources( self, sources: Sequence[Union[PathLike, Verilog, VerilatorControlFile]] ) -> None: verilog_sources: List[_ValueAndTag] = [] for source in sources: if isinstance(source, _Tag): if isinstance(source, (Verilog, VerilatorControlFile)): abs_path = get_abs_path(source.value) verilog_sources.append(_ValueAndTag(abs_path, type(source))) else: raise ValueError(f"Unsupported file type: {source}") else: tag = _determine_file_type(source) abs_path = get_abs_path(source) verilog_sources.append(_ValueAndTag(abs_path, tag)) self._verilog_sources = verilog_sources @property def vhdl_sources(self) -> List[Path]: return [source.value for source in self._vhdl_sources] @vhdl_sources.setter def vhdl_sources(self, value: List[Path]) -> None: self._set_vhdl_sources(value) def _set_vhdl_sources(self, sources: Sequence[Union[PathLike, VHDL]]) -> None: vhdl_sources: List[_ValueAndTag] = [] for source in sources: if isinstance(source, _Tag): if isinstance(source, VHDL): abs_path = get_abs_path(source.value) vhdl_sources.append(_ValueAndTag(abs_path, type(source))) else: raise ValueError(f"Unsupported file type: {source}") else: tag = _determine_file_type(source) abs_path = get_abs_path(source) vhdl_sources.append(_ValueAndTag(abs_path, tag)) self._vhdl_sources = vhdl_sources @property def sources(self) -> List[Path]: return [source.value for source in self._sources] @sources.setter def sources(self, value: List[Path]) -> None: self._set_sources(value) def _set_sources( self, sources: Sequence[Union[PathLike, Verilog, VHDL, VerilatorControlFile]] ) -> None: sources_: List[_ValueAndTag] = [] for source in sources: if isinstance(source, _Tag): if isinstance(source, (Verilog, VHDL, VerilatorControlFile)): abs_path = get_abs_path(source.value) sources_.append(_ValueAndTag(abs_path, type(source))) else: raise ValueError(f"Unsupported file type: {source}") else: tag = _determine_file_type(source) abs_path = get_abs_path(source) sources_.append(_ValueAndTag(abs_path, tag)) self._sources = sources_ @property def build_args(self) -> List[str]: return [arg.value for arg in self._build_args] @build_args.setter def build_args(self, value: List[str]) -> None: self._set_build_args(value) def _set_build_args(self, build_args: Sequence[Union[str, Verilog, VHDL]]) -> None: build_args_: List[_ValueAndOptionalTag] = [] for build_arg in build_args: if isinstance(build_arg, _Tag): if isinstance(build_arg, (Verilog, VHDL)): build_args_.append( _ValueAndOptionalTag(build_arg.value, type(build_arg)) ) else: raise ValueError(f"Unsupported tag type: {build_arg}") else: build_args_.append(_ValueAndOptionalTag(build_arg, None)) self._build_args = build_args_ def outdated(output: Path, dependencies: Iterable[Path]) -> bool: """Return ``True`` if any source files in *dependencies* are newer than the *output* directory. Returns: ``True`` if any source files are newer, ``False`` otherwise. """ if not output.is_file(): return True output_mtime = output.stat().st_mtime dep_mtime = 0.0 for dependency in dependencies: mtime = dependency.stat().st_mtime dep_mtime = max(mtime, dep_mtime) return dep_mtime > output_mtime def get_abs_path(path: PathLike) -> Path: """Return *path* in absolute form.""" path = Path(path) if path.is_absolute(): return path.resolve() else: return Path(Path.cwd() / path).resolve() class Icarus(Runner): """Implementation of :class:`Runner` for Icarus Verilog. .. admonition:: Simulator-specific Usage * ``hdl_toplevel`` argument to :meth:`.build` is *required*. * ``waves=True`` *must* be given to :meth:`.build` if either ``waves`` or ``gui`` are to be used during :meth:`.test`. * ``timescale`` argument to :meth:`.build` must be given to support dumping the command file. * Does not support the ``pre_cmd`` argument to :meth:`.test`. """ supported_gpi_interfaces = {"verilog": ["vpi"]} def _simulator_in_path(self) -> None: if shutil.which("iverilog") is None: raise SystemExit("ERROR: iverilog executable not found!") def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: return [f"-I{include}" for include in includes] def _get_define_options(self, defines: Mapping[str, object]) -> _Command: return [f"-D{name}={_as_sv_literal(value)}" for name, value in defines.items()] def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: return [ f"-P{self.hdl_toplevel}.{name}={value}" for name, value in parameters.items() ] def _use_external_viewer(self) -> bool: return True def _waves_file(self) -> Optional[str]: return f"{self.hdl_toplevel}.fst" def _create_cmd_file(self) -> None: assert self.timescale is not None with open(self.cmds_file, "w") as f: f.write("+timescale+{}/{}\n".format(*self.timescale)) def _create_iverilog_dump_file(self) -> None: dumpfile_path = _as_sv_literal(str(self.build_dir / f"{self.hdl_toplevel}.fst")) with open(self.iverilog_dump_file, "w") as f: f.write("module cocotb_iverilog_dump();\n") f.write("initial begin\n") f.write(" string dumpfile_path;") f.write( ' if ($value$plusargs("dumpfile_path=%s", dumpfile_path)) begin\n' ) f.write(" $dumpfile(dumpfile_path);\n") f.write(" end else begin\n") f.write(f" $dumpfile({dumpfile_path});\n") f.write(" end\n") f.write(f" $dumpvars(0, {self.hdl_toplevel});\n") f.write("end\n") f.write("endmodule\n") @property def sim_file(self) -> Path: return self.build_dir / "sim.vvp" @property def iverilog_dump_file(self) -> Path: return self.build_dir / "cocotb_iverilog_dump.v" @property def cmds_file(self) -> Path: return self.build_dir / "cmds.f" def _build_command(self) -> List[_Command]: if self.hdl_toplevel is None: raise ValueError("hdl_toplevel argument is required for all Icarus builds") sources = self._sources + self._verilog_sources for source in sources: if source.tag is not Verilog: raise ValueError( f"{type(self).__qualname__} only supports Verilog. {str(source.value)!r} cannot be compiled." ) for arg in self._build_args: if arg.tag not in (Verilog, None): raise ValueError( f"{type(self).__qualname__} only supports Verilog. build_args {arg.value!r} cannot be applied." ) build_args = [arg.value for arg in self._build_args] if self.waves: self._create_iverilog_dump_file() build_args += ["-s", "cocotb_iverilog_dump"] if self.timescale is not None: self._create_cmd_file() build_args += ["-f", str(self.cmds_file)] cmds: list[_Command] = [] if outdated(self.sim_file, (source.value for source in sources)) or self.always: cmds = [ [ "iverilog", "-o", str(self.sim_file), "-s", self.hdl_toplevel, "-g2012", ] + self._get_define_options(self.defines) + self._get_include_options(self.includes) + self._get_parameter_options(self.parameters) + [arg for arg in build_args if type(arg) in (str, Verilog)] + [str(source_file.value) for source_file in sources] + [ str(source_file) for source_file in [self.iverilog_dump_file] if self.waves ] ] else: self.log.warning("Skipping compilation of %s", self.sim_file) return cmds def _test_command(self) -> List[_Command]: if self.pre_cmd is not None: raise RuntimeError("pre_cmd is not implemented for Icarus Verilog.") plusargs = self.plusargs if self.waves or self.gui: plusargs += ["-fst"] else: # Disable waveform output plusargs += ["-none"] return [ [ "vvp", "-M", str(cocotb_tools.config.libs_dir), "-m", cocotb_tools.config.lib_name("vpi", "icarus"), *self.test_args, str(self.sim_file), *plusargs, ] ] class Questa(Runner): """Implementation of :class:`Runner` for Siemens Questa. .. admonition:: Simulator-specific Usage * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`. """ supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["fli", "vhpi"]} def _simulator_in_path(self) -> None: if shutil.which("vsim") is None: raise SystemExit("ERROR: vsim executable not found!") def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: return [f"+incdir+{_as_tcl_value(str(include))}" for include in includes] def _get_define_options(self, defines: Mapping[str, object]) -> _Command: return [ f"+define+{name}={_as_sv_literal(value)}" for name, value in defines.items() ] def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: return [f"-g{name}={value}" for name, value in parameters.items()] def _build_command(self) -> List[_Command]: cmds = [] cmds.append(["vlib", _as_tcl_value(self.hdl_library)]) vhdl_args = [ _as_tcl_value(arg.value) for arg in self._build_args if arg.tag in (VHDL, None) ] verilog_args = [ _as_tcl_value(arg.value) for arg in self._build_args if arg.tag in (Verilog, None) ] hdl_library = _as_tcl_value(self.hdl_library) defines = self._get_define_options(self.defines) includes = self._get_include_options(self.includes) for source in chain(self._sources, self._vhdl_sources, self._verilog_sources): if source.tag is VHDL: cmds.append( [ "vcom", "-work", hdl_library, *vhdl_args, _as_tcl_value(str(source.value)), ] ) elif source.tag is Verilog: cmds.append( [ "vlog", *([] if self.always else ["-incr"]), "-work", hdl_library, "-sv", *defines, *includes, *verilog_args, _as_tcl_value(str(source.value)), ] ) else: raise ValueError(f"Unsupported file type: {source.value}") return cmds def _test_command(self) -> List[_Command]: cmds = [] if self.pre_cmd is not None: pre_cmd = ["-do", *self.pre_cmd] else: pre_cmd = [] do_script = "" if self.waves: do_script += "log -recursive /*;" if not self.gui: do_script += "run -all; quit" gpi_if_entry = self.gpi_interfaces[0] if gpi_if_entry == "fli": lib_opts = [ "-foreign", "cocotb_init " + _as_tcl_value( cocotb_tools.config.lib_name_path("fli", "questa").as_posix() ), ] elif gpi_if_entry == "vhpi": lib_opts = ["-voptargs=-access=rw+/."] lib_opts += [ "-foreign", "vhpi_startup_routines_bootstrap " + _as_tcl_value( cocotb_tools.config.lib_name_path("vhpi", "questa").as_posix() ), ] else: lib_opts = [ "-pli", _as_tcl_value( cocotb_tools.config.lib_name_path("vpi", "questa").as_posix() ), ] cmds.append( ["vsim"] + ["-gui" if self.gui else "-c"] + ["-onfinish", "stop" if self.gui else "exit"] + lib_opts + [_as_tcl_value(v) for v in self.test_args] + [_as_tcl_value(v) for v in self._get_parameter_options(self.parameters)] + [_as_tcl_value(f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}")] + [_as_tcl_value(v) for v in self.plusargs] + pre_cmd + ["-do", do_script] ) gpi_extra_list = [] for gpi_if in self.gpi_interfaces[1:]: gpi_if_lib_path = cocotb_tools.config.lib_name_path(gpi_if, "questa") if gpi_if_lib_path.is_file(): gpi_extra_list.append( gpi_if_lib_path.as_posix() + f":cocotb{gpi_if}_entry_point" ) else: raise RuntimeError(f"{gpi_if_lib_path} library not found.") self.env["GPI_EXTRA"] = ",".join(gpi_extra_list) return cmds class Ghdl(Runner): """Implementation of :class:`Runner` for GHDL. .. admonition:: Simulator-specific Usage * Does not support the ``pre_cmd`` argument to :meth:`.test`. """ supported_gpi_interfaces = {"vhdl": ["vpi"]} def _set_env(self) -> None: super()._set_env() if "COCOTB_TRUST_INERTIAL_WRITES" not in self.env: self.env["COCOTB_TRUST_INERTIAL_WRITES"] = "1" def _simulator_in_path(self) -> None: if shutil.which("ghdl") is None: raise SystemExit("ERROR: ghdl executable not found!") def _is_mcode_backend(self) -> bool: """Is GHDL using the mcode backend?""" result = subprocess.run( ["ghdl", "--version"], check=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) return "mcode" in result.stdout def _use_external_viewer(self) -> bool: return True def _waves_file(self) -> Optional[str]: return f"{self.hdl_toplevel}.ghw" def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: raise RuntimeError def _get_define_options(self, defines: Mapping[str, object]) -> _Command: raise RuntimeError def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: return [f"-g{name}={value}" for name, value in parameters.items()] def _build_command(self) -> List[_Command]: sources = self._sources + self._vhdl_sources for source in sources: if source.tag is not VHDL: raise ValueError( f"{type(self).__qualname__} only supports VHDL. {str(source.value)!r} cannot be compiled." ) for arg in self._build_args: if arg.tag not in (VHDL, None): raise ValueError( f"{type(self).__qualname__} only supports VHDL. build_args {arg.value!r} will not be applied." ) cmds = [ ["ghdl", "-i"] + [f"--work={self.hdl_library}"] + [arg.value for arg in self._build_args] + [str(source.value) for source in sources] ] if self.hdl_toplevel is not None: cmds += [ [ "ghdl", "-m", f"--work={self.hdl_library}", *(arg.value for arg in self._build_args), self.hdl_toplevel, ] ] return cmds def _test_command(self) -> List[_Command]: if self.pre_cmd is not None: raise RuntimeError("pre_cmd is not implemented for GHDL.") ghdl_run_args = self.test_args if self._is_mcode_backend() and self.timescale: _, precision = self.timescale # Convert the time precision to a format string supported by GHDL, # if possible. # GHDL only supports setting the time precision if the mcode backend # is used, using the --time-resolution argument causes GHDL to error # out otherwise. # https://ghdl.github.io/ghdl/using/InvokingGHDL.html#cmdoption-ghdl-time-resolution if precision == "1fs": ghdl_time_resolution = "fs" elif precision == "1ps": ghdl_time_resolution = "ps" elif precision == "1ns": ghdl_time_resolution = "ns" elif precision == "1us": ghdl_time_resolution = "us" elif precision == "1ms": ghdl_time_resolution = "ms" elif precision == "1s": ghdl_time_resolution = "sec" else: raise ValueError( "GHDL only supports the following precisions in timescale: 1fs, 1ps, 1us, 1ms, 1s" ) ghdl_run_args.append(f"--time-resolution={ghdl_time_resolution}") cmds = [ ["ghdl", "-r"] + [f"--work={self.hdl_toplevel_library}"] + ghdl_run_args + [self.sim_hdl_toplevel] + ["--vpi=" + cocotb_tools.config.lib_name_path("vpi", "ghdl").as_posix()] + self.plusargs + self._get_parameter_options(self.parameters) + ([f"--wave={self._waves_file()}"] if self.waves or self.gui else []) ] return cmds class Nvc(Runner): """Implementation of :class:`Runner` for NVC. .. admonition:: Simulator-specific Usage * Does not support the ``pre_cmd`` argument to :meth:`.test`. * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`. """ supported_gpi_interfaces = {"vhdl": ["vhpi"]} def __init__(self) -> None: super().__init__() version_str = subprocess.run( ["nvc", "--version"], check=True, universal_newlines=True, stdout=subprocess.PIPE, ).stdout version = NvcVersion.from_commandline(version_str) if version > NvcVersion("1.16"): self._preserve_case = ["--preserve-case"] else: self._preserve_case = [] def _set_env(self) -> None: super()._set_env() if "COCOTB_TRUST_INERTIAL_WRITES" not in self.env: self.env["COCOTB_TRUST_INERTIAL_WRITES"] = "1" def _simulator_in_path(self) -> None: if shutil.which("nvc") is None: raise SystemExit("ERROR: nvc executable not found!") def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: raise RuntimeError def _get_define_options(self, defines: Mapping[str, object]) -> _Command: raise RuntimeError def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: return [f"-g{name}={value}" for name, value in parameters.items()] def _use_external_viewer(self) -> bool: return True def _waves_file(self) -> Optional[str]: return f"{self.hdl_toplevel}.fst" def _build_command(self) -> List[_Command]: sources = self._sources + self._vhdl_sources for source in sources: if source.tag is not VHDL: raise ValueError( f"{type(self).__qualname__} only supports VHDL. {str(source.value)!r} cannot be compiled." ) for arg in self._build_args: if arg.tag not in (VHDL, None): raise ValueError( f"{type(self).__qualname__} only supports VHDL. build_args {arg.value!r} will not be applied." ) cmds = [ [ "nvc", f"--work={self.hdl_library}", "-L", str(get_abs_path(self.build_dir)), ] + [arg.value for arg in self._build_args] + ["-a"] + [str(source.value) for source in sources] + self._preserve_case ] return cmds def _test_command(self) -> List[_Command]: work_library = str(get_abs_path(self.build_dir / self.hdl_toplevel_library)) cmds = [ [ "nvc", f"--work={self.hdl_toplevel_library}:{work_library}", "-L", str(get_abs_path(self.build_dir)), ] + [arg.value for arg in self._build_args] + ["-e", self.sim_hdl_toplevel, "--no-save", "--jit"] + self.elab_args + self._get_parameter_options(self.parameters) + ["-r"] + self.test_args + ["--load=" + cocotb_tools.config.lib_name_path("vhpi", "nvc").as_posix()] + self.plusargs + ([f"--wave={self._waves_file()}"] if self.waves or self.gui else []) ] return cmds class Riviera(Runner): """Implementation of :class:`Runner` for Aldec Riviera-PRO. .. admonition:: Simulator-specific Usage * Does not support the ``pre_cmd`` argument to :meth:`.test`. * Does not support the ``gui`` argument to :meth:`.test`. * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`. """ supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["vhpi"]} def _simulator_in_path(self) -> None: if shutil.which("vsimsa") is None: raise SystemExit("ERROR: vsimsa executable not found!") def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: return [f"+incdir+{_as_tcl_value(str(include))}" for include in includes] def _get_define_options(self, defines: Mapping[str, object]) -> _Command: return [ f"+define+{name}={self._as_define_value(value)}" for name, value in defines.items() ] def _as_define_value(self, value: object) -> str: if isinstance(value, int): return str(value) elif isinstance(value, str): for char in value: if ord(char) < 32 or ord(char) >= 255 or char in '\\"': # Control characters are generally not supported. # Not sure if there's any way to escape quotes or backslashes. raise ValueError( f"Character {char!r} not supported in define value" ) return '\\"\\\\"' + value + '\\\\"\\"' else: raise TypeError("Can't serialize this type as an SV literal") def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: return [f"-g{name}={value}" for name, value in parameters.items()] def _build_command(self) -> List[_Command]: do_script: List[str] = ["onerror {\n quit -code 1 \n}"] out_file = self.build_dir / self.hdl_library / f"{self.hdl_library}.lib" sources = self._sources + self._vhdl_sources + self._verilog_sources if outdated(out_file, (source.value for source in sources)) or self.always: vhdl_args = [ arg.value for arg in self._build_args if arg.tag in (VHDL, None) ] verilog_args = [ arg.value for arg in self._build_args if arg.tag in (Verilog, None) ] defines = " ".join(self._get_define_options(self.defines)) includes = " ".join(self._get_include_options(self.includes)) verilog_args_str = " ".join(_as_tcl_value(v) for v in verilog_args) vhdl_args_str = " ".join(_as_tcl_value(v) for v in vhdl_args) hdl_library = _as_tcl_value(self.hdl_library) ext_name = _as_tcl_value( cocotb_tools.config.lib_name_path("vpi", "riviera").as_posix() ) do_script.append(f"alib {hdl_library}") for source in sources: if source.tag is Verilog: do_script.append( f"alog -work {hdl_library} -pli {ext_name} -sv {defines} {includes} {verilog_args_str} {_as_tcl_value(str(source.value))}" ) elif source.tag is VHDL: do_script.append( f"acom -work {hdl_library} {vhdl_args_str} {_as_tcl_value(str(source.value))}" ) else: raise ValueError(f"Unsupported file type: {source.value}") # Explicitly exit the script at the end. In batch mode, which is invoked # implicitly by redirecting STDOUT/STDERR of the alog/acom commands, # the tool exits by itself even without this 'exit' command -- but not # when running from an interactive terminal. Be explicit for predictable # behavior. do_script.append("exit") with tempfile.NamedTemporaryFile(delete=False) as do_file: do_file.write("\n".join(do_script).encode()) return [["vsimsa", "-do", "do", do_file.name]] def _test_command(self) -> List[_Command]: if self.pre_cmd is not None: raise RuntimeError("pre_cmd is not implemented for Riviera.") do_script: str = "\nonerror {\n quit -code 1 \n} \n" if self.hdl_toplevel_lang == "vhdl": do_script += "asim +access +w_nets -interceptcoutput -loadvhpi {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS}\n".format( TOPLEVEL=_as_tcl_value( f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}" ), EXT_NAME=_as_tcl_value( cocotb_tools.config.lib_name_path("vhpi", "riviera").as_posix() + ":vhpi_startup_routines_bootstrap" ), EXTRA_ARGS=" ".join( _as_tcl_value(v) for v in ( self.test_args + self._get_parameter_options(self.parameters) ) ), PLUSARGS=" ".join(_as_tcl_value(v) for v in self.plusargs), ) self.env["GPI_EXTRA"] = ( cocotb_tools.config.lib_name_path("vpi", "riviera").as_posix() + ":cocotbvpi_entry_point" ) else: do_script += "asim +access +w_nets -interceptcoutput -pli {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS} \n".format( TOPLEVEL=_as_tcl_value( f"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}" ), EXT_NAME=_as_tcl_value( cocotb_tools.config.lib_name_path("vpi", "riviera").as_posix() ), EXTRA_ARGS=" ".join( _as_tcl_value(v) for v in ( self.test_args + self._get_parameter_options(self.parameters) ) ), PLUSARGS=" ".join(_as_tcl_value(v) for v in self.plusargs), ) self.env["GPI_EXTRA"] = ( cocotb_tools.config.lib_name_path("vhpi", "riviera").as_posix() + ":cocotbvhpi_entry_point" ) if self.waves: do_script += "log -recursive /*;" do_script += "run -all \nexit" with tempfile.NamedTemporaryFile(delete=False) as do_file: do_file.write(do_script.encode()) return [["vsimsa", "-do", "do", do_file.name]] class Verilator(Runner): """Implementation of :class:`Runner` for Verilator. .. admonition:: Simulator-specific Usage * ``waves=True`` *must* be given to :meth:`.build` if either ``waves`` or ``gui`` are to be used during :meth:`.test`. * Does not support the ``pre_cmd`` argument to :meth:`.test`. """ supported_gpi_interfaces = {"verilog": ["vpi"]} def _set_env(self) -> None: super()._set_env() if "COCOTB_TRUST_INERTIAL_WRITES" not in self.env: self.env["COCOTB_TRUST_INERTIAL_WRITES"] = "1" def _simulator_in_path(self) -> None: # the verilator binary is only needed for building return def _use_external_viewer(self) -> bool: return True def _waves_file(self) -> Optional[str]: return "dump.vcd" def _simulator_in_path_build_only(self) -> None: executable = shutil.which("verilator") if executable is None: raise SystemExit("ERROR: verilator executable not found!") self.executable: str = executable def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: return [f"-I{include}" for include in includes] def _get_define_options(self, defines: Mapping[str, object]) -> _Command: return [f"-D{name}={_as_sv_literal(value)}" for name, value in defines.items()] def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: return [f"-G{name}={value}" for name, value in parameters.items()] def _build_command(self) -> List[_Command]: self._simulator_in_path_build_only() sources = self._sources + self._verilog_sources for source in sources: if source.tag not in (Verilog, VerilatorControlFile): raise ValueError( f"{type(self).__qualname__} only supports Verilog and Verilator Control Files. {str(source.value)!r} cannot be compiled." ) for arg in self._build_args: if arg.tag not in (Verilog, None): raise ValueError( f"{type(self).__qualname__} only supports Verilog. build_args {arg.value!r} will not be applied." ) if self.hdl_toplevel is None: raise ValueError( f"{type(self).__qualname__} requires the hdl_toplevel parameter to be specified." ) # TODO: set "--debug" if self.verbose # TODO: support "--always" verilator_cpp = str( cocotb_tools.config.share_dir / "lib" / "verilator" / "verilator.cpp" ) cmds = [] cmds.append( [ "perl", self.executable, "-cc", "--exe", "-Mdir", str(self.build_dir), "--top-module", self.hdl_toplevel, "--vpi", "--public-flat-rw", "--prefix", "Vtop", "-o", self.hdl_toplevel, "-LDFLAGS", f"-Wl,-rpath,{cocotb_tools.config.libs_dir} -L{cocotb_tools.config.libs_dir} -lcocotbvpi_verilator", ] + (["--trace"] if self.waves else []) + [arg.value for arg in self._build_args] + ( ["--timescale", "{}/{}".format(*self.timescale)] if self.timescale is not None else [] ) + self._get_define_options(self.defines) + self._get_include_options(self.includes) + self._get_parameter_options(self.parameters) + [verilator_cpp] + [str(source.value) for source in sources] ) cmds.append( [ "make", "-j", f"{_get_max_parallel_build_jobs()}", "-C", str(self.build_dir), "-f", "Vtop.mk", f"VM_TRACE={int(self.waves)}", ] ) return cmds def _test_command(self) -> List[_Command]: if self.pre_cmd is not None: raise RuntimeError("pre_cmd is not implemented for Verilator.") out_file = self.build_dir / self.sim_hdl_toplevel return [ [str(out_file)] + (["--trace"] if self.waves or self.gui else []) + self.test_args + self.plusargs ] class Xcelium(Runner): """Implementation of :class:`Runner` for Cadence Xcelium. .. admonition:: Simulator-specific Usage * Does not support the ``waves`` argument to :meth:`.build` (must be set in :meth:`.test` instead). * Does not support the ``pre_cmd`` argument to :meth:`.test`. * Does not support the ``timescale`` argument to :meth:`.test`. """ supported_gpi_interfaces = {"verilog": ["vpi"], "vhdl": ["vhpi"]} def _simulator_in_path(self) -> None: if shutil.which("xrun") is None: raise SystemExit("ERROR: xrun executable not found!") def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: return [f"-incdir {include}" for include in includes] def _get_define_options(self, defines: Mapping[str, object]) -> _Command: return [ f"-define {name}={self._as_define_value(value)}" for name, value in defines.items() ] def _as_define_value(self, value: object) -> str: if isinstance(value, int): return str(value) elif isinstance(value, str): for char in value: if ord(char) < 32 or ord(char) >= 255 or char == '"': # Control characters are generally not supported. # Not sure if there's any way to escape quotes. raise ValueError( f"Character {char!r} not supported in define value" ) return '"\\"' + value.replace("\\", "\\\\") + '\\""' else: raise TypeError("Can't serialize this type as an SV literal") def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: return [f'-gpg "{name} => {value}"' for name, value in parameters.items()] def _build_command(self) -> List[_Command]: self.env["CDS_AUTO_64BIT"] = "all" if self.waves: raise RuntimeError( "waves is not supported in the build step. Please set it in the test step." ) if self.hdl_toplevel is None: raise ValueError("A HDL toplevel is required in all Xcelium compiles.") verbosity_opts = [] if self.verbose: verbosity_opts += ["-messages"] verbosity_opts += ["-status"] verbosity_opts += ["-gverbose"] # print assigned generics/parameters verbosity_opts += ["-pliverbose"] verbosity_opts += ["-plidebug"] # Enhance the profile output with PLI info verbosity_opts += [ "-plierr_verbose" ] # Expand handle info in PLI/VPI/VHPI messages else: verbosity_opts += ["-quiet"] verbosity_opts += ["-plinowarn"] sources = self._sources + self._vhdl_sources + self._verilog_sources for source in sources: if source.tag not in (VHDL, Verilog): raise ValueError(f"Unsupported file type: {source.value}") vhpi_opts = [] if any(source.tag is VHDL for source in sources): # Xcelium 23.09.004 fixes cocotb issue #1076 as long as the # following define is set. vhpi_opts.append("-NEW_VHPI_PROPAGATE_DELAY") cmds = [ ["xrun"] + ["-logfile"] + ["xrun_build.log"] + ["-elaborate"] + ["-xmlibdirname"] + [f"{self.build_dir}/xrun_snapshot"] + ["-licqueue"] + (["-clean"] if self.always else []) + verbosity_opts # + ["-vpicompat 1800v2005"] # <1364v1995|1364v2001|1364v2005|1800v2005> Specify the IEEE VPI + ["-access +rwc"] + ["-loadvpi"] # always start with VPI on Xcelium + [ cocotb_tools.config.lib_name_path("vpi", "xcelium").as_posix() + ":vlog_startup_routines_bootstrap" ] + vhpi_opts + [f"-work {self.hdl_library}"] + ( ["-timescale", "{}/{}".format(*self.timescale)] if self.timescale is not None else [] ) + [arg.value for arg in self._build_args] + self._get_include_options(self.includes) + self._get_define_options(self.defines) + self._get_parameter_options(self.parameters) + [f"-top {self.hdl_toplevel}"] + [str(source_file.value) for source_file in sources] ] return cmds def _test_command(self) -> List[_Command]: if self.pre_cmd is not None: raise RuntimeError("pre_cmd is not implemented for Xcelium.") if self.timescale is not None: raise RuntimeError( "timescale is not supported in the test step. Please set it in the build step." ) self.env["CDS_AUTO_64BIT"] = "all" verbosity_opts = [] if self.verbose: verbosity_opts += ["-messages"] verbosity_opts += ["-status"] verbosity_opts += ["-gverbose"] # print assigned generics/parameters verbosity_opts += ["-pliverbose"] verbosity_opts += ["-plidebug"] # Enhance the profile output with PLI info verbosity_opts += [ "-plierr_verbose" ] # Expand handle info in PLI/VPI/VHPI messages else: verbosity_opts += ["-quiet"] verbosity_opts += ["-plinowarn"] tmpdir = f"implicit_tmpdir_{self.current_test_name}" if self.hdl_toplevel_lang == "vhdl": xrun_top = ":" else: xrun_top = self.sim_hdl_toplevel if self.waves: input_tcl = [ f'-input "@database -open cocotb_waves -default" ' f'-input "@probe -database cocotb_waves -create {xrun_top} -all -depth all" ' f'-input "@run" ' f'-input "@exit" ' ] else: input_tcl = ["-input", "@run; exit;"] sources = self._sources + self._vhdl_sources + self._verilog_sources vhpi_opts = [] if any(source.tag is VHDL for source in sources): # Xcelium 23.09.004 fixes cocotb issue #1076 as long as the # following define is set. vhpi_opts.append("-NEW_VHPI_PROPAGATE_DELAY") cmds = [["mkdir", "-p", tmpdir]] cmds += [ [ "xrun", "-logfile", f"xrun_{self.current_test_name}.log", "-xmlibdirname", f"{self.build_dir}/xrun_snapshot", "-cds_implicit_tmpdir", tmpdir, "-licqueue", *vhpi_opts, *verbosity_opts, "-R", *self.test_args, *self.plusargs, "-gui" if self.gui else "", *input_tcl, ] ] self.env["GPI_EXTRA"] = ( cocotb_tools.config.lib_name_path("vhpi", "xcelium").as_posix() + ":cocotbvhpi_entry_point" ) return cmds class Vcs(Runner): """Implementation of :class:`Runner` for Synopsys VCS. .. admonition:: Simulator-specific Usage * Does not support the ``pre_cmd`` argument to :meth:`.test`. * Does not support VHDL. * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`. """ supported_gpi_interfaces = {"verilog": ["vpi"]} def _simulator_in_path(self) -> None: if shutil.which("vcs") is None: raise SystemExit("ERROR: vcs executable not found!") def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: return [f"+incdir+{include}" for include in includes] def _get_define_options(self, defines: Mapping[str, object]) -> _Command: return [ f"+define+{name}={_as_sv_literal(value)}" for name, value in defines.items() ] def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: if self.hdl_toplevel is None: raise ValueError("A HDL toplevel is required in all VCS compiles.") return [ f"-pvalue+{self.hdl_toplevel}.{name}={value}" for name, value in parameters.items() ] @property def sim_file(self) -> Path: return self.build_dir / "simv" @property def _build_opts(self) -> List[str]: opts = [ "-full64", "-debug_access+all", "+acc+3", "-sverilog", "-LDFLAGS -Wl,--no-as-needed", ] if self.verbose: opts += ["-diag all"] else: opts += ["-q"] opts += ["-suppress=VPI-CT-NS"] return opts def _build_command(self) -> List[_Command]: cmds: List[_Command] = [] sources = self._sources + self._vhdl_sources + self._verilog_sources for source in sources: if source.tag not in (VHDL, Verilog): raise ValueError(f"Unsupported file type: {source.value}") if outdated(self.sim_file, (source.value for source in sources)) or self.always: cmds = [ ["vcs"] + self._build_opts + ["-load", cocotb_tools.config.lib_name_path("vpi", "vcs").as_posix()] + [arg.value for arg in self._build_args] + self._get_include_options(self.includes) + self._get_define_options(self.defines) + self._get_parameter_options(self.parameters) + ["-top", f"{self.hdl_toplevel}"] + [str(source.value) for source in sources] + ["-o", str(self.sim_file)] ] else: self.log.warning("Skipping compilation of %s", self.sim_file) return cmds def _test_command(self) -> List[_Command]: if self.pre_cmd is not None: raise RuntimeError("pre_cmd is not implemented for Vcs.") verbosity_opts = [] if self.verbose: verbosity_opts += ["-diag all"] else: verbosity_opts += ["-suppress=ASLR_DETECTED_INFO"] cmds = [[str(self.sim_file), *verbosity_opts, *self.test_args, *self.plusargs]] return cmds class Dsim(Runner): """Implementation of :class:`Runner` for Siemens DSim. .. admonition:: Simulator-specific Usage * Does not support the ``pre_cmd`` argument to :meth:`.test`. """ supported_gpi_interfaces = {"verilog": ["vpi"]} def _simulator_in_path(self) -> None: if shutil.which("dsim") is None: raise SystemExit("ERROR: dsim executable not found!") def _get_include_options(self, includes: Sequence[PathLike]) -> _Command: return [f"+incdir+{include}" for include in includes] def _get_define_options(self, defines: Mapping[str, object]) -> _Command: return [ f"+define+{name}={_as_sv_literal(value)}" for name, value in defines.items() ] def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command: return [ f"-defparam {name}={_as_sv_literal(value)}" for name, value in parameters.items() ] @property def sim_file(self) -> Path: return self.build_dir / "image.so" def _use_external_viewer(self) -> bool: return True def _waves_file(self) -> Optional[str]: return "file.vcd" def _test_command(self) -> List[_Command]: if self.pre_cmd is not None: raise RuntimeError("pre_cmd is not implemented for DSim.") plusargs = self.plusargs if self.waves or self.gui: plusargs += [f"-waves {self._waves_file()}"] if self.timescale: plusargs += ["-timescale {}/{}".format(*self.timescale)] return [ [ "dsim", "-work", str(self.build_dir), "-pli_lib", cocotb_tools.config.lib_name_path("vpi", "dsim").as_posix(), "+acc+rwcbfsWF", "-image", "image", *self.test_args, *plusargs, ] ] def _build_command(self) -> List[_Command]: sources = self._sources + self._verilog_sources for source in sources: if source.tag is not Verilog: raise ValueError( f"{type(self).__qualname__} only supports Verilog. {str(source.value)!r} cannot be compiled." ) for arg in self._build_args: if arg.tag not in (Verilog, None): raise ValueError( f"{type(self).__qualname__} only supports Verilog. build_args {arg!r} cannot be applied." ) cmds: list[_Command] = [] if outdated(self.sim_file, (source.value for source in sources)) or self.always: cmds = [ [ "dsim", "-work", str(self.build_dir), "-pli_lib", cocotb_tools.config.lib_name_path("vpi", "dsim").as_posix(), "+acc+rwcbfsWF", "-genimage", "image", ] + self._get_define_options(self.defines) + self._get_include_options(self.includes) + self._get_parameter_options(self.parameters) + [arg.value for arg in self._build_args] + [str(source_file.value) for source_file in sources] ] else: self.log.warning("Skipping compilation of %s", self.sim_file) return cmds def get_runner(simulator_name: str) -> Runner: """Return an instance of a runner for *simulator_name*. Args: simulator_name: Name of simulator to get runner for. Raises: ValueError: If *simulator_name* is not one of the supported simulators or an alias of one. """ supported_sims: Dict[str, Type[Runner]] = { "icarus": Icarus, "questa": Questa, "ghdl": Ghdl, "riviera": Riviera, "verilator": Verilator, "xcelium": Xcelium, "nvc": Nvc, "vcs": Vcs, "dsim": Dsim, # TODO: "activehdl": ActiveHdl, } try: return supported_sims[simulator_name]() except KeyError: raise ValueError( f"Simulator {simulator_name!r} is not in supported list: {', '.join(supported_sims)}" ) from None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/cocotb_tools/sim_versions.py0000644000175100017510000000743315106067236021020 0ustar00runnerrunner# Copyright cocotb contributors # Licensed under the Revised BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-3-Clause # type: ignore # distutils is untyped, so there's little reason to check this file """ Classes to compare simulation versions. These are for cocotb-internal use only. .. warning:: These classes silently allow comparing versions of different simulators. """ from cocotb_tools._vendor.distutils_version import LooseVersion class ActivehdlVersion(LooseVersion): """Version numbering class for Aldec Active-HDL. NOTE: unsupported versions exist, e.g. ActivehdlVersion("10.5a.12.6914") > ActivehdlVersion("10.5.216.6767") """ class CvcVersion(LooseVersion): """Version numbering class for Tachyon DA CVC. Example: >>> CvcVersion( ... "OSS_CVC_7.00b-x86_64-rhel6x of 07/07/14 (Linux-elf)" ... ) > CvcVersion("OSS_CVC_7.00a-x86_64-rhel6x of 07/07/14 (Linux-elf)") True """ class GhdlVersion(LooseVersion): """Version numbering class for GHDL.""" class IcarusVersion(LooseVersion): """Version numbering class for Icarus Verilog. Example: >>> IcarusVersion("11.0 (devel)") > IcarusVersion("10.3 (stable)") True >>> IcarusVersion("10.3 (stable)") <= IcarusVersion("10.3 (stable)") True """ class ModelsimVersion(LooseVersion): """Version numbering class for Mentor ModelSim.""" class QuestaVersion(LooseVersion): """Version numbering class for Mentor Questa. Example: >>> QuestaVersion("10.7c 2018.08") > QuestaVersion("10.7b 2018.06") True >>> QuestaVersion("2020.1 2020.01") > QuestaVersion("10.7c 2018.08") True >>> QuestaVersion("2020.1 2020.01") == QuestaVersion("2020.1") True >>> QuestaVersion("2023.1_2 2023.03") > QuestaVersion("2023.1_1") True """ def parse(self, vstring): # A Questa version string, as returned by the simulator, consists of two # space-separated parts. The first part is the actual version number, # the second part seems to be the year and month of the initial release. # We only need the first part, which is also used in public # communication by Siemens. try: first_component = vstring.split(" ", 1)[0] except IndexError: first_component = vstring super().parse(first_component) class RivieraVersion(LooseVersion): """Version numbering class for Aldec Riviera-PRO. Example: >>> RivieraVersion("2019.10.138.7537") == RivieraVersion("2019.10.138.7537") True """ class VcsVersion(LooseVersion): """Version numbering class for Synopsys VCS. Example: >>> VcsVersion("Q-2020.03-1_Full64") > VcsVersion("K-2015.09_Full64") True """ class VerilatorVersion(LooseVersion): """Version numbering class for Verilator. Example: >>> VerilatorVersion("4.032 2020-04-04") > VerilatorVersion("4.031 devel") True """ class XceliumVersion(LooseVersion): """Version numbering class for Cadence Xcelium. Example: >>> XceliumVersion("20.06-g183") > XceliumVersion("20.03-s002") True >>> XceliumVersion("20.07-e501") > XceliumVersion("20.06-g183") True """ class IusVersion(XceliumVersion): # inherit everything from Xcelium """Version numbering class for Cadence IUS. Example: >>> IusVersion("15.20-s050") > IusVersion("15.20-s049") True """ class NvcVersion(LooseVersion): """Version numbering class for NVC.""" @classmethod def from_commandline(cls, cmdline): firstline = cmdline.split("\n")[0] sim, version, *version_extra = firstline.strip().split(" ") assert sim == "nvc" return cls(version) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1763209677.3587027 cocotb-2.0.1/src/pygpi/0000755000175100017510000000000015106070715014352 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/pygpi/__init__.py0000644000175100017510000000000015106067236016455 0ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/pygpi/entry.py0000644000175100017510000000310215106067236016065 0ustar00runnerrunnerimport importlib import operator import os from typing import Callable, List, Tuple def load_entry(argv: List[str]) -> None: """Gather entry point information by parsing :envvar:`PYGPI_USERS`.""" entry_point_str = os.environ.get( "PYGPI_USERS", ",".join( ( "cocotb_tools._coverage:start_cocotb_library_coverage", "cocotb.logging:_configure", "cocotb._init:init_package_from_simulation", "cocotb._init:run_regression", ) ), ) # Parse the entry point string of the form "module:func,module:func,...". # Any failure prevents any entry points from being loaded. entry_points: List[Tuple[str, str]] = [] try: entry_points_str = entry_point_str.split(",") for entry_point_str in entry_points_str: entry_module_str, entry_func_str = entry_point_str.split(":") # TODO maybe some basic validation of the module and function names. # WITHOUT IMPORTING THEM. entry_points.append((entry_module_str, entry_func_str)) except Exception as e: raise RuntimeError(f"Failure to parse PYGPI_USERS ('{entry_point_str}')") from e # Run all entry points. # Expect failure to stop the loading of any additional entry points. for entry_module_str, entry_func_str in entry_points: entry_module = importlib.import_module(entry_module_str) entry_func: Callable[[List[str]], object] = operator.attrgetter(entry_func_str)( entry_module ) entry_func(argv) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1763208862.0 cocotb-2.0.1/src/pygpi/py.typed0000644000175100017510000000000015106067236016043 0ustar00runnerrunner