[
  {
    "path": ".backportrc.json",
    "content": "// Documentation at\n// https://github.com/sorenlouv/backport/blob/main/docs/config-file-options.md\n// Comments are allowed, trailing commas are not.\n{\n  \"repoOwner\": \"cocotb\",\n  \"repoName\": \"cocotb\",\n\n  // Branches to backport to.\n  \"targetBranchChoices\": [\n    \"stable/1.9\"\n  ],\n\n  // Use `backport-to:VERSION` as indication of the target branch.\n  // Also update .github/workflows/backport.yml when changing the label here.\n  \"branchLabelMapping\": {\n    \"^backport-to:(\\\\d+\\\\.\\\\d+)$\": \"stable/$1\"\n  },\n\n  // Labels assigned to the source PR after opening the backport PR(s).\n  \"sourcePRLabels\": [\"status:backport-created\"],\n\n  // In GitHub PR comments made by the bot suggest that users run\n  // \"npx backport\", which automatically installs backport if necessary.\n  \"backportBinary\": \"npx backport\",\n\n  // Leave a note in the source PR if a backport failed.\n  \"publishStatusCommentOnFailure\": true,\n\n  // Title of the backport PR(s).\n  \"prTitle\": \"[{{targetBranch}}] Backport PR #{{sourcePullRequest.number}}: {{sourcePullRequest.title}}\",\n\n  // Labels added to the newly created backport PR(s).\n  \"targetPRLabels\": [\"type:backport\"],\n\n  // Default reviewers.\n  \"reviewers\": [\"cocotb/maintainers\"]\n}\n"
  },
  {
    "path": ".clang-format",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nBasedOnStyle: Google\nIndentWidth: 4\nAccessModifierOffset: -2\nPointerAlignment: Right\n"
  },
  {
    "path": ".codecov.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Codecov configuration\ncodecov:\n    notify:\n        # Codecov claims [1] to wait until all CI runs have completed, but that\n        # doesn't work for our CI setup, causing early reports to come in which\n        # indicate a drop in coverage. These reports are later updated as more\n        # reports come in. But by that time the first issue comment has already\n        # been made and an email has been sent. Prevent that by explicitly\n        # specifying the number of builds that need to be uploaded to codecov\n        # [2].\n        #\n        # Keep this number in sync with the CI configuration!\n        #\n        # The number should be the same as the total number of tests belonging\n        # to \"ci-free\" and \"ci-licensed\".\n        #\n        # [1] https://docs.codecov.io/docs/merging-reports#how-does-codecov-know-when-to-send-notifications\n        # [2] https://docs.codecov.io/docs/notifications#preventing-notifications-until-after-n-builds\n        after_n_builds: 24\n\ncoverage:\n    status:\n        project:\n            default:\n                # Report a CI failure if coverage drops by more than 1 percent.\n                threshold: 1%\n"
  },
  {
    "path": ".devcontainer/Dockerfile",
    "content": "ARG VERILATOR_VERSION=5.044\nARG UV_VERSION=0.10.2\n\n# Container images used only to copy binaries out of it (see below).\nFROM verilator/verilator:v${VERILATOR_VERSION} AS verilator\nFROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv\n\n# See https://github.com/devcontainers/images/tree/main/src/base-ubuntu/history\n# for a description of what's in this base image.\nFROM mcr.microsoft.com/devcontainers/base:2-ubuntu-24.04\n\nRUN apt-get update && export DEBIAN_FRONTEND=noninteractive \\\n    && apt-get -y install --no-install-recommends \\\n        bear \\\n        bison  \\\n        build-essential \\\n        ccache \\\n        clang \\\n        clangd \\\n        colordiff \\\n        doxygen \\\n        flex \\\n        gdb \\\n        gdb \\\n        gh \\\n        ghdl \\\n        git \\\n        git-absorb \\\n        gperf  \\\n        graphviz \\\n        iverilog \\\n        libenchant-2-dev \\\n        lldb \\\n        pre-commit \\\n        python3-dev \\\n        python3-pip \\\n        python3-venv \\\n        valgrind \\\n    && apt-get clean && rm -rf /var/lib/apt/lists/*\n\n# Install UV from the official uv container image.\nCOPY --from=uv /uv /uvx /usr/local/bin/\n\n# Install Verilator from official Verilator container image.\nCOPY --from=verilator /usr/local/share/verilator /usr/local/share/verilator\nCOPY --from=verilator /usr/local/bin/verilator* /usr/local/bin/\nCOPY --from=verilator /usr/local/share/man /usr/local/share/man\nCOPY --from=verilator /usr/local/share/pkgconfig/verilator.pc /usr/local/share/pkgconfig\n\n# Install NVC from an upstream Debian package.\n# (Use apt instead of dpkg to resolve dependencies automatically.)\nARG NVC_VERSION=1.18.2\nARG NVC_SHA256=bb6f19a84a398e13c56649996262db63ed9787e19dd0ad894774e132e170b785\nRUN mkdir -p /tmp/nvc-install \\\n    && curl -SLo /tmp/nvc-install/nvc.deb \"https://github.com/nickg/nvc/releases/download/r${NVC_VERSION}/nvc_${NVC_VERSION}-1_amd64_ubuntu-24.04.deb\" \\\n    && echo \"${NVC_SHA256} /tmp/nvc-install/nvc.deb\" | sha256sum --check \\\n    && apt-get update && export DEBIAN_FRONTEND=noninteractive \\\n    && apt -y install --no-install-recommends /tmp/nvc-install/nvc.deb \\\n    && apt-get clean && rm -rf /var/lib/apt/lists/* \\\n    && rm -rf /tmp/nvc-install\n"
  },
  {
    "path": ".devcontainer/README.md",
    "content": "# Cocotb Development Environment in a Dev Container\n\nThe Dev Container provides a ready-to-code development environment for cocotb on Windows, Mac, or Linux.\nDev Containers combine VS Code with (Docker) containers and configuration within the cocotb repository.\n\nBy default, Dev Containers cannot access files on your local machine;\nif you want to use proprietary simulators installed on your machine, you might be better off with a development environment on your machine itself.\n\n## What's included in the Dev Container?\n\n* Ubuntu 24.04\n* Compilers: GCC and clang\n* Open-source simulators: GHDL, Icarus Verilog, Verilator, NVC\n* Productivity tools: GDB, LLDB, Valgrind, [Bear](https://github.com/rizsotto/Bear)\n\n## Getting started\n\nYou need VS Code and the Dev Containers extension to run the Dev Container on your local machine.\nFollow the [Dev Containers Getting Started documentation](https://code.visualstudio.com/docs/devcontainers/containers#_getting-started) documentation to install all required tools.\n\nThen start the Dev Container:\n* Open VS Code\n* Open the command palette (F1)\n* Type `Dev Containers: Clone Repository in Container Volume...` and press ENTER.\n* Enter the repository URL `https://github.com/cocotb/cocotb` and press ENTER again.\n* Wait for a short moment until the Dev Container is ready to be used.\n\nNote: On Linux you can alternatively clone the Git repository on your local machine and open the folder in a container.\nWe don't recommend that on Windows or Mac to get good filesystem performance ([learn more](https://code.visualstudio.com/remote/advancedcontainers/improve-performance)).\n\nAfter the Dev Container startup completed **open a new terminal** to run a first cocotb test.\nNote: *Do not* reuse the `Welcome to Codespaces` terminal you might see -- it does not have an active Python venv and commands will fail.\n\n```\ncd examples/simple_dff\nmake WAVES=1 SIM=iverlog\ncode sim_build/dff.fst\n```\n"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "content": "// VS Code Dev Container configuration file for a cocotb development environment.\n{\n\t\"name\": \"cocotb development\",\n\t\"build\": {\n\t\t\"context\": \"..\",\n\t\t\"dockerfile\": \"Dockerfile\"\n\t},\n\t\"postCreateCommand\": \".devcontainer/post-create.sh\",\n\t\"postAttachCommand\": \"less .devcontainer/README.md\",\n\t\"customizations\": {\n\t\t\"vscode\": {\n\t\t\t\"extensions\": [\n\t\t\t\t\"llvm-vs-code-extensions.vscode-clangd\",\n\t\t\t\t\"ms-python.python\",\n\t\t\t\t\"ms-python.vscode-pylance\",\n\t\t\t\t\"lramseyer.vaporview\"\n\t\t\t],\n\t\t\t\"settings\": {\n\t\t\t\t\"tasks\": {\n\t\t\t\t\t// See https://go.microsoft.com/fwlink/?LinkId=733558\n\t\t\t\t\t// for the documentation about the tasks.json format\n\t\t\t\t\t\"version\": \"2.0.0\",\n\t\t\t\t\t\"tasks\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"label\": \"Preview documentation\",\n\t\t\t\t\t\t\t\"type\": \"shell\",\n\t\t\t\t\t\t\t// Run the docs_preview nox session with the virtual environment's Python\n\t\t\t\t\t\t\t// (if it exists).\n\t\t\t\t\t\t\t\"command\": \"PATH=.venv/bin:$PATH nox -s docs_preview\",\n\t\t\t\t\t\t\t\"isBackground\": true\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"files.exclude\": {\n\t\t\t\t\t\"**/.venv\": true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": ".devcontainer/post-create.sh",
    "content": "#!/bin/bash\nset -eo pipefail\n\n# Create and activate a virtual environment.\npython3 -m venv --prompt cocotb-devenv .venv\n. .venv/bin/activate\n\n# Install prerequisites and development tools.\npre-commit install\npip3 install nox pytest\n\n# Install cocotb in editable mode.\nbear -- pip3 install -e .\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# The following command will configure your local git repo to ignore these commits\n# when doing git-blame.\n#     git config blame.ignoreRevsFile .git-blame-ignore-revs\n\n# clang-format\n78e69fa428477b73808d08aec0e6702a924497f8\n# black and isort\n720b0e1071d0c720e61fa50fcb1813fd99198f20\n# ruff\neb254d7581b64e5384ee87f49d4363d72be6e20a\n785e0896930039023db3c2e2be47bed5375326c5\n0f943a324a997bb31dcd55831b51b393d5435965\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\n\nThanks for improving cocotb! Here are some points to make this as smooth as possible.\nNot all of them may be applicable.\n\nMost important: please explain *why* you are proposing this change.\n\n* Make sure you have read https://github.com/cocotb/cocotb/blob/master/CONTRIBUTING.md\n* Extend or add a test under `tests/test_cases/`.\n* Add documentation under `docs/source/`,\n  docstrings in Python code, or Doxygen markup in C/C++ code.\n  Use ``versionadded``/``versionchanged``/``deprecated``.\n* Add a newsfragment - see `docs/source/newsfragments/README.rst`.\n* Use `closes #XXXX` to auto-close the issue that this PR fixes (if such).\n\n-->\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nversion: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    cooldown:\n      default-days: 7\n  - package-ecosystem: \"uv\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    cooldown:\n      default-days: 7\n    versioning-strategy: lockfile-only\n    groups:\n      updates:\n        applies-to: version-updates\n        patterns:\n          - \"*\"\n        update-types:\n          - \"minor\"\n          - \"patch\"\n"
  },
  {
    "path": ".github/generate-envs.py",
    "content": "#!/usr/bin/env python3\n# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Generate a list of test environments.\n\nEach environment must contain the following fields:\n- lang: The TOPLEVEL_LANG of the test. Must be one of \"verilog\" or \"vhdl\".\n- sim: The SIM of the test. Must be one of \"icarus\", \"ghdl\", \"nvc\", \"verilator\", \"riviera\", \"questa\", \"xcelium\", or \"vcs\".\n- sim-version: The version of the simulator to use. Valid values depend upon the simulator and build recipe.\n- os: The OS to operate on. Must be a valid value for the \"jobs.<job_name>.runs-on\" field for Github Actions.\n- python-version: The Python version to test with. Must be a valid value for the \"python-version\" field of the \"actions/setup-python\" Github Action.\n- group: The group to run the test in. One of \"ci-free\", \"ci-licensed\", \"experimental\", or \"extended\". See below note.\n\nOptional fields:\n- self-hosted: True if test needs to be run on a self-hosted Github Action runner. Default: False.\n- cc: C compiler and linker to use. Default: gcc.\n- cxx: C++ compiler and linker to use. Default: g++.\n- extra_name: Additional tag prepended to computed name for test. Default: <none>.\n\nWhat tests belong in what groups:\n- ci-free: The most recent stable release of a given free simulator, all supported versions of Python, and all supported operating systems. Run on all PRs and master pushes.\n- ci-licensed: The most recent stable release of a given licensed simulator. Run on all PRs and master pushes in the cocotb repo, but are skipped in forks.\n- experimental: Development HEAD for each simulator, any under-development version of Python, and under-development simulator. Run weekly.\n- extended: The minimum supoprted version of a simulator, and a smattering of released simulator versions between the minimum and most recent. Run weekly.\n\nIdeally, whenever a new version of a simulator is released, a new test should be added for that simulator.\nThe current test in the \"ci-free\"/\"ci-licensed\" group should be moved to \"extended\",\nand the new version should be added to \"ci-free\"/\"ci-licensed\" and any changes in behavior recorded with expectations to make CI pass.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport sys\n\nENVS = [\n    # Test different Python versions with package managed Icarus on Ubuntu\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"nvc\",\n        \"sim-version\": \"r1.19.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-free\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"nvc\",\n        \"sim-version\": \"r1.19.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.10\",\n        \"group\": \"ci-free\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"nvc\",\n        \"sim-version\": \"r1.19.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.11\",\n        \"group\": \"ci-free\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"nvc\",\n        \"sim-version\": \"r1.19.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.12\",\n        \"group\": \"ci-free\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"nvc\",\n        \"sim-version\": \"r1.19.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.13\",\n        \"group\": \"ci-free\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"nvc\",\n        \"sim-version\": \"r1.19.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.14\",\n        \"group\": \"ci-free\",\n    },\n    # {\n    #     \"lang\": \"vhdl\",\n    #     \"sim\": \"nvc\",\n    #     \"sim-version\": \"r1.17.1\",\n    #     \"os\": \"ubuntu-22.04\",\n    #     \"python-version\": \"3.15\",\n    #     \"group\": \"experimental\",\n    # },\n    # Test Icarus on Ubuntu\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"icarus\",\n        \"sim-version\": \"v11_0\",  # Minimum supported version\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.9\",\n        \"group\": \"extended\",\n    },\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"icarus\",\n        \"sim-version\": \"v13_0\",  # The latest release version.\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-free\",\n    },\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"icarus\",\n        \"sim-version\": \"master\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.9\",\n        \"group\": \"experimental\",\n    },\n    # Test GHDL on Ubuntu\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"ghdl\",\n        \"sim-version\": \"v2.0.0\",  # GHDL 2.0 is the minimum supported version.\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.9\",\n        \"group\": \"extended\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"ghdl\",\n        \"sim-version\": \"v5.1.1\",  # The latest release version.\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-free\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"ghdl\",\n        \"sim-version\": \"master\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.9\",\n        \"group\": \"experimental\",\n    },\n    # Testing latest release is covered by the Python version tests\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"nvc\",\n        \"sim-version\": \"master\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.9\",\n        \"group\": \"experimental\",\n    },\n    # Test Verilator on Ubuntu\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"verilator\",\n        \"sim-version\": \"v5.046\",  # Latest release version.\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.10\",\n        \"group\": \"ci-free\",\n    },\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"verilator\",\n        \"sim-version\": \"master\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.10\",\n        \"group\": \"experimental\",\n    },\n    # Test other OSes\n    # Icarus homebrew (ARM64)\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"icarus\",\n        \"sim-version\": \"homebrew-stable\",\n        \"os\": \"macos-14\",\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-free\",\n    },\n    # Icarus homebrew (ARM64) (HEAD/master)\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"icarus\",\n        \"sim-version\": \"homebrew-HEAD\",\n        \"os\": \"macos-14\",\n        \"python-version\": \"3.9\",\n        \"group\": \"experimental\",\n    },\n    # Verilator macOS (ARM64) HEAD\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"verilator\",\n        \"sim-version\": \"master\",\n        \"os\": \"macos-14\",\n        \"python-version\": \"3.9\",\n        \"group\": \"experimental\",\n    },\n    # Verilator macOS (ARM64) latest release\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"verilator\",\n        \"sim-version\": \"v5.046\",\n        \"os\": \"macos-14\",\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-free\",\n    },\n    # Icarus homebrew (x86)\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"icarus\",\n        \"sim-version\": \"homebrew-stable\",\n        \"os\": \"macos-15-intel\",\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-free\",\n    },\n    # Icarus windows from source\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"icarus\",\n        \"sim-version\": \"v13_0\",\n        \"os\": \"windows-latest\",\n        \"python-version\": \"3.11\",\n        \"toolchain\": \"mingw\",\n        \"extra-name\": \"mingw\",\n        \"group\": \"ci-free\",\n    },\n    # use msvc instead of mingw\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"icarus\",\n        \"sim-version\": \"v13_0\",\n        \"os\": \"windows-latest\",\n        \"python-version\": \"3.11\",\n        \"toolchain\": \"msvc\",\n        \"extra-name\": \"msvc\",\n        \"group\": \"ci-free\",\n    },\n    # NVC on windows\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"nvc\",\n        \"sim-version\": \"r1.19.2\",\n        \"os\": \"windows-latest\",\n        \"python-version\": \"3.11\",\n        \"group\": \"ci-free\",\n    },\n    # Other\n    # use clang instead of gcc\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"nvc\",\n        \"sim-version\": \"r1.19.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"python-version\": \"3.9\",\n        \"cxx\": \"clang++\",\n        \"cc\": \"clang\",\n        \"extra-name\": \"clang\",\n        \"group\": \"ci-free\",\n    },\n    # Test Siemens Questa on Ubuntu\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"questa\",\n        \"sim-version\": \"siemens/questa/2025.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"self-hosted\": True,\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-licensed\",\n    },\n    {\n        \"lang\": \"vhdl and fli\",\n        \"sim\": \"questa\",\n        \"sim-version\": \"siemens/questa/2025.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"self-hosted\": True,\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-licensed\",\n    },\n    {\n        \"lang\": \"vhdl and vhpi\",\n        \"sim\": \"questa\",\n        \"sim-version\": \"siemens/questa/2025.2\",\n        \"os\": \"ubuntu-22.04\",\n        \"self-hosted\": True,\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-licensed\",\n    },\n    # Test Aldec Riviera-PRO on Ubuntu\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"riviera\",\n        \"sim-version\": \"aldec/rivierapro/2025.10\",\n        \"os\": \"ubuntu-22.04\",\n        \"self-hosted\": True,\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-licensed\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"riviera\",\n        \"sim-version\": \"aldec/rivierapro/2025.10\",\n        \"os\": \"ubuntu-22.04\",\n        \"self-hosted\": True,\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-licensed\",\n    },\n    # Test Cadence Xcelium on Ubuntu\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"xcelium\",\n        \"sim-version\": \"cadence/xcelium/2509\",\n        \"os\": \"ubuntu-22.04\",\n        \"self-hosted\": True,\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-licensed\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"xcelium\",\n        \"sim-version\": \"cadence/xcelium/2509\",\n        \"os\": \"ubuntu-22.04\",\n        \"self-hosted\": True,\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-licensed\",\n    },\n    # Test Synopsys VCS on Ubuntu\n    {\n        \"lang\": \"verilog\",\n        \"sim\": \"vcs\",\n        \"sim-version\": \"synopsys/vcs/X-2025.06\",\n        \"os\": \"ubuntu-22.04\",\n        \"self-hosted\": True,\n        \"python-version\": \"3.9\",\n        \"group\": \"ci-licensed\",\n    },\n    {\n        \"lang\": \"vhdl\",\n        \"sim\": \"vcs\",\n        \"sim-version\": \"synopsys/vcs/X-2025.06\",\n        \"os\": \"ubuntu-22.04\",\n        \"self-hosted\": True,\n        \"python-version\": \"3.9\",\n        \"group\": \"experimental\",\n    },\n]\n\nghdl_versions = (\"v3.0.0\", \"v4.1.0\")\nfor version in ghdl_versions:\n    ENVS += [\n        {\n            \"lang\": \"vhdl\",\n            \"sim\": \"ghdl\",\n            \"sim-version\": version,\n            \"os\": \"ubuntu-22.04\",\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n    ]\n\nicarus_versions = (\"v12_0\",)\nfor version in icarus_versions:\n    ENVS += [\n        {\n            \"lang\": \"verilog\",\n            \"sim\": \"icarus\",\n            \"sim-version\": version,\n            \"os\": \"ubuntu-22.04\",\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n    ]\n\nverilator_versions = (\"v5.036\", \"v5.038\", \"v5.040\", \"v5.042\", \"v5.044\")\nfor version in verilator_versions:\n    ENVS += [\n        {\n            \"lang\": \"verilog\",\n            \"sim\": \"verilator\",\n            \"sim-version\": version,\n            \"os\": \"ubuntu-22.04\",\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n    ]\n\nnvc_versions = (\n    \"r1.11.0\",\n    \"r1.12.2\",\n    \"r1.13.3\",\n    \"r1.14.2\",\n    \"r1.15.2\",\n    \"r1.16.0\",  # First version with --preserve-case\n    \"r1.17.1\",\n    \"r1.18.2\",\n)\nfor version in nvc_versions:\n    ENVS += [\n        {\n            \"lang\": \"vhdl\",\n            \"sim\": \"nvc\",\n            \"sim-version\": version,\n            \"os\": \"ubuntu-22.04\",\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n    ]\n\n# Questa: test more versions as part of the extended tests.\nquesta_versions_novhpi = (\"2021.2\", \"2021.3\", \"2021.4\", \"2022.1\", \"2022.2\")\nquesta_versions_vhpi = (\n    \"2022.3\",\n    \"2022.4\",\n    \"2023.1\",\n    \"2023.2\",\n    \"2023.4\",\n    \"2024.1\",\n    \"2024.2\",\n)\n\nfor version in questa_versions_novhpi + questa_versions_vhpi:\n    ENVS += [\n        {\n            \"lang\": \"verilog\",\n            \"sim\": \"questa\",\n            \"sim-version\": f\"siemens/questa/{version}\",\n            \"os\": \"ubuntu-22.04\",\n            \"self-hosted\": True,\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n        {\n            \"lang\": \"vhdl and fli\",\n            \"sim\": \"questa\",\n            \"sim-version\": f\"siemens/questa/{version}\",\n            \"os\": \"ubuntu-22.04\",\n            \"self-hosted\": True,\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n    ]\nfor version in questa_versions_vhpi:\n    ENVS += [\n        {\n            \"lang\": \"vhdl and vhpi\",\n            \"sim\": \"questa\",\n            \"sim-version\": f\"siemens/questa/{version}\",\n            \"os\": \"ubuntu-22.04\",\n            \"self-hosted\": True,\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n    ]\n\n# Riviera-PRO: test more versions as part of the extended tests.\nriviera_versions = (\n    \"2019.10\",\n    \"2020.04\",\n    \"2020.10\",\n    \"2021.04\",\n    \"2021.10\",\n    \"2022.04\",\n    \"2023.10\",\n    \"2024.04\",\n    \"2024.10\",\n    \"2025.04\",\n)\nfor version in riviera_versions:\n    ENVS += [\n        {\n            \"lang\": \"verilog\",\n            \"sim\": \"riviera\",\n            \"sim-version\": f\"aldec/rivierapro/{version}\",\n            \"os\": \"ubuntu-22.04\",\n            \"self-hosted\": True,\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n        {\n            \"lang\": \"vhdl\",\n            \"sim\": \"riviera\",\n            \"sim-version\": f\"aldec/rivierapro/{version}\",\n            \"os\": \"ubuntu-22.04\",\n            \"self-hosted\": True,\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n    ]\n\n# Xcelium: test more versions as part of the extended tests.\nxcelium_versions = (\"2309\", \"2403\", \"2503\")\nfor version in xcelium_versions:\n    ENVS += [\n        {\n            \"lang\": \"verilog\",\n            \"sim\": \"xcelium\",\n            \"sim-version\": f\"cadence/xcelium/{version}\",\n            \"os\": \"ubuntu-22.04\",\n            \"self-hosted\": True,\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n        {\n            \"lang\": \"vhdl\",\n            \"sim\": \"xcelium\",\n            \"sim-version\": f\"cadence/xcelium/{version}\",\n            \"os\": \"ubuntu-22.04\",\n            \"self-hosted\": True,\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n    ]\n\n# VCS: test more versions as part of the extended tests.\nvcs_versions = (\"W-2024.09\",)\nfor version in vcs_versions:\n    ENVS += [\n        {\n            \"lang\": \"verilog\",\n            \"sim\": \"vcs\",\n            \"sim-version\": f\"synopsys/vcs/{version}\",\n            \"os\": \"ubuntu-22.04\",\n            \"self-hosted\": True,\n            \"python-version\": \"3.9\",\n            \"group\": \"extended\",\n        },\n        # Don't run extended tests for VCS/VHDL yet until we have a version that\n        # works.\n    ]\n\n\ndef append_str_val(listref, my_list, key) -> None:\n    if key not in my_list:\n        return\n    listref.append(str(my_list[key]))\n\n\ndef main() -> int:\n    parser = argparse.ArgumentParser(description=__doc__)\n    parser.add_argument(\"--group\")\n    parser.add_argument(\"--output-format\", choices=(\"gha\", \"json\"), default=\"json\")\n    parser.add_argument(\n        \"--gha-output-file\",\n        type=argparse.FileType(\"a\", encoding=\"utf-8\"),\n        help=\"The $GITHUB_OUTPUT file.\",\n    )\n\n    args = parser.parse_args()\n\n    if args.group is not None and args.group != \"\":\n        selected_envs = [t for t in ENVS if \"group\" in t and t[\"group\"] == args.group]\n    else:\n        # Return all tasks if no group is selected.\n        selected_envs = ENVS\n\n    for env in selected_envs:\n        # The \"runs-on\" job attribute is a string if we're using the GitHub-\n        # provided hosted runners, or an array with special keys if we're\n        # using self-hosted runners.\n        if \"self-hosted\" in env and env[\"self-hosted\"] and \"runs-on\" not in env:\n            env[\"runs-on\"] = [\"self-hosted\", f\"cocotb-private-{env['os']}\"]\n        else:\n            env[\"runs-on\"] = env[\"os\"]\n\n        # Assemble the human-readable name of the job.\n        name_parts = []\n        append_str_val(name_parts, env, \"extra-name\")\n        append_str_val(name_parts, env, \"sim\")\n        if \"/\" in env[\"sim-version\"]:\n            # Shorten versions like 'siemens/questa/2023.2' to '2023.2'.\n            name_parts.append(env[\"sim-version\"].split(\"/\")[-1])\n        else:\n            name_parts.append(env[\"sim-version\"])\n        append_str_val(name_parts, env, \"lang\")\n        append_str_val(name_parts, env, \"os\")\n        append_str_val(name_parts, env, \"python-version\")\n        if env.get(\"may-fail\") is not None:\n            name_parts.append(\"May fail\")\n\n        env[\"name\"] = \"|\".join(name_parts)\n\n    if args.output_format == \"gha\":\n        # Output for GitHub Actions (GHA). Appends the configuration to\n        # the file named in the \"--gha-output-file\" argument.\n\n        assert args.gha_output_file is not None\n\n        # The generated JSON output may not contain newlines to be parsed by GHA\n        print(f\"envs={json.dumps(selected_envs)}\", file=args.gha_output_file)\n\n        # Print the the selected environments for easier debugging.\n        print(\"Generated the following test configurations:\")\n        print(json.dumps(selected_envs, indent=2))\n    elif args.output_format == \"json\":\n        print(json.dumps(selected_envs, indent=2))\n    else:\n        assert False\n\n    return 0\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n"
  },
  {
    "path": ".github/issue_template.md",
    "content": "<!--\nIn case you are reporting a problem with running cocotb,\nplease remember to add relevant information about your environment, such as\n* the cocotb version used,\n* the operating system and version (32/64 bit),\n* the simulator and version (32/64 bit),\n* the Python version, and where it's coming from (e.g. system, Anaconda, self-installed, ...),\n* (part of) the log file (cleaned of proprietary information).\nIf you are unsure about any of the above items, open the issue anyway and we will figure it out together.\nThanks for helping improve cocotb!\n-->\n"
  },
  {
    "path": ".github/workflows/backport.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# A workflow to automatically backport pull requests to a stable branch.\n#\n# This workflow uses the Backport CLI (https://github.com/sorenlouv/backport)\n# under the hood, which is configured in `.backportrc.json` in the repository\n# root.\n#\n# See https://github.com/sorenlouv/backport-github-action for documentation\n# on the used action.\n\nname: Backport PRs to stable branches\n\non:\n  pull_request_target:\n    # Run this workflow when a label on a PR is added, or if it's closed.\n    types: [\"labeled\", \"closed\"]\n\njobs:\n  backport:\n    name: Backport PR\n    if: github.event.pull_request.merged == true\n    runs-on: ubuntu-latest\n    steps:\n      # Run the backport action only on PRs with one of the `backport-to:`\n      # labels applied.\n      #\n      # Also update `branchLabelMapping` in `.backportrc.json` when changing the\n      # label here.\n      #\n      # Implementation note: GitHub's contains() is matching the full string\n      # when operating on an array (and startsWith() does not operate on arrays\n      # at all). Do the label matching with jq instead.\n      - name: Check for backport labels\n        id: check_labels\n        run: |-\n          labels='${{ toJSON(github.event.pull_request.labels.*.name) }}'\n          matched=$(echo $labels | jq '.|map(select(startswith(\"backport-to:\"))) | length')\n          echo \"matched=$matched\"\n          echo \"matched=$matched\" >> $GITHUB_OUTPUT\n\n      - name: Backport Action\n        if: fromJSON(steps.check_labels.outputs.matched) > 0\n        uses: sorenlouv/backport-github-action@9460b7102fea25466026ce806c9ebf873ac48721  # v11.0.0\n        with:\n          # GITHUB_TOKEN is available by default, but the powers it has are\n          # configurable. Follow the GitHub documentation at\n          # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#setting-the-permissions-of-the-github_token-for-your-repository\n          # to \"Allow GitHub Actions to create and approve pull requests\".\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Info log\n        if: ${{ fromJSON(steps.check_labels.outputs.matched) > 0 && success() }}\n        run: cat ~/.backport/backport.info.log\n\n      - name: Debug log\n        if: ${{ fromJSON(steps.check_labels.outputs.matched) > 0 && failure() }}\n        run: cat ~/.backport/backport.debug.log\n"
  },
  {
    "path": ".github/workflows/benchmark.yml",
    "content": "name: Performance Benchmark\n# adapted from https://github.com/benchmark-action/github-action-benchmark#charts-on-github-pages-1\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }}\n  cancel-in-progress: ${{ !(contains(github.ref, 'release/') || contains(github.ref, 'master')) }}\n\non:\n  push:\n    branches:\n    - master\n  pull_request:\n    branches:\n      - master\n\njobs:\n\n  tests:\n    if: github.repository == 'cocotb/cocotb'\n    name: Python ${{matrix.python-version}}\n    runs-on: ubuntu-22.04\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - python-version: 3.9\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2\n    - name: Set up Python ${{matrix.python-version}}\n      uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0\n      with:\n        python-version: ${{matrix.python-version}}\n\n    - name: Install Icarus Verilog\n      run: |\n        sudo apt-get install -y --no-install-recommends iverilog\n\n    - name: Set up NVC (Ubuntu)\n      run: |\n        sudo apt-get install -y --no-install-recommends llvm-dev libdw-dev flex libzstd-dev pkg-config\n        git clone https://github.com/nickg/nvc.git\n        cd nvc\n        git reset --hard r1.16.0\n        ./autogen.sh\n        mkdir build\n        cd build\n        ../configure\n        make -j $(nproc)\n        sudo make install\n\n    - name: Run benchmark\n      run: |\n        pip install pytest pytest-benchmark\n        pip install .\n        pytest -c /dev/null tests/benchmarks --benchmark-json output.json\n\n    # Pushing the benchmark requires elevated permissions to the\n    # cocotb/cocotb-benchmark-results repository, which we only grant for\n    # master builds, not for PR builds.\n    - name: Generate a token to access cocotb/cocotb-benchmark-results\n      if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}\n      id: generate_token\n      uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859  # v3.0.0\n      with:\n        app-id: ${{ secrets.COCOTB_CI_REPOACCESS_APP_ID }}\n        private-key: ${{ secrets.COCOTB_CI_REPOACCESS_APP_PRIVATE_KEY }}\n        owner: ${{ github.repository_owner }}\n        repositories: cocotb-benchmark-results\n\n    - name: Store benchmark result\n      if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}\n      uses: benchmark-action/github-action-benchmark@a60cea5bc7b49e15c1f58f411161f99e0df48372  # v1.22.0\n      continue-on-error: true\n      with:\n        tool: 'pytest'\n        output-file-path: output.json\n        alert-threshold: '120%'\n        fail-on-alert: true\n        github-token: ${{ steps.generate_token.outputs.token }}\n        auto-push: true\n        gh-repository: 'github.com/cocotb/cocotb-benchmark-results'\n"
  },
  {
    "path": ".github/workflows/build-test-dev.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nname: CI\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }}\n  cancel-in-progress: ${{ !(contains(github.ref, 'release/') || contains(github.ref, 'master')) }}\n\non:\n  # Run this workflow on every push to the master branch, or a stable branch.\n  push:\n    branches:\n      - master\n      - \"stable/**\"\n  pull_request:\n    branches:\n      - master\n      - 'stable/**'\n    paths-ignore:\n      # Skip running tests for changes only in:\n      # Documentation\n      - 'docs/**'\n      # Dot-files not related to running tests\n      - '.devcontainer/**'\n      - '.backportrc.json'\n      - '.clang-format'\n      - '.git-blame-ignore-revs'\n      - '.gitignore'\n      - '.pre-commit-config.yaml'\n      - '.readthedocs.yml'\n      # Information files\n      - 'LICENSE'\n      - 'README.md'\n      - 'CONTRIBUTING.md'\n      - 'MANIFEST.in'\n      # Github files that aren't related to testing\n      - '.github/issue_template.md'\n      - '.github/PULL_REQUEST_TEMPLATE.md'\n      - '.github/workflows/backport.yml'\n      - '.github/workflows/benchmark.yml'\n      - '.github/workflows/ecosystem-compat.yml'\n      - '.github/workflows/experimental.yml'\n      - '.github/workflows/extended.yml'\n      - '.github/workflows/stale.yml'\n\njobs:\n  test_dev:\n    name: Regression Tests\n    uses: ./.github/workflows/regression-tests.yml\n    with:\n      test_task: dev_test\n      collect_coverage: true\n      group: ci-free\n\n  test_dev_licensed:\n    if: github.repository == 'cocotb/cocotb'\n    name: Regression Tests\n    uses: ./.github/workflows/regression-tests.yml\n    with:\n      test_task: dev_test\n      collect_coverage: true\n      group: ci-licensed\n"
  },
  {
    "path": ".github/workflows/build-test-release.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n#\n# DO NOT RENAME THIS FILE!\n# PyPi uploads use OIDC, aka Trusted Publishing, to avoid the need for API keys.\n# https://pypi.org/manage/project/cocotb/settings/publishing/ is configured to\n# allow uploads from the cocotb GitHub project and this exact file name.\n#\n\nname: Release\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }}\n  cancel-in-progress: ${{ !(contains(github.ref, 'release/') || contains(github.ref, 'master')) }}\n\non:\n  # Run this workflow on every push to master or to a stable branch.\n  push:\n    branches:\n      - master\n      - \"stable/**\"\n    tags:\n      - 'v*'\n\njobs:\n  build_release:\n    name: Build distribution on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false # Keep going even if one matrix build fails.\n      matrix:\n        os:\n          - ubuntu-22.04\n          - windows-2022\n          - macos-15-intel  # x86_64\n          - macos-14        # ARM64\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2\n      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0\n        with:\n          python-version: \"3.12\"\n      - name: Install uv\n        uses: astral-sh/setup-uv@v7\n      - name: Install nox\n        run: python3 -m pip install nox nox-uv\n\n      # Use the cibuildwheel configuration inside nox, instead of the\n      # cibuildwheel GitHub Action, to make the process easy to reproduce\n      # locally.\n      - name: Build cocotb release\n        run: |\n          nox -s release_clean\n          nox -s release_build\n\n      - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f  # v7.0.0\n        with:\n          name: cocotb-dist-${{ matrix.os }}\n          path: |\n            dist/*.whl\n            dist/*.tar.gz\n\n  # This tests both the sdist and wheel builds in separate venvs back to back with just the pytest tests.\n  test_release:\n    name: Regression Tests\n    needs: build_release\n    uses: ./.github/workflows/regression-tests.yml\n    with:\n      test_task: release_test\n      download_artifacts: true\n      group: ci-free\n\n  test_release_licensed:\n    name: Regression Tests\n    needs: build_release\n    uses: ./.github/workflows/regression-tests.yml\n    with:\n      test_task: release_test\n      download_artifacts: true\n      group: ci-licensed\n\n  deploy_pypi:\n    name: Deploy to pypi.org\n    needs:\n    - test_release\n    - test_release_licensed\n    permissions:\n      id-token: write\n    runs-on: ubuntu-22.04\n    # Only upload tagged releases.\n    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2\n    - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0\n      with:\n        python-version: \"3.12\"\n    - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c  # v8.0.1\n      with:\n        path: dist\n        pattern: cocotb-dist-*\n        merge-multiple: true\n    - name: Publish distribution to PyPI\n      uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e  # v1.13.0\n      # Authentication to PyPi is done through OIDC (\"Trusted Publishing\").\n"
  },
  {
    "path": ".github/workflows/ecosystem-compat.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Tests to ensure that projects depending on cocotb continue to work with the\n# latest development version of cocotb.\n#\n# Generally, we test the development version of cocotb against supported,\n# released versions of the other projects. (It is expected that the projects\n# themselves test their in-development code against the released version of\n# cocotb.)\n\nname: Ecosystem compatibility tests\n\non:\n  # Run daily at midnight (UTC).\n  schedule:\n    - cron: '0 0 * * *'\n  # Allow triggering a CI run from the web UI.\n  workflow_dispatch:\n\njobs:\n  cocotb-coverage:\n    if: github.repository == 'cocotb/cocotb'\n    name: Test cocotb-coverage\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        cocotb-coverage-version: [ \"2.0\" ]\n\n    steps:\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0\n        with:\n          python-version: \"3.11\"\n\n      - name: Install Icarus Verilog\n        run: sudo apt-get install -y --no-install-recommends iverilog\n\n      - name: Checkout cocotb-coverage repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2\n        with:\n          repository: mciepluc/cocotb-coverage\n          path: cocotb-coverage\n          ref: v${{ matrix.cocotb-coverage-version }}\n\n      - name: Install the release version of cocotb-coverage\n        run: pip install ./cocotb-coverage\n\n      - name: Install the development version of cocotb\n        run: pip install git+https://github.com/cocotb/cocotb.git\n\n      - name: Run tests\n        if: ${{ matrix.cocotb-coverage-version }} == '2.0'\n        env:\n          SIM: icarus\n          TOPLEVEL_LANG: verilog\n        run: |\n          pip install pytest cocotb-bus numpy\n          cd cocotb-coverage\n          make -k -C tests\n          make -C examples/fifo/tests\n          make -C examples/pkt_switch/tests\n\n  pyuvm:\n    if: github.repository == 'cocotb/cocotb'\n    name: Test pyuvm\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        pyuvm-version: [ \"4.0.1\" ]\n\n    steps:\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0\n        with:\n          python-version: \"3.11\"\n\n      - name: Install Icarus Verilog\n        run: sudo apt-get install -y --no-install-recommends iverilog\n\n      - name: Install NVC\n        uses: nickg/setup-nvc@v1\n        with:\n          version: r1.19.3\n\n      - name: Checkout pyuvm repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2\n        with:\n          repository: pyuvm/pyuvm\n          path: pyuvm\n          ref: ${{ matrix.pyuvm-version }}\n\n      - name: Install pyuvm\n        run: pip install ./pyuvm\n\n      - name: Install the development version of cocotb\n        run: pip install git+https://github.com/cocotb/cocotb.git\n\n      - name: Run tests\n        if: ${{ matrix.pyuvm-version }} == '4.0.1'\n        working-directory: pyuvm\n        env:\n          VERILOG_SIM: icarus\n          VHDL_SIM: nvc\n        run: |\n          pip install pytest\n          pytest\n          make cocotb_tests\n\n  forastero:\n    if: github.repository == 'cocotb/cocotb'\n    name: Test Forastero\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        forastero-version: [ \"1.2.1\" ]\n\n    steps:\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0\n        with:\n          python-version: \"3.13\"\n\n      - name: Install Icarus Verilog\n        run: sudo apt-get install -y --no-install-recommends iverilog\n\n      - name: Checkout Forastero repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2\n        with:\n          repository: intuity/forastero\n          path: forastero\n          ref: ${{ matrix.forastero-version }}\n\n      - name: Install the release version of Forastero\n        run: pip install ./forastero\n\n      - name: Install the development version of cocotb\n        run: pip install git+https://github.com/cocotb/cocotb.git\n\n      - name: Run tests\n        working-directory: forastero\n        env:\n          SIM: icarus\n          TOPLEVEL_LANG: verilog\n        run: |\n          make -C examples/arbiter_strict\n          make -C examples/arbiter_window\n"
  },
  {
    "path": ".github/workflows/experimental.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# A workflow where the tool is the moving target, or the tool is known to be\n# not fully supported by cocotb, but we still want to see how its support\n# evolves over time.\n\nname: Test experimental tool versions\n\non:\n  # Run every Monday at 2am (UTC).\n  schedule:\n    - cron: '0 2 * * 1'\n  # Allow triggering a CI run from the web UI.\n  workflow_dispatch:\n\njobs:\n  test_dev:\n    if: github.repository == 'cocotb/cocotb'\n    name: Regression Tests\n    uses: ./.github/workflows/regression-tests.yml\n    with:\n      test_task: dev_test\n      group: experimental\n"
  },
  {
    "path": ".github/workflows/extended.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Run tests against an extended set of simulator (versions).\n\nname: Test extended tool versions\n\non:\n  # Run every Sunday at 2am (UTC).\n  schedule:\n    - cron: '0 2 * * 0'\n  # Allow triggering a CI run from the web UI.\n  workflow_dispatch:\n\njobs:\n  test_dev:\n    if: github.repository == 'cocotb/cocotb'\n    name: Regression Tests\n    uses: ./.github/workflows/regression-tests.yml\n    with:\n      test_task: dev_test\n      group: extended\n      max_parallel: 5\n"
  },
  {
    "path": ".github/workflows/regression-tests.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nname: Regression Tests\n\non:\n  workflow_call:\n    inputs:\n      test_task:\n        required: true\n        type: string\n        default: dev_test\n      collect_coverage:\n        required: false\n        type: boolean\n        default: false\n      download_artifacts:\n        required: false\n        type: boolean\n        default: false\n      group:\n        required: false\n        type: string\n        default: \"ci-free\"\n        description: Group of environments to run the tests against. Leave empty to run them all.\n      max_parallel:\n        required: false\n        type: number\n        default: 0\n        description: Maximum number of parallel matrix jobs\n      setup_python:\n        required: false\n        type: string\n        description: Which Github Action to setup Python\n\njobs:\n\n  generate_envs:\n    runs-on: ubuntu-latest\n    name: Generate a list of environments to run tests against\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2\n    - run: ./.github/generate-envs.py --output-format=gha --gha-output-file=\"$GITHUB_OUTPUT\" --group=\"${{inputs.group}}\"\n      id: run_generate_script\n    outputs:\n      envs: ${{ steps.run_generate_script.outputs.envs }}\n\n  tests:\n\n    needs: generate_envs\n\n    name: ${{matrix.name}}\n    runs-on: ${{matrix.runs-on}}\n    timeout-minutes: 60\n\n    env:\n      SIM: ${{matrix.sim}}\n      TOPLEVEL_LANG: ${{matrix.lang}}\n      CXX: ${{matrix.cxx || 'g++'}}\n      CC: ${{matrix.cc || 'gcc'}}\n      OS: ${{matrix.os}}\n      PYTHON_VERSION: ${{matrix.python-version}}\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include: ${{ fromJson(needs.generate_envs.outputs.envs) }}\n      max-parallel: ${{ inputs.max_parallel }}\n\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2\n      with:\n        # GitHub PR's create a merge commit, and Actions are run on that commit.\n        # Codecov's uploader needs the previous commit (tip of PR branch) to associate coverage correctly.\n        # A fetch depth of 2 provides enough information without fetching the entire history.\n        fetch-depth: 2\n\n    - name: setup ccache\n      uses: hendrikmuhs/ccache-action@33522472633dbd32578e909b315f5ee43ba878ce # v1.2.22\n      if: ${{ startsWith(matrix.os, 'ubuntu') }}\n      with:\n        key: ${{ matrix.os }}-${{matrix.cc || 'gcc'}}\n    - name: setup ccache path\n      if: ${{ startsWith(matrix.os, 'ubuntu') }}\n      run: |\n        echo \"/usr/lib/ccache:/usr/local/opt/ccache/libexec\" >> $GITHUB_PATH\n\n     # Use the ccache cache for all compilers.\n\n    - name: Update package index (ubuntu)\n      if: startsWith(matrix.os, 'ubuntu')\n      run: sudo apt-get update\n\n     # Download distribution artifacts (if any).\n    - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c  # v8.0.1\n      if: ${{ inputs.download_artifacts }}\n      with:\n        path: dist\n        pattern: cocotb-dist-*\n        merge-multiple: true\n\n      # Install Python\n    - name: Set up Python ${{matrix.python-version}} (setup-python)\n      if: matrix.setup_python == ''\n      uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0\n      with:\n        python-version: ${{matrix.python-version}}\n        allow-prereleases: true\n\n    - name: Install msys2 (Windows)\n      if: startsWith(matrix.os, 'windows') && matrix.sim == 'icarus'\n      uses: msys2/setup-msys2@v2\n      with:\n        msystem: MINGW64\n        update: true\n        install: >\n          base-devel\n          gperf\n          mingw-w64-x86_64-toolchain\n\n      # Install\n    - name: Install XML-dependencies for Python 3.14\n      if: startsWith(matrix.python-version, '3.14') && startsWith(matrix.os, 'ubuntu')\n      run: sudo apt-get install -y --no-install-recommends libxml2-dev libxslt-dev\n      # Run tests that don't need a simulator.\n    - name: Install uv\n      uses: astral-sh/setup-uv@v7\n    - name: Install Python testing dependencies\n      run: |\n        pip install nox nox-uv\n\n      # Install Icarus\n    - name: Set up Icarus (Ubuntu - apt)\n      if: startsWith(matrix.os, 'ubuntu') && matrix.sim == 'icarus' && matrix.sim-version == 'apt'\n      run: |\n        sudo apt-get install -y --no-install-recommends iverilog\n    - name: Set up Icarus (Ubuntu - source)\n      if: startsWith(matrix.os, 'ubuntu') && matrix.sim == 'icarus' && matrix.sim-version != 'apt'\n      run: |\n        sudo apt-get install -y --no-install-recommends g++ gperf flex bison make autoconf\n        git clone https://github.com/steveicarus/iverilog.git\n        cd iverilog\n        git reset --hard ${{matrix.sim-version}}\n        bash ./autoconf.sh\n        # Icarus 11.0 fails to configure under Ubuntu 22.04 without explicitly\n        # telling it where to find the preprocessor.\n        CXXCPP=/usr/bin/cpp bash ./configure\n        make -j $(nproc)\n        sudo make install\n    - name: Set up Icarus (Windows - source - pt. 1)\n      if: startsWith(matrix.os, 'windows') && matrix.sim == 'icarus'\n      run: |\n        git config --global core.autocrlf input\n        git clone https://github.com/steveicarus/iverilog.git\n        cd iverilog\n        git reset --hard ${{matrix.sim-version}}\n    - name: Set up Icarus (Windows - source - pt. 2)\n      if: startsWith(matrix.os, 'windows') && matrix.sim == 'icarus'\n      timeout-minutes: 10\n      shell: msys2 {0}\n      env:\n        MINGW_ARCH: MINGW64\n      run: |\n        cd iverilog\n        cd msys2\n        makepkg-mingw --noconfirm --noprogressbar -sCLf\n    - name: Set up Icarus (Windows - source - pt. 3)\n      if: startsWith(matrix.os, 'windows') && matrix.sim == 'icarus'\n      timeout-minutes: 10\n      shell: msys2 {0}\n      env:\n        MINGW_ARCH: MINGW64\n      run: |\n        pacman -U --noconfirm iverilog/msys2/*.zst\n        echo \"$(dirname $(cygpath -m $(which iverilog)))\" >> $GITHUB_PATH\n    - name: Set up Icarus (MacOS - homebrew --HEAD)\n      if: startsWith(matrix.os, 'macos') && matrix.sim == 'icarus' && matrix.sim-version == 'homebrew-HEAD'\n      run: |\n        brew install icarus-verilog --HEAD\n    - name: Set up Icarus (MacOS - homebrew)\n      if: startsWith(matrix.os, 'macos') && matrix.sim == 'icarus' && matrix.sim-version == 'homebrew-stable'\n      run: |\n        brew install icarus-verilog\n\n      # Install GHDL\n    - name: Set up GHDL (Ubuntu)\n      if: startsWith(matrix.os, 'ubuntu') && matrix.sim == 'ghdl'\n      run: |\n        sudo apt-get install -y --no-install-recommends gnat\n        git clone https://github.com/ghdl/ghdl.git\n        cd ghdl\n        git reset --hard ${{matrix.sim-version}}\n        mkdir build\n        cd build\n        ../configure\n        make -j $(nproc)\n        sudo make install\n\n      # Install NVC\n    - name: Set up NVC (Ubuntu, release)\n      if: startsWith(matrix.os, 'ubuntu') && matrix.sim == 'nvc' && startsWith(matrix.sim-version, 'r') && matrix.cc != 'clang'\n      uses: nickg/setup-nvc@v1\n      with:\n        version: ${{matrix.sim-version}}\n    - name: Set up NVC (Windows, release)\n      if: startsWith(matrix.os, 'windows') && matrix.sim == 'nvc'\n      uses: nickg/setup-nvc@v1\n      with:\n        version: ${{matrix.sim-version}}\n    - name: Set up NVC (Ubuntu, source)\n      if: startsWith(matrix.os, 'ubuntu') && matrix.sim == 'nvc' && (!startsWith(matrix.sim-version, 'r') || matrix.cc == 'clang')\n      run: |\n        sudo apt-get install -y --no-install-recommends llvm-dev libdw-dev flex\n        git clone --depth=1 --no-single-branch https://github.com/nickg/nvc.git\n        cd nvc\n        git reset --hard ${{matrix.sim-version}}\n        ./autogen.sh\n        mkdir build\n        cd build\n        ../configure\n        make -j $(nproc)\n        sudo make install\n\n      # Install Verilator (Linux)\n    - name: Set up Verilator (Ubuntu - source)\n      if: startsWith(matrix.os, 'ubuntu') && matrix.sim == 'verilator'\n      run: |\n        sudo apt-get install -y --no-install-recommends help2man make g++ perl python3 autoconf flex bison libfl2 libfl-dev zlib1g zlib1g-dev\n        git clone https://github.com/verilator/verilator.git\n        cd verilator\n        git reset --hard ${{matrix.sim-version}}\n        autoconf\n        ./configure\n        make -j $(nproc)\n        sudo make install\n\n      # Install Verilator (MacOS)\n    - name: Set up Verilator (MacOS - source)\n      if: startsWith(matrix.os, 'macos') && matrix.sim == 'verilator'\n      run: |\n        brew install autoconf help2man\n        git clone https://github.com/verilator/verilator.git\n        cd verilator\n        git reset --hard ${{matrix.sim-version}}\n        autoconf\n        ./configure\n        make -j $(sysctl -n hw.logicalcpu)\n        sudo make install\n\n      # Windows Testing\n    - name: Test (Windows)\n      if: startsWith(matrix.os, 'windows')\n      id: windowstesting\n      continue-on-error: ${{matrix.may-fail || false}}\n      run: |\n        nox -k \"${{ inputs.test_task }} and ${{ matrix.sim }} and ${{ matrix.lang }}\"\n      env:\n        COCOTB_ANSI_OUTPUT: 1\n        COCOTB_CI_SKIP_MAKE: 1\n\n      # Ubuntu / MacOS Testing\n    - name: Install cocotb build dependencies (Ubuntu - g++)\n      if: startsWith(matrix.os, 'ubuntu') && (!matrix.cxx || matrix.cxx == 'g++')\n      run: |\n        sudo apt-get install g++\n    - name: Install cocotb build dependencies (Ubuntu - clang++)\n      if: startsWith(matrix.os, 'ubuntu') && matrix.cxx == 'clang++'\n      run: |\n        sudo apt-get install clang llvm\n    - name: Install cocotb build dependencies (MacOS)\n      if: startsWith(matrix.os, 'macos')\n      run: |\n        g++ --version\n    - name: Test (Ubuntu, MacOS)\n      id: unixtesting\n      if: startsWith(matrix.os, 'ubuntu') || startsWith(matrix.os, 'macos')\n      continue-on-error: ${{matrix.may-fail || false}}\n      timeout-minutes: 40\n      run: |\n        if [ \"${{matrix.self-hosted}}\" == \"true\" ]; then\n          module load \"${{ matrix.sim-version }}\"\n        fi\n        nox -k \"${{ inputs.test_task }} and ${{ matrix.sim }} and ${{ matrix.lang }}\"\n      env:\n        COCOTB_ANSI_OUTPUT: 1\n\n    # codecov\n    - name: Combine and report coverage\n      if: inputs.collect_coverage && matrix.cxx != 'clang++'\n      run: nox -s dev_coverage_report\n    - name: Combine and report coverage (clang)\n      if: inputs.collect_coverage && matrix.cxx == 'clang++'\n      run: nox -s dev_coverage_report -- 'llvm-cov gcov'\n\n    - name: Upload to codecov\n      if: inputs.collect_coverage\n      uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2  # v6.0.0\n      env:\n        # https://community.codecov.com/t/upload-issues-unable-to-locate-build-via-github-actions-api/3954\n        CODECOV_TOKEN: 669f2048-851e-479e-a618-8fa64f3736cc\n      with:\n        files: .python_coverage.xml,.cpp_coverage.xml\n        name: ${{ matrix.name }}\n        env_vars: SIM,TOPLEVEL_LANG,CXX,OS,PYTHON_VERSION\n        verbose: true\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nname: \"Stale Questions\"\non:\n  schedule:\n  - cron: \"00 02 * * *\"\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f  # v10.2.0\n      with:\n        repo-token: ${{secrets.GITHUB_TOKEN}}\n        days-before-stale: 30\n        days-before-close: 7\n        stale-issue-message: >\n          Has your question been resolved? If so please close this issue.\n          If it has not been resolved, you may need to provide more information.\n          If no more activity on this issue occurs in 7 days, it will be closed.\n        stale-issue-label: \"status:stale\"\n        stale-pr-message: >\n          Are you still actively working on this pull request?\n          You may have requested changes that need to be addressed.\n          If the maintainers aren't being timely with a review, we apologize.\n          Please bump this pull request to keep it alive.\n          If no more activity on this pull request occurs in 7 days, it will be closed.\n        stale-pr-label: \"status:stale\"\n        any-of-labels: \"type:question,status:close?,status:needs-info\"\n        operations-per-run: 30\n"
  },
  {
    "path": ".gitignore",
    "content": "*.py[cod]\n\n# C extensions\n*.so\n*.dll\n\n# C objects\n*.o\n\n# Python and C++ code coverage\n.coverage\n.coverage.cocotb\n*.gcno\n*.gcda\n*.gcov\n*.xml\n\n# Packaging\n*.egg\n*.egg-info\ndist\nbuild\neggs\nparts\nsdist\nobj\ndevelop-eggs\n.installed.cfg\n__pycache__\n.tox\n.nox\n.eggs\n\n# Vim tmp files\n*.swp\n*~\n\n# VSCode project files\n.vscode/\n*.code-workspace\n\n# Emacs tmp files\n\\#*\\#\n\\.\\#*\n\n# Mergetool tmp files\n*.orig\n*.bak\n\n# Waveforms\n*.vcd\n*.fst\n*.fst.hier\n\n# Results\nresults.xml\ncombined_results.xml\n\n# Debuggers\n.gdb_history\n\n# VCS files\n*.tab\nsim_build\nucli.key\n\n# Pytest\n.pytest_cache\n\n# Cadence Incisive/Xcelium\n*.elog\nirun.log\nxrun.log\nirun.key\nxrun.key\nirun.history\nxrun.history\nINCA_libs\nxcelium.d\nncelab_*.err\nxmelab_*.err\nncsim_*.err\nxmsim_*.err\nbpad_*.err\n.bpad/\n.simvision/\nwaves.shm/\n\n# Interface libraries built on setup\nsrc/cocotb/libs\npip-wheel-metadata/\n\n# Mentor Modelsim/Questa\ntests/test_cases/*/modelsim.ini\ntests/test_cases/*/transcript\ntests/test_cases/*/qwave.db\ntests/test_cases/*/design.bin\nexamples/*/tests/modelsim.ini\nexamples/*/tests/transcript\nexamples/*/tests/qwave.db\nexamples/*/tests/design.bin\n*.wlf\nqrun.log\nvisualizer.log\n\n# Riviera\ntests/test_cases/*/library.cfg\ntests/test_cases/*/dataset.asdb\ntests/test_cases/*/compile\nexamples/*/tests/library.cfg\nexamples/*/tests/dataset.asdb\nexamples/*/tests/compile\n\n# Tachyon DA CVC\ntests/test_cases/*/verilog.log\nexamples/*/tests/verilog.log\n\n# DSim\ndsim*\nmetrics.db\n\n# Build artifacts\n/dist/\n\n# clangd\ncompile_commands.json\ncompile_commands.*.json\n.cache/\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nexclude: \"^.*/_vendor/\"\nrepos:\n# ruff with --fix should run before other formatting tools\n- repo: https://github.com/astral-sh/ruff-pre-commit\n  rev: \"v0.15.10\"\n  hooks:\n    # Run the linter.\n    - id: \"ruff\"\n      args:\n      - \"--fix\"\n      - \"--exit-non-zero-on-fix\"\n    # Run the formatter.\n    - id: ruff-format\n\n- repo: \"https://github.com/pre-commit/mirrors-clang-format\"\n  rev: \"v22.1.3\"\n  hooks:\n  - id: \"clang-format\"\n    exclude: \"^src/cocotb/share/include/(sv_vpi|vhpi|vpi)_user(_ext)?.h\"\n    types_or: [c, c++]\n\n- repo: \"https://github.com/pre-commit/pre-commit-hooks\"\n  rev: \"v6.0.0\"\n  hooks:\n  - id: \"trailing-whitespace\"\n  - id: \"mixed-line-ending\"\n    args:\n    - \"--fix=lf\"\n  - id: \"end-of-file-fixer\"\n    exclude: \"^docs/source/diagrams/(svg|xml)/\"\n\n- repo: https://github.com/henryiii/validate-pyproject-schema-store\n  rev: \"2026.04.11\"\n  hooks:\n    - id: validate-pyproject\n      files: pyproject.toml\n\n- repo: local\n  hooks:\n  - id: \"git-diff\"\n    name: git diff\n    entry: git diff --exit-code\n    language: system\n    pass_filenames: false\n    always_run: true\n\n- repo: https://github.com/codespell-project/codespell\n  rev: v2.4.2\n  hooks:\n  - id: codespell\n    additional_dependencies:\n      - tomli\n\n- repo: https://github.com/pre-commit/mirrors-mypy\n  rev: v1.19.1\n  hooks:\n  - id: mypy\n    args: [--follow-imports=silent]\n    additional_dependencies:\n    - pytest\n    - pluggy\n    - coverage\n    - nox\n    - nox-uv\n    files: ^(src/cocotb/|src/pygpi/|noxfile\\.py|src/cocotb_tools/pytest/)\n\n- repo: https://github.com/astral-sh/uv-pre-commit\n  rev: 0.11.6\n  hooks:\n    - id: uv-lock\n\nci:\n  autofix_prs: false\n"
  },
  {
    "path": ".readthedocs.yml",
    "content": "# .readthedocs.yml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details\n\nversion: 2\n\nbuild:\n  os: ubuntu-22.04\n  tools:\n    python: \"3.12\"\n  apt_packages:\n    - graphviz\n  jobs:\n    create_environment:\n      - asdf plugin add uv\n      - asdf install uv latest\n      - asdf global uv latest\n      - UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --all-extras --group docs\n    install:\n      - \"true\"\n\nsphinx:\n  configuration: docs/source/conf.py\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# cocotb Contribution Guidelines\n\ncocotb welcomes contributions from anyone!\nPlease have a look at the [Development & Community](https://docs.cocotb.org/en/development/contributing.html) section of the cocotb documentation for an in-depth contribution guide.\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright cocotb contributors\nCopyright (c) 2013 Potential Ventures Ltd\nCopyright (c) 2013 SolarFlare Communications Inc\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "recursive-include src/cocotb/share *\nrecursive-include src/cocotb/_vendor *\ninclude README.md\ninclude LICENSE\ninclude cocotb_build_libs.py\n"
  },
  {
    "path": "Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nREPO_ROOT := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n\n.PHONY: all\nall: test\n\n.PHONY: clean\nclean:\n\t-@find . -name \"obj\" -exec rm -rf {} +\n\t-@find . -name \"*.pyc\" -delete\n\t-@find . -name \"*results.xml\" -delete\n\t$(MAKE) -C examples clean\n\t$(MAKE) -C tests clean\n\n.PHONY: do_tests\ndo_tests::\n\t$(MAKE) -C tests\ndo_tests::\n\t$(MAKE) -C examples\n\n# For Jenkins we use the exit code to detect compile errors or catastrophic\n# failures and the XML to track test results\n.PHONY: jenkins\njenkins: do_tests\n\tpython -m cocotb_tools.combine_results --repo-root $(REPO_ROOT) --suppress_rc --testsuites_name=cocotb_regression\n\n# By default want the exit code to indicate the test results\n.PHONY: test\ntest:\n\t$(MAKE) do_tests; ret=$$?; python -m cocotb_tools.combine_results --repo-root $(REPO_ROOT) && exit $$ret\n\nCOCOTB_MAKEFILES_DIR = $(realpath $(shell cocotb-config --makefiles))\nAVAILABLE_SIMULATORS = $(patsubst .%,%,$(suffix $(wildcard $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.*)))\n\n.PHONY: help\nhelp:\n\t@echo \"\"\n\t@echo \"This cocotb makefile has the following targets\"\n\t@echo \"\"\n\t@echo \"all, test - run regression producing combined_results.xml\"\n\t@echo \"            (return error code produced by sub-makes)\"\n\t@echo \"jenkins   - run regression producing combined_results.xml\"\n\t@echo \"            (return error code 1 if any failure was found)\"\n\t@echo \"clean     - remove build directory and all simulation artefacts\"\n\t@echo \"\"\n\t@echo \"The default simulator is Icarus Verilog.\"\n\t@echo \"To use another, set the environment variable SIM as below.\"\n\t@echo \"Available simulators:\"\n\t@for X in $(sort $(AVAILABLE_SIMULATORS)); do \\\n\t\techo export SIM=$$X; \\\n\tdone\n\t@echo \"\"\n"
  },
  {
    "path": "README.md",
    "content": "**cocotb** is a framework empowering users to write VHDL and Verilog testbenches in Python.\n\n[![Documentation Status](https://readthedocs.org/projects/cocotb/badge/?version=development)](https://docs.cocotb.org/en/stable/)\n[![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)\n[![PyPI](https://img.shields.io/pypi/dm/cocotb.svg?label=PyPI%20downloads)](https://pypi.org/project/cocotb/)\n[![codecov](https://codecov.io/gh/cocotb/cocotb/branch/master/graph/badge.svg)](https://codecov.io/gh/cocotb/cocotb)\n\n* Check out the [tutorial](https://docs.cocotb.org/en/stable/quickstart.html)\n* Read the [docs](https://docs.cocotb.org/en/stable/)\n* Find more info in the [wiki](https://github.com/cocotb/cocotb/wiki)\n* Discover [useful extensions](https://github.com/cocotb/cocotb/wiki/Further-Resources#utility-libraries-and-frameworks)\n* Join the discussion in the [Gitter chat room](https://gitter.im/cocotb/Lobby)\n* [Ask a question](https://github.com/cocotb/cocotb/discussions)\n* [Raise a bug / request an enhancement](https://github.com/cocotb/cocotb/issues/new)\n"
  },
  {
    "path": "cocotb_build_libs.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport distutils\nimport logging\nimport os\nimport subprocess\nimport sys\nimport sysconfig\nimport textwrap\nfrom distutils.ccompiler import get_default_compiler\nfrom distutils.file_util import copy_file\n\nfrom setuptools import Extension\nfrom setuptools.command.build_ext import build_ext as _build_ext\n\nlogger = logging.getLogger(__name__)\ncocotb_share_dir = os.path.abspath(\n    os.path.join(os.path.dirname(__file__), \"src\", \"cocotb\", \"share\")\n)\n_base_warns = [\n    \"-Wall\",\n    \"-Wextra\",\n    \"-Wcast-qual\",\n    \"-Wwrite-strings\",\n    \"-Wconversion\",\n    # -Wno-missing-field-initializers is required on GCC 4.x to prevent a\n    # spurious warning `error: missing initializer for member ...` when\n    # compiling `PyTypeObject type = {};` in `simulatormodule.cpp`.\n    # (See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750.) This flag can be\n    # removed once we require later GCC versions.\n    \"-Wno-missing-field-initializers\",\n    \"-Werror=shadow\",\n]\n_ccx_warns = [*_base_warns, \"-Wnon-virtual-dtor\", \"-Woverloaded-virtual\"]\n_extra_cxx_compile_args = [\n    \"-std=c++11\",\n    \"-fvisibility=hidden\",\n    \"-fvisibility-inlines-hidden\",\n    *_ccx_warns,\n]\nif os.name != \"nt\":\n    _extra_cxx_compile_args += [\"-flto\"]\n\n_extra_cxx_compile_args_msvc = [\"/permissive-\"]\n\n# Make PRI* format macros available with C++11 compiler but older libc, e.g. on RHEL6.\n_extra_defines = [(\"__STDC_FORMAT_MACROS\", \"\")]\n\n\ndef create_sxs_assembly_manifest(\n    name: str, filename: str, libraries: list[str], dependency_only=False\n) -> str:\n    \"\"\"\n    Create side-by-side (sxs) assembly manifest\n\n    It contains dependencies to other assemblies (in our case the assemblies are equal to the other libraries).\n    For more details see:\n     - https://docs.microsoft.com/en-us/windows/win32/sbscs/assembly-manifests\n     - https://docs.microsoft.com/en-us/windows/win32/sbscs/using-side-by-side-assemblies\n\n    Args:\n        name: The name of the assembly for which the manifest is generated, e.g. ``libgpi``.\n        filename: The filename of the library, e.g. ``libgpi.dll``.\n        libraries: A list of names of dependent manifests, e.g. ``[\"libgpi\"]``.\n    \"\"\"\n\n    architecture = \"amd64\" if sys.maxsize > 2**32 else \"x86\"\n    dependencies = []\n\n    for lib in libraries:\n        dependencies.append(\n            textwrap.dedent(\n                \"\"\"\\\n            <dependency>\n                <dependentAssembly>\n                    <assemblyIdentity name=\"%s\" version=\"1.0.0.0\" type=\"win32\" processorArchitecture=\"%s\" />\n                </dependentAssembly>\n            </dependency>\n            \"\"\"\n            )\n            % (lib, architecture)\n        )\n\n    if not dependency_only:\n        manifest_body = textwrap.dedent(\n            \"\"\"\\\n            <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n            <assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n                <assemblyIdentity name=\"%s\" version=\"1.0.0.0\" type=\"win32\" processorArchitecture=\"%s\" />\n                <file name=\"%s\" />\n                %s\n            </assembly>\n            \"\"\"\n        ) % (\n            name,\n            architecture,\n            filename,\n            textwrap.indent(\"\".join(dependencies), \"    \").strip(),\n        )\n    else:\n        manifest_body = textwrap.dedent(\n            \"\"\"\\\n            <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n            <assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n                %s\n            </assembly>\n            \"\"\"\n        ) % (textwrap.indent(\"\".join(dependencies), \"    \").strip())\n\n    return manifest_body\n\n\ndef create_sxs_appconfig(filename):\n    \"\"\"\n    Create side-by-side (sxs) application configuration file.\n\n    The application configuration specifies additional search paths for manifests.\n    For more details see: https://docs.microsoft.com/en-us/windows/win32/sbscs/application-configuration-files\n    \"\"\"\n\n    config_body = textwrap.dedent(\n        \"\"\"\\\n        <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n        <configuration>\n            <windows>\n                <assemblyBinding xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n                    <probing privatePath=\"libs\" />\n                </assemblyBinding>\n            </windows>\n        </configuration>\n        \"\"\"\n    )\n\n    dirpath = os.path.dirname(filename)\n    os.makedirs(dirpath, exist_ok=True)\n\n    with open(filename + \".2.config\", \"w\", encoding=\"utf-8\") as f:\n        f.write(config_body)\n\n\ndef create_rc_file(rc_filename, name, filename, libraries, runtime_libraries):\n    \"\"\"\n    Creates windows resource definition script to embed the side-by-side assembly manifest into the libraries.\n\n    For more details see: https://docs.microsoft.com/en-us/windows/win32/menurc/about-resource-files\n    \"\"\"\n\n    manifest = create_sxs_assembly_manifest(name, filename, libraries)\n\n    # Escape double quotes and put every line between double quotes for embedding into rc file\n    manifest = manifest.replace('\"', '\"\"')\n    manifest = \"\\n\".join([f'\"{x}\\\\r\\\\n\"' for x in manifest.splitlines()])\n\n    rc_body = (\n        textwrap.dedent(\n            \"\"\"\\\n        #pragma code_page(65001) // UTF-8\n        #include <Windows.h>\n\n        LANGUAGE 0x00, 0x00\n\n        ISOLATIONAWARE_MANIFEST_RESOURCE_ID RT_MANIFEST\n        BEGIN\n        %s\n        END\n        \"\"\"\n        )\n        % manifest\n    )\n\n    if runtime_libraries is not None:\n        manifest = create_sxs_assembly_manifest(\n            name, filename, runtime_libraries, dependency_only=True\n        )\n\n        # Escape double quotes and put every line between double quotes for embedding into rc file\n        manifest = manifest.replace('\"', '\"\"')\n        manifest = \"\\n\".join([f'\"{x}\\\\r\\\\n\"' for x in manifest.splitlines()])\n\n        rc_body += (\n            textwrap.dedent(\n                \"\"\"\\\n            1000 RT_MANIFEST\n            BEGIN\n            %s\n            END\n            \"\"\"\n            )\n            % manifest\n        )\n\n    with open(rc_filename, \"w\", encoding=\"utf-8\") as f:\n        f.write(rc_body)\n\n\ndef _get_lib_ext_name():\n    \"\"\"Get name of default library file extension on given OS.\"\"\"\n\n    if os.name == \"nt\":\n        ext_name = \"dll\"\n    else:\n        ext_name = \"so\"\n\n    return ext_name\n\n\nclass build_ext(_build_ext):\n    def _uses_msvc(self):\n        if self.compiler == \"msvc\":\n            return True\n        if self.compiler is None:\n            return get_default_compiler() == \"msvc\"\n        else:\n            return getattr(self.compiler, \"compiler_type\", None) == \"msvc\"\n\n    def run(self):\n        if os.name == \"nt\":\n            create_sxs_appconfig(\n                self.get_ext_fullpath(os.path.join(\"cocotb\", \"simulator\"))\n            )\n\n        super().run()\n\n    def build_extensions(self):\n        if os.name == \"nt\":\n            if self._uses_msvc():\n                # Initialize the compiler now so that compiler/linker flags are populated\n                if not self.compiler.initialized:\n                    self.compiler.initialize()\n\n                # Setuptools defaults to activate automatic manifest generation for msvc,\n                # disable it here as we manually generate it to also support mingw on windows\n                for k, ldflags in self.compiler._ldflags.items():\n                    self.compiler._ldflags[k] = [\n                        x for x in ldflags if not x.startswith(\"/MANIFEST\")\n                    ] + [\"/MANIFEST:NO\"]\n\n                self.compiler.compile_options = [\n                    x for x in self.compiler.compile_options if not x.startswith(\"/W\")\n                ] + [\"/W4\"]\n\n            ext_names = {os.path.split(ext.name)[-1] for ext in self.extensions}\n            for ext in self.extensions:\n                fullname = self.get_ext_fullname(ext.name)\n                filename = self.get_ext_filename(fullname)\n                name = os.path.split(fullname)[-1]\n                filename = os.path.split(filename)[-1]\n                libraries = {\"lib\" + lib for lib in ext.libraries}.intersection(\n                    ext_names\n                )\n                rc_filename = name + \".rc\"\n                runtime_libraries = None\n\n                # Strip lib prefix for msvc\n                if self._uses_msvc():\n                    name = name[3:] if name.startswith(\"lib\") else name\n                    libraries = {\n                        (lib[3:] if lib.startswith(\"lib\") else lib) for lib in libraries\n                    }\n                    if runtime_libraries is not None:\n                        runtime_libraries = {\n                            (lib[3:] if lib.startswith(\"lib\") else lib)\n                            for lib in runtime_libraries\n                        }\n                create_rc_file(\n                    rc_filename, name, filename, libraries, runtime_libraries\n                )\n\n            def_dir = os.path.join(cocotb_share_dir, \"def\")\n            self._gen_import_libs(def_dir)\n\n            for e in self.extensions:\n                e.library_dirs += [def_dir]\n\n        super().build_extensions()\n\n    def build_extension(self, ext):\n        \"\"\"Build each extension in its own temp directory to make gcov happy.\n\n        A normal PEP 517 install still works as the temp directories are discarded anyway.\n        \"\"\"\n        lib_name = os.path.split(ext.name)[-1]\n\n        if self._uses_msvc():\n            ext.extra_compile_args += _extra_cxx_compile_args_msvc\n        else:\n            ext.extra_compile_args += _extra_cxx_compile_args\n\n            if os.name == \"nt\":\n                # Align behavior of gcc with msvc and export only symbols marked with __declspec(dllexport)\n                ext.extra_link_args += [\"-Wl,--exclude-all-symbols\"]\n            else:\n                ext.extra_link_args += [\"-flto\"]\n\n                rpaths = []\n                if lib_name == \"simulator\":\n                    rpaths += [\"$ORIGIN/libs\"]\n                    install_name = None\n                else:\n                    rpaths += [\"$ORIGIN\"]\n                    install_name = lib_name\n\n                if sys.platform == \"darwin\":\n                    rpaths = [\n                        rpath.replace(\"$ORIGIN\", \"@loader_path\") for rpath in rpaths\n                    ]\n                    if install_name is not None:\n                        ext.extra_link_args += [\n                            f\"-Wl,-install_name,@rpath/{install_name}.so\"\n                        ]\n\n                if sys.platform == \"linux\":\n                    # Avoid a runtime dependency on libstdc++. Some simulators\n                    # ship a version of libstdc++6.so which is older than the\n                    # one cocotb has been compiled with, which will then lead to\n                    # load-time errors like \"libstdc++.so.6: version\n                    # `GLIBCXX_3.4.29' not found (required by\n                    # /path/to/libcocotbvhpi_modelsim.so).\"\n                    ext.extra_link_args += [\"-static-libstdc++\"]\n\n                ext.extra_link_args += [f\"-Wl,-rpath,{rpath}\" for rpath in rpaths]\n\n        # vpi_user.h and vhpi_user.h require that WIN32 is defined\n        if os.name == \"nt\":\n            ext.define_macros += [(\"WIN32\", \"\")]\n\n        old_build_temp = self.build_temp\n        self.build_temp = os.path.join(self.build_temp, ext.name)\n        super().build_extension(ext)\n        self.build_temp = old_build_temp\n\n    # Needed for Windows to not assume python module (generate interface in def file)\n    def get_export_symbols(self, ext):\n        return None\n\n    # For proper cocotb library naming, based on https://github.com/cython/cython/issues/1740\n    def get_ext_filename(self, ext_name):\n        \"\"\"\n        Like the base class method, but for libraries that are not python extension:\n         - removes the ``.cpython-36m-x86_64-linux-gnu.`` or ``-cpython-36m.`` part before the extension\n         - replaces ``.pyd`` with ``.dll`` on windows.\n        \"\"\"\n\n        filename = _build_ext.get_ext_filename(self, ext_name)\n\n        # for the simulator python extension library, leaving suffix in place\n        if os.path.split(ext_name)[-1] == \"simulator\":\n            return filename\n\n        head, tail = os.path.split(filename)\n        tail_split = tail.split(\".\")\n\n        # mingw on msys2 uses `-` as separator\n        tail_split = tail_split[0].split(\"-\")\n\n        # strip lib prefix if msvc is used\n        if self._uses_msvc() and tail_split[0].startswith(\"lib\"):\n            tail_split[0] = tail_split[0][3:]\n\n        filename_short = os.path.join(head, tail_split[0] + \".\" + _get_lib_ext_name())\n\n        return filename_short\n\n    def finalize_options(self):\n        \"\"\"Like the base class method,but add extra library_dirs path.\"\"\"\n\n        super().finalize_options()\n\n        for ext in self.extensions:\n            ext.library_dirs.append(os.path.join(self.build_lib, \"cocotb\", \"libs\"))\n\n    def copy_extensions_to_source(self):\n        \"\"\"Like the base class method, but copy libs into proper directory in develop.\"\"\"\n\n        build_py = self.get_finalized_command(\"build_py\")\n        for ext in self.extensions:\n            fullname = self.get_ext_fullname(ext.name)\n            filename = self.get_ext_filename(fullname)\n            modpath = fullname.split(\".\")\n            package = \".\".join(modpath[:-1])\n            package_dir = build_py.get_package_dir(package)\n            # unlike the method from `setuptools`, we do not call `os.path.basename` here\n            dest_filename = os.path.join(package_dir, filename)\n            src_filename = os.path.join(self.build_lib, filename)\n\n            os.makedirs(os.path.dirname(dest_filename), exist_ok=True)\n\n            copy_file(src_filename, dest_filename, verbose=self.verbose)\n            if ext._needs_stub:\n                self.write_stub(package_dir or os.curdir, ext, True)\n\n    def _gen_import_libs(self, def_dir):\n        \"\"\"\n        On Windows generate import libraries that contains the code required to\n        load the DLL (.a) based on module definition files (.def)\n        \"\"\"\n\n        for sim in [\"icarus\", \"modelsim\", \"aldec\", \"ghdl\", \"nvcvhpi\"]:\n            if self._uses_msvc():\n                subprocess.run(\n                    [\n                        self.compiler.lib,\n                        \"/def:\" + os.path.join(def_dir, sim + \".def\"),\n                        \"/out:\" + os.path.join(def_dir, sim + \".lib\"),\n                        \"/machine:\" + (\"X64\" if sys.maxsize > 2**32 else \"X86\"),\n                    ],\n                    check=True,\n                )\n            else:\n                subprocess.run(\n                    [\n                        \"dlltool\",\n                        \"-d\",\n                        os.path.join(def_dir, sim + \".def\"),\n                        \"-l\",\n                        os.path.join(def_dir, \"lib\" + sim + \".a\"),\n                    ],\n                    check=True,\n                )\n\n\ndef _get_python_lib_link():\n    \"\"\"Get name of python library used for linking\"\"\"\n\n    if sys.platform == \"darwin\":\n        ld_library = sysconfig.get_config_var(\"LIBRARY\")\n    else:\n        ld_library = sysconfig.get_config_var(\"LDLIBRARY\")\n\n    if ld_library is not None:\n        python_lib_link = os.path.splitext(ld_library)[0][3:]\n    else:\n        python_version = sysconfig.get_python_version().replace(\".\", \"\")\n        python_lib_link = \"python\" + python_version\n\n    return python_lib_link\n\n\ndef _get_python_lib():\n    \"\"\"Get the library for embedded the python interpreter\"\"\"\n\n    if os.name == \"nt\":\n        python_lib = _get_python_lib_link() + \".\" + _get_lib_ext_name()\n    elif sys.platform == \"darwin\":\n        python_lib = os.path.join(\n            sysconfig.get_config_var(\"LIBDIR\"), \"lib\" + _get_python_lib_link() + \".\"\n        )\n        if os.path.exists(python_lib + \"dylib\"):\n            python_lib += \"dylib\"\n        else:\n            python_lib += \"so\"\n    else:\n        python_lib = \"lib\" + _get_python_lib_link() + \".\" + _get_lib_ext_name()\n\n    return python_lib\n\n\ndef _get_common_lib_ext(include_dirs, share_lib_dir):\n    \"\"\"\n    Defines common libraries.\n\n    All libraries go into the same directory to enable loading without modifying the library path (e.g. LD_LIBRARY_PATH).\n    \"\"\"\n\n    #\n    #  libgpi\n    #\n    libgpi_sources = [\n        os.path.join(share_lib_dir, \"gpi\", \"GpiCbHdl.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"GpiCommon.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"dynload.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"logging.cpp\"),\n    ]\n    libgpi_libraries = []\n    if sys.platform.startswith((\"linux\", \"darwin\", \"cygwin\", \"msys\")):\n        libgpi_libraries.append(\"dl\")  # dlopen, dlerror, dlsym\n    if os.name == \"nt\":\n        libgpi_sources += [\"libgpi.rc\"]\n    libgpi = Extension(\n        os.path.join(\"cocotb\", \"libs\", \"libgpi\"),\n        define_macros=[\n            (\"GPI_EXPORTS\", \"\"),\n            *_extra_defines,\n        ],\n        include_dirs=include_dirs,\n        libraries=libgpi_libraries,\n        sources=libgpi_sources,\n    )\n\n    #\n    #  PyGPI\n    #\n    pygpi_sources = [\n        os.path.join(share_lib_dir, \"pygpi\", \"bind.cpp\"),\n        os.path.join(share_lib_dir, \"pygpi\", \"embed.cpp\"),\n        os.path.join(share_lib_dir, \"pygpi\", \"logging.cpp\"),\n    ]\n    if os.name == \"nt\":\n        pygpi_sources += [\"simulator.rc\"]\n    python_lib_dirs = []\n    if sys.platform == \"darwin\":\n        python_lib_dirs = [sysconfig.get_config_var(\"LIBDIR\")]\n    libpygpi = Extension(\n        os.path.join(\"cocotb\", \"simulator\"),\n        define_macros=[\n            (\"PYGPI_EXPORTS\", \"\"),\n            *_extra_defines,\n        ],\n        include_dirs=include_dirs,\n        libraries=[\"gpi\"],\n        library_dirs=python_lib_dirs,\n        sources=pygpi_sources,\n    )\n\n    # The libraries in this list are compiled in order of their appearance.\n    # If there is a linking dependency on one library to another,\n    # the linked library must be built first.\n    return [libgpi, libpygpi]\n\n\ndef _get_vpi_lib_ext(\n    include_dirs, share_lib_dir, sim_define, extra_lib=[], extra_lib_dir=[]\n):\n    lib_name = \"libcocotbvpi_\" + sim_define.lower()\n    libcocotbvpi_sources = [\n        os.path.join(share_lib_dir, \"gpi\", \"vpi\", \"VpiImpl.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"vpi\", \"VpiCbHdl.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"vpi\", \"VpiObj.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"vpi\", \"VpiIterator.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"vpi\", \"VpiSignal.cpp\"),\n    ]\n    if os.name == \"nt\":\n        libcocotbvpi_sources += [lib_name + \".rc\"]\n    libcocotbvpi = Extension(\n        os.path.join(\"cocotb\", \"libs\", lib_name),\n        define_macros=[(\"COCOTBVPI_EXPORTS\", \"\"), (sim_define, \"\"), *_extra_defines],\n        include_dirs=include_dirs,\n        libraries=[\"gpi\", *extra_lib],\n        library_dirs=extra_lib_dir,\n        sources=libcocotbvpi_sources,\n    )\n\n    return libcocotbvpi\n\n\ndef _get_vhpi_lib_ext(\n    include_dirs, share_lib_dir, sim_define, extra_lib=[], extra_lib_dir=[]\n):\n    lib_name = \"libcocotbvhpi_\" + sim_define.lower()\n    libcocotbvhpi_sources = [\n        os.path.join(share_lib_dir, \"gpi\", \"vhpi\", \"VhpiImpl.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"vhpi\", \"VhpiCbHdl.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"vhpi\", \"VhpiObj.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"vhpi\", \"VhpiIterator.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"vhpi\", \"VhpiSignal.cpp\"),\n    ]\n    if os.name == \"nt\":\n        libcocotbvhpi_sources += [lib_name + \".rc\"]\n    libcocotbvhpi = Extension(\n        os.path.join(\"cocotb\", \"libs\", lib_name),\n        include_dirs=include_dirs,\n        define_macros=[(\"COCOTBVHPI_EXPORTS\", \"\"), (sim_define, \"\"), *_extra_defines],\n        libraries=[\"gpi\", *extra_lib],\n        library_dirs=extra_lib_dir,\n        sources=libcocotbvhpi_sources,\n    )\n\n    return libcocotbvhpi\n\n\ndef get_ext():\n    cfg_vars = distutils.sysconfig.get_config_vars()\n\n    if sys.platform == \"darwin\":\n        cfg_vars[\"LDSHARED\"] = cfg_vars[\"LDSHARED\"].replace(\"-bundle\", \"-dynamiclib\")\n        cfg_vars[\"LDCXXSHARED\"] = cfg_vars[\"LDSHARED\"].replace(\"-bundle\", \"-dynamiclib\")\n\n    share_lib_dir = os.path.relpath(os.path.join(cocotb_share_dir, \"lib\"))\n    include_dirs = [\n        os.path.relpath(os.path.join(cocotb_share_dir, \"include\")),\n        os.path.relpath(os.path.join(os.path.dirname(__file__), \"src\", \"cocotb\")),\n    ]\n\n    ext = []\n\n    logger.info(\"Compiling interface libraries for cocotb ...\")\n\n    ext += _get_common_lib_ext(include_dirs, share_lib_dir)\n\n    #\n    #  Icarus Verilog\n    #\n    icarus_extra_lib = []\n    logger.info(\"Compiling libraries for Icarus Verilog\")\n    if os.name == \"nt\":\n        icarus_extra_lib = [\"icarus\"]\n\n    icarus_vpi_ext = _get_vpi_lib_ext(\n        include_dirs=include_dirs,\n        share_lib_dir=share_lib_dir,\n        sim_define=\"ICARUS\",\n        extra_lib=icarus_extra_lib,\n    )\n    ext.append(icarus_vpi_ext)\n\n    #\n    #  Modelsim/Questa\n    #\n    modelsim_extra_lib = []\n    logger.info(\"Compiling libraries for Modelsim/Questa\")\n    if os.name == \"nt\":\n        modelsim_extra_lib = [\"modelsim\"]\n\n    modelsim_vpi_ext = _get_vpi_lib_ext(\n        include_dirs=include_dirs,\n        share_lib_dir=share_lib_dir,\n        sim_define=\"MODELSIM\",\n        extra_lib=modelsim_extra_lib,\n    )\n    ext.append(modelsim_vpi_ext)\n\n    modelsim_vhpi_ext = _get_vhpi_lib_ext(\n        include_dirs=include_dirs,\n        share_lib_dir=share_lib_dir,\n        sim_define=\"MODELSIM\",\n        extra_lib=modelsim_extra_lib,\n    )\n    ext.append(modelsim_vhpi_ext)\n\n    lib_name = \"libcocotbfli_modelsim\"\n    fli_sources = [\n        os.path.join(share_lib_dir, \"gpi\", \"fli\", \"FliImpl.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"fli\", \"FliCbHdl.cpp\"),\n        os.path.join(share_lib_dir, \"gpi\", \"fli\", \"FliObjHdl.cpp\"),\n    ]\n    if os.name == \"nt\":\n        fli_sources += [lib_name + \".rc\"]\n    fli_ext = Extension(\n        os.path.join(\"cocotb\", \"libs\", lib_name),\n        define_macros=[(\"COCOTBFLI_EXPORTS\", \"\"), *_extra_defines],\n        include_dirs=include_dirs,\n        libraries=[\"gpi\", *modelsim_extra_lib],\n        sources=fli_sources,\n    )\n\n    ext.append(fli_ext)\n\n    #\n    # GHDL\n    #\n    ghdl_extra_lib = []\n    logger.info(\"Compiling libraries for GHDL\")\n    if os.name == \"nt\":\n        ghdl_extra_lib = [\"ghdl\"]\n\n    ghdl_vpi_ext = _get_vpi_lib_ext(\n        include_dirs=include_dirs,\n        share_lib_dir=share_lib_dir,\n        sim_define=\"GHDL\",\n        extra_lib=ghdl_extra_lib,\n    )\n    ext.append(ghdl_vpi_ext)\n\n    #\n    # IUS\n    #\n    if os.name == \"posix\":\n        logger.info(\"Compiling libraries for Incisive/Xcelium\")\n        ius_vpi_ext = _get_vpi_lib_ext(\n            include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define=\"IUS\"\n        )\n        ext.append(ius_vpi_ext)\n\n        ius_vhpi_ext = _get_vhpi_lib_ext(\n            include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define=\"IUS\"\n        )\n        ext.append(ius_vhpi_ext)\n\n    #\n    # VCS\n    #\n    if os.name == \"posix\":\n        logger.info(\"Compiling libraries for VCS\")\n        vcs_vpi_ext = _get_vpi_lib_ext(\n            include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define=\"VCS\"\n        )\n        ext.append(vcs_vpi_ext)\n\n    #\n    # Aldec Riviera Pro\n    #\n    aldec_extra_lib = []\n    logger.info(\"Compiling libraries for Riviera\")\n    if os.name == \"nt\":\n        aldec_extra_lib = [\"aldec\"]\n\n    aldec_vpi_ext = _get_vpi_lib_ext(\n        include_dirs=include_dirs,\n        share_lib_dir=share_lib_dir,\n        sim_define=\"ALDEC\",\n        extra_lib=aldec_extra_lib,\n    )\n    ext.append(aldec_vpi_ext)\n\n    aldec_vhpi_ext = _get_vhpi_lib_ext(\n        include_dirs=include_dirs,\n        share_lib_dir=share_lib_dir,\n        sim_define=\"ALDEC\",\n        extra_lib=aldec_extra_lib,\n    )\n    ext.append(aldec_vhpi_ext)\n\n    #\n    # Verilator\n    #\n    if os.name == \"posix\":\n        logger.info(\"Compiling libraries for Verilator\")\n        verilator_vpi_ext = _get_vpi_lib_ext(\n            include_dirs=include_dirs,\n            share_lib_dir=share_lib_dir,\n            sim_define=\"VERILATOR\",\n        )\n        ext.append(verilator_vpi_ext)\n\n    #\n    # NVC\n    #\n    nvc_extra_lib = []\n    if os.name == \"nt\":\n        nvc_extra_lib = [\"nvcvhpi\"]\n    logger.info(\"Compiling libraries for NVC\")\n    nvc_vhpi_ext = _get_vhpi_lib_ext(\n        include_dirs=include_dirs,\n        share_lib_dir=share_lib_dir,\n        sim_define=\"NVC\",\n        extra_lib=nvc_extra_lib,\n    )\n    ext.append(nvc_vhpi_ext)\n\n    #\n    # DSim\n    #\n    if os.name == \"posix\":\n        logger.info(\"Compiling libraries for DSim\")\n        dsim_vpi_ext = _get_vpi_lib_ext(\n            include_dirs=include_dirs, share_lib_dir=share_lib_dir, sim_define=\"DSim\"\n        )\n        ext.append(dsim_vpi_ext)\n\n    return ext\n"
  },
  {
    "path": "docs/.gitignore",
    "content": ".venv\nsource/master-notes.rst\nsource/doxygen\n"
  },
  {
    "path": "docs/Doxyfile",
    "content": "# Doxyfile 1.9.8\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a double hash (##) is considered a comment and is placed in\n# front of the TAG it is preceding.\n#\n# All text after a single hash (#) is considered a comment and will be ignored.\n# The format is:\n# TAG = value [value, ...]\n# For lists, items can also be appended using:\n# TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\\\" \\\").\n#\n# Note:\n#\n# Use doxygen to compare the used configuration file with the template\n# configuration file:\n# doxygen -x [configFile]\n# Use doxygen to compare the used configuration file with the template\n# configuration file without replacing the environment variables or CMake type\n# replacement variables:\n# doxygen -x_noenv [configFile]\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the configuration\n# file that follow. The default is UTF-8 which is also the encoding used for all\n# text before the first occurrence of this tag. Doxygen uses libiconv (or the\n# iconv built into libc) for the transcoding. See\n# https://www.gnu.org/software/libiconv/ for the list of possible encodings.\n# The default value is: UTF-8.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by\n# double-quotes, unless you are using Doxywizard) that should identify the\n# project for which the documentation is generated. This name is used in the\n# title of most generated pages and in a few other places.\n# The default value is: My Project.\n\nPROJECT_NAME           = cocotb\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. This\n# could be handy for archiving the generated documentation or if some version\n# control system is used.\n\nPROJECT_NUMBER         =\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer a\n# quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          =\n\n# With the PROJECT_LOGO tag one can specify a logo or an icon that is included\n# in the documentation. The maximum height of the logo should not exceed 55\n# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy\n# the logo to the output directory.\n\nPROJECT_LOGO           =\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path\n# into which the generated documentation will be written. If a relative path is\n# entered, it will be relative to the location where doxygen was started. If\n# left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = source/doxygen\n\n# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096\n# sub-directories (in 2 levels) under the output directory of each output format\n# and will distribute the generated files over these directories. Enabling this\n# option can be useful when feeding doxygen a huge amount of source files, where\n# putting all generated files in the same directory would otherwise causes\n# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to\n# control the number of sub-directories.\n# The default value is: NO.\n\nCREATE_SUBDIRS         = NO\n\n# Controls the number of sub-directories that will be created when\n# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every\n# level increment doubles the number of directories, resulting in 4096\n# directories at level 8 which is the default and also the maximum value. The\n# sub-directories are organized in 2 levels, the first level always has a fixed\n# number of 16 directories.\n# Minimum value: 0, maximum value: 8, default value: 8.\n# This tag requires that the tag CREATE_SUBDIRS is set to YES.\n\nCREATE_SUBDIRS_LEVEL   = 8\n\n# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII\n# characters to appear in the names of generated files. If set to NO, non-ASCII\n# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode\n# U+3044.\n# The default value is: NO.\n\nALLOW_UNICODE_NAMES    = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,\n# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English\n# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,\n# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with\n# English messages), Korean, Korean-en (Korean with English messages), Latvian,\n# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,\n# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,\n# Swedish, Turkish, Ukrainian and Vietnamese.\n# The default value is: English.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member\n# descriptions after the members that are listed in the file and class\n# documentation (similar to Javadoc). Set to NO to disable this.\n# The default value is: YES.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief\n# description of a member or function before the detailed description\n#\n# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n# The default value is: YES.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator that is\n# used to form the text in various listings. Each string in this list, if found\n# as the leading text of the brief description, will be stripped from the text\n# and the result, after processing the whole list, is used as the annotated\n# text. Otherwise, the brief description is used as-is. If left blank, the\n# following values are used ($name is automatically replaced with the name of\n# the entity):The $name class, The $name widget, The $name file, is, provides,\n# specifies, contains, represents, a, an and the.\n\nABBREVIATE_BRIEF       =\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# doxygen will generate a detailed section even if there is only a brief\n# description.\n# The default value is: NO.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n# The default value is: NO.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path\n# before files name in the file list and in the header files. If set to NO the\n# shortest path that makes the file name unique will be used\n# The default value is: YES.\n\nFULL_PATH_NAMES        = NO\n\n# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.\n# Stripping is only done if one of the specified strings matches the left-hand\n# part of the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the path to\n# strip.\n#\n# Note that you can specify absolute paths here, but also relative paths, which\n# will be relative from the directory where doxygen is started.\n# This tag requires that the tag FULL_PATH_NAMES is set to YES.\n\nSTRIP_FROM_PATH        =\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the\n# path mentioned in the documentation of a class, which tells the reader which\n# header file to include in order to use a class. If left blank only the name of\n# the header file containing the class definition is used. Otherwise one should\n# specify the list of include paths that are normally passed to the compiler\n# using the -I flag.\n\nSTRIP_FROM_INC_PATH    =\n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but\n# less readable) file names. This can be useful is your file systems doesn't\n# support long names like on DOS, Mac, or CD-ROM.\n# The default value is: NO.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the\n# first line (until the first dot) of a Javadoc-style comment as the brief\n# description. If set to NO, the Javadoc-style will behave just like regular Qt-\n# style comments (thus requiring an explicit @brief command for a brief\n# description.)\n# The default value is: NO.\n\nJAVADOC_AUTOBRIEF      = YES\n\n# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line\n# such as\n# /***************\n# as being the beginning of a Javadoc-style comment \"banner\". If set to NO, the\n# Javadoc-style will behave just like regular comments and it will not be\n# interpreted by doxygen.\n# The default value is: NO.\n\nJAVADOC_BANNER         = NO\n\n# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first\n# line (until the first dot) of a Qt-style comment as the brief description. If\n# set to NO, the Qt-style will behave just like regular Qt-style comments (thus\n# requiring an explicit \\brief command for a brief description.)\n# The default value is: NO.\n\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a\n# multi-line C++ special comment block (i.e. a block of //! or /// comments) as\n# a brief description. This used to be the default behavior. The new default is\n# to treat a multi-line C++ comment block as a detailed description. Set this\n# tag to YES if you prefer the old behavior instead.\n#\n# Note that setting this tag to YES also means that rational rose comments are\n# not recognized any more.\n# The default value is: NO.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# By default Python docstrings are displayed as preformatted text and doxygen's\n# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the\n# doxygen's special commands can be used and the contents of the docstring\n# documentation blocks is shown as doxygen documentation.\n# The default value is: YES.\n\nPYTHON_DOCSTRING       = YES\n\n# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the\n# documentation from any documented member that it re-implements.\n# The default value is: YES.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new\n# page for each member. If set to NO, the documentation of a member will be part\n# of the file/class/namespace that contains it.\n# The default value is: NO.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen\n# uses this value to replace tabs by spaces in code fragments.\n# Minimum value: 1, maximum value: 16, default value: 4.\n\nTAB_SIZE               = 4\n\n# This tag can be used to specify a number of aliases that act as commands in\n# the documentation. An alias has the form:\n# name=value\n# For example adding\n# \"sideeffect=@par Side Effects:^^\"\n# will allow you to put the command \\sideeffect (or @sideeffect) in the\n# documentation, which will result in a user-defined paragraph with heading\n# \"Side Effects:\". Note that you cannot put \\n's in the value part of an alias\n# to insert newlines (in the resulting output). You can put ^^ in the value part\n# of an alias to insert a newline as if a physical newline was in the original\n# file. When you need a literal { or } or , in the value part of an alias you\n# have to escape them by means of a backslash (\\), this can lead to conflicts\n# with the commands \\{ and \\} for these it is advised to use the version @{ and\n# @} or use a double escape (\\\\{ and \\\\})\n\nALIASES                =\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources\n# only. Doxygen will then generate output that is more tailored for C. For\n# instance, some of the names that are used will be different. The list of all\n# members will be omitted, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_FOR_C  = NO\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or\n# Python sources only. Doxygen will then generate output that is more tailored\n# for that language. For instance, namespaces will be presented as packages,\n# qualified scopes will look different, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources. Doxygen will then generate output that is tailored for Fortran.\n# The default value is: NO.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for VHDL.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice\n# sources only. Doxygen will then generate output that is more tailored for that\n# language. For instance, namespaces will be presented as modules, types will be\n# separated into more groups, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_SLICE  = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given\n# extension. Doxygen has a built-in mapping, but you can override or extend it\n# using this tag. The format is ext=language, where ext is a file extension, and\n# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,\n# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,\n# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:\n# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser\n# tries to guess whether the code is fixed or free formatted code, this is the\n# default for Fortran type files). For instance to make doxygen treat .inc files\n# as Fortran files (default is PHP), and .f files as C (default is Fortran),\n# use: inc=Fortran f=C.\n#\n# Note: For files without extension you can use no_extension as a placeholder.\n#\n# Note that for custom extensions you also need to set FILE_PATTERNS otherwise\n# the files are not read by doxygen. When specifying no_extension you should add\n# * to the FILE_PATTERNS.\n#\n# Note see also the list of default file extension mappings.\n\nEXTENSION_MAPPING      =\n\n# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments\n# according to the Markdown format, which allows for more readable\n# documentation. See https://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by doxygen, so you can\n# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in\n# case of backward compatibilities issues.\n# The default value is: YES.\n\nMARKDOWN_SUPPORT       = YES\n\n# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up\n# to that level are automatically included in the table of contents, even if\n# they do not have an id attribute.\n# Note: This feature currently applies only to Markdown headings.\n# Minimum value: 0, maximum value: 99, default value: 5.\n# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.\n\nTOC_INCLUDE_HEADINGS   = 5\n\n# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to\n# generate identifiers for the Markdown headings. Note: Every identifier is\n# unique.\n# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a\n# sequence number starting at 0 and GITHUB use the lower case version of title\n# with any whitespace replaced by '-' and punctuation characters removed.\n# The default value is: DOXYGEN.\n# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.\n\nMARKDOWN_ID_STYLE      = DOXYGEN\n\n# When enabled doxygen tries to link words that correspond to documented\n# classes, or namespaces to their corresponding documentation. Such a link can\n# be prevented in individual cases by putting a % sign in front of the word or\n# globally by setting AUTOLINK_SUPPORT to NO.\n# The default value is: YES.\n\nAUTOLINK_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should set this\n# tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string);\n# versus func(std::string) {}). This also make the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n# The default value is: NO.\n\nBUILTIN_STL_SUPPORT    = NO\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n# The default value is: NO.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:\n# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen\n# will parse them like normal C++ but will assume all classes use public instead\n# of private inheritance when no explicit protection keyword is present.\n# The default value is: NO.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate\n# getter and setter methods for a property. Setting this option to YES will make\n# doxygen to replace the get and set methods by a property in the documentation.\n# This will only work if the methods are indeed getting or setting a simple\n# type. If this is not the case, or you want to show the methods anyway, you\n# should set this option to NO.\n# The default value is: YES.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n# The default value is: NO.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# If one adds a struct or class to a group and this option is enabled, then also\n# any nested class or struct is added to the same group. By default this option\n# is disabled and one has to add nested compounds explicitly via \\ingroup.\n# The default value is: NO.\n\nGROUP_NESTED_COMPOUNDS = NO\n\n# Set the SUBGROUPING tag to YES to allow class member groups of the same type\n# (for instance a group of public functions) to be put as a subgroup of that\n# type (e.g. under the Public Functions section). Set it to NO to prevent\n# subgrouping. Alternatively, this can be done per class using the\n# \\nosubgrouping command.\n# The default value is: YES.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions\n# are shown inside the group in which they are included (e.g. using \\ingroup)\n# instead of on a separate page (for HTML and Man pages) or section (for LaTeX\n# and RTF).\n#\n# Note that this feature does not work in combination with\n# SEPARATE_MEMBER_PAGES.\n# The default value is: NO.\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions\n# with only public data fields or simple typedef fields will be shown inline in\n# the documentation of the scope in which they are defined (i.e. file,\n# namespace, or group documentation), provided this scope is documented. If set\n# to NO, structs, classes, and unions are shown on a separate page (for HTML and\n# Man pages) or section (for LaTeX and RTF).\n# The default value is: NO.\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or\n# enum is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically be\n# useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n# The default value is: NO.\n\nTYPEDEF_HIDES_STRUCT   = YES\n\n# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This\n# cache is used to resolve symbols given their name and scope. Since this can be\n# an expensive process and often the same symbol appears multiple times in the\n# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small\n# doxygen will become slower. If the cache is too large, memory is wasted. The\n# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range\n# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536\n# symbols. At the end of a run doxygen will report the cache usage and suggest\n# the optimal cache size from a speed point of view.\n# Minimum value: 0, maximum value: 9, default value: 0.\n\nLOOKUP_CACHE_SIZE      = 0\n\n# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use\n# during processing. When set to 0 doxygen will based this on the number of\n# cores available in the system. You can set it explicitly to a value larger\n# than 0 to get more control over the balance between CPU load and processing\n# speed. At this moment only the input processing can be done using multiple\n# threads. Since this is still an experimental feature the default is set to 1,\n# which effectively disables parallel processing. Please report any issues you\n# encounter. Generating dot graphs in parallel is controlled by the\n# DOT_NUM_THREADS setting.\n# Minimum value: 0, maximum value: 32, default value: 1.\n\nNUM_PROC_THREADS       = 1\n\n# If the TIMESTAMP tag is set different from NO then each generated page will\n# contain the date or date and time when the page was generated. Setting this to\n# NO can help when comparing the output of multiple runs.\n# Possible values are: YES, NO, DATETIME and DATE.\n# The default value is: NO.\n\nTIMESTAMP              = NO\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in\n# documentation are documented, even if no documentation was available. Private\n# class members and static file members will be hidden unless the\n# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.\n# Note: This will also disable the warnings about undocumented members that are\n# normally produced when WARNINGS is set to YES.\n# The default value is: NO.\n\nEXTRACT_ALL            = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will\n# be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIVATE        = NO\n\n# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual\n# methods of a class will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIV_VIRTUAL   = NO\n\n# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal\n# scope will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be\n# included in the documentation.\n# The default value is: NO.\n\nEXTRACT_STATIC         = NO\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined\n# locally in source files will be included in the documentation. If set to NO,\n# only classes defined in header files are included. Does not have any effect\n# for Java sources.\n# The default value is: YES.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. If set to YES, local methods,\n# which are defined in the implementation section but not in the interface are\n# included in the documentation. If set to NO, only methods in the interface are\n# included.\n# The default value is: NO.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base name of\n# the file that contains the anonymous namespace. By default anonymous namespace\n# are hidden.\n# The default value is: NO.\n\nEXTRACT_ANON_NSPACES   = NO\n\n# If this flag is set to YES, the name of an unnamed parameter in a declaration\n# will be determined by the corresponding definition. By default unnamed\n# parameters remain unnamed in the output.\n# The default value is: YES.\n\nRESOLVE_UNNAMED_PARAMS = YES\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all\n# undocumented members inside documented classes or files. If set to NO these\n# members will be included in the various overviews, but no documentation\n# section is generated. This option has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy. If set\n# to NO, these classes will be included in the various overviews. This option\n# will also hide undocumented C++ concepts if enabled. This option has no effect\n# if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend\n# declarations. If set to NO, these declarations will be included in the\n# documentation.\n# The default value is: NO.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any\n# documentation blocks found inside the body of a function. If set to NO, these\n# blocks will be appended to the function's detailed documentation block.\n# The default value is: NO.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation that is typed after a\n# \\internal command is included. If the tag is set to NO then the documentation\n# will be excluded. Set it to YES to include the internal documentation.\n# The default value is: NO.\n\nINTERNAL_DOCS          = NO\n\n# With the correct setting of option CASE_SENSE_NAMES doxygen will better be\n# able to match the capabilities of the underlying filesystem. In case the\n# filesystem is case sensitive (i.e. it supports files in the same directory\n# whose names only differ in casing), the option must be set to YES to properly\n# deal with such files in case they appear in the input. For filesystems that\n# are not case sensitive the option should be set to NO to properly deal with\n# output files written for symbols that only differ in casing, such as for two\n# classes, one named CLASS and the other named Class, and to also support\n# references to files without having to specify the exact matching casing. On\n# Windows (including Cygwin) and MacOS, users should typically set this option\n# to NO, whereas on Linux or other Unix flavors it should typically be set to\n# YES.\n# Possible values are: SYSTEM, NO and YES.\n# The default value is: SYSTEM.\n\nCASE_SENSE_NAMES       = YES\n\n# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with\n# their full class and namespace scopes in the documentation. If set to YES, the\n# scope will be hidden.\n# The default value is: NO.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will\n# append additional text to a page's title, such as Class Reference. If set to\n# YES the compound reference will be hidden.\n# The default value is: NO.\n\nHIDE_COMPOUND_REFERENCE= NO\n\n# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class\n# will show which file needs to be included to use the class.\n# The default value is: YES.\n\nSHOW_HEADERFILE        = YES\n\n# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of\n# the files that are included by a file in the documentation of that file.\n# The default value is: YES.\n\nSHOW_INCLUDE_FILES     = NO\n\n# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each\n# grouped member an include statement to the documentation, telling the reader\n# which file to include in order to use the member.\n# The default value is: NO.\n\nSHOW_GROUPED_MEMB_INC  = NO\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include\n# files with double quotes in the documentation rather than with sharp brackets.\n# The default value is: NO.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the\n# documentation for inline members.\n# The default value is: YES.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the\n# (detailed) documentation of file and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order.\n# The default value is: YES.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief\n# descriptions of file, namespace and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order. Note that\n# this will also influence the order of the classes in the class list.\n# The default value is: NO.\n\nSORT_BRIEF_DOCS        = NO\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the\n# (brief and detailed) documentation of class members so that constructors and\n# destructors are listed first. If set to NO the constructors will appear in the\n# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.\n# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief\n# member documentation.\n# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting\n# detailed member documentation.\n# The default value is: NO.\n\nSORT_MEMBERS_CTORS_1ST = NO\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy\n# of group names into alphabetical order. If set to NO the group names will\n# appear in their defined order.\n# The default value is: NO.\n\nSORT_GROUP_NAMES       = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by\n# fully-qualified names, including namespaces. If set to NO, the class list will\n# be sorted only by class name, not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the alphabetical\n# list.\n# The default value is: NO.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper\n# type resolution of all parameters of a function it will reject a match between\n# the prototype and the implementation of a member function even if there is\n# only one candidate or it is obvious which candidate to choose by doing a\n# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still\n# accept a match between prototype and implementation in such cases.\n# The default value is: NO.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo\n# list. This list is created by putting \\todo commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test\n# list. This list is created by putting \\test commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug\n# list. This list is created by putting \\bug commands in the documentation.\n# The default value is: YES.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)\n# the deprecated list. This list is created by putting \\deprecated commands in\n# the documentation.\n# The default value is: YES.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional documentation\n# sections, marked by \\if <section_label> ... \\endif and \\cond <section_label>\n# ... \\endcond blocks.\n\nENABLED_SECTIONS       =\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the\n# initial value of a variable or macro / define can have for it to appear in the\n# documentation. If the initializer consists of more lines than specified here\n# it will be hidden. Use a value of 0 to hide initializers completely. The\n# appearance of the value of individual variables and macros / defines can be\n# controlled using \\showinitializer or \\hideinitializer command in the\n# documentation regardless of this setting.\n# Minimum value: 0, maximum value: 10000, default value: 30.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at\n# the bottom of the documentation of classes and structs. If set to YES, the\n# list will mention the files that were used to generate the documentation.\n# The default value is: YES.\n\nSHOW_USED_FILES        = NO\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This\n# will remove the Files entry from the Quick Index and from the Folder Tree View\n# (if specified).\n# The default value is: YES.\n\nSHOW_FILES             = NO\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces\n# page. This will remove the Namespaces entry from the Quick Index and from the\n# Folder Tree View (if specified).\n# The default value is: YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command command input-file, where command is the value of the\n# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided\n# by doxygen. Whatever the program writes to standard output is used as the file\n# version. For an example see the documentation.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option. You can\n# optionally specify a file name after the option, if omitted DoxygenLayout.xml\n# will be used as the name of the layout file. See also section \"Changing the\n# layout of pages\" for information.\n#\n# Note that if you run doxygen from a directory containing a file called\n# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE\n# tag is left empty.\n\nLAYOUT_FILE            =\n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files containing\n# the reference definitions. This must be a list of .bib files. The .bib\n# extension is automatically appended if omitted. This requires the bibtex tool\n# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.\n# For LaTeX the style of the bibliography can be controlled using\n# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the\n# search path. See also \\cite for info how to create references.\n\nCITE_BIB_FILES         =\n\n#---------------------------------------------------------------------------\n# Configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated to\n# standard output by doxygen. If QUIET is set to YES this implies that the\n# messages are off.\n# The default value is: NO.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES\n# this implies that the warnings are on.\n#\n# Tip: Turn warnings on while writing the documentation.\n# The default value is: YES.\n\nWARNINGS               = YES\n\n# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate\n# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: YES.\n\nWARN_IF_UNDOCUMENTED   = NO\n\n# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as documenting some parameters in\n# a documented function twice, or documenting parameters that don't exist or\n# using markup commands wrongly.\n# The default value is: YES.\n\nWARN_IF_DOC_ERROR      = YES\n\n# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete\n# function parameter documentation. If set to NO, doxygen will accept that some\n# parameters have no documentation without warning.\n# The default value is: YES.\n\nWARN_IF_INCOMPLETE_DOC = YES\n\n# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that\n# are documented, but have no documentation for their parameters or return\n# value. If set to NO, doxygen will only warn about wrong parameter\n# documentation, but not about the absence of documentation. If EXTRACT_ALL is\n# set to YES then this flag will automatically be disabled. See also\n# WARN_IF_INCOMPLETE_DOC\n# The default value is: NO.\n\nWARN_NO_PARAMDOC       = NO\n\n# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about\n# undocumented enumeration values. If set to NO, doxygen will accept\n# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: NO.\n\nWARN_IF_UNDOC_ENUM_VAL = NO\n\n# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when\n# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS\n# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but\n# at the end of the doxygen process doxygen will return with a non-zero status.\n# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves\n# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not\n# write the warning messages in between other messages but write them at the end\n# of a run, in case a WARN_LOGFILE is defined the warning messages will be\n# besides being in the defined file also be shown at the end of a run, unless\n# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case\n# the behavior will remain as with the setting FAIL_ON_WARNINGS.\n# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.\n# The default value is: NO.\n\nWARN_AS_ERROR          = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that doxygen\n# can produce. The string should contain the $file, $line, and $text tags, which\n# will be replaced by the file and line number from which the warning originated\n# and the warning text. Optionally the format may contain $version, which will\n# be replaced by the version of the file (if it could be obtained via\n# FILE_VERSION_FILTER)\n# See also: WARN_LINE_FORMAT\n# The default value is: $file:$line: $text.\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# In the $text part of the WARN_FORMAT command it is possible that a reference\n# to a more specific place is given. To make it easier to jump to this place\n# (outside of doxygen) the user can define a custom \"cut\" / \"paste\" string.\n# Example:\n# WARN_LINE_FORMAT = \"'vi $file +$line'\"\n# See also: WARN_FORMAT\n# The default value is: at line $line of file $file.\n\nWARN_LINE_FORMAT       = \"at line $line of file $file\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning and error\n# messages should be written. If left blank the output is written to standard\n# error (stderr). In case the file specified cannot be opened for writing the\n# warning and error messages are written to standard error. When as file - is\n# specified the warning and error messages are written to standard output\n# (stdout).\n\nWARN_LOGFILE           =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag is used to specify the files and/or directories that contain\n# documented source files. You may enter file names like myfile.cpp or\n# directories like /usr/src/myproject. Separate the files or directories with\n# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING\n# Note: If this tag is empty the current directory is searched.\n\nINPUT                  = ../src/cocotb/share/include/gpi.h\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses\n# libiconv (or the iconv built into libc) for the transcoding. See the libiconv\n# documentation (see:\n# https://www.gnu.org/software/libiconv/) for the list of possible encodings.\n# See also: INPUT_FILE_ENCODING\n# The default value is: UTF-8.\n\nINPUT_ENCODING         = UTF-8\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify\n# character encoding on a per file pattern basis. Doxygen will compare the file\n# name with each pattern and apply the encoding instead of the default\n# INPUT_ENCODING) if there is a match. The character encodings are a list of the\n# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding\n# \"INPUT_ENCODING\" for further information on supported encodings.\n\nINPUT_FILE_ENCODING    =\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and\n# *.h) to filter out the source-files in the directories.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# read by doxygen.\n#\n# Note the list of default checked file patterns might differ from the list of\n# default file extension mappings.\n#\n# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,\n# *.cpp, *.cppm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl,\n# *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, *.php,\n# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be\n# provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,\n# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.\n\nFILE_PATTERNS          =\n\n# The RECURSIVE tag can be used to specify whether or not subdirectories should\n# be searched for input files as well.\n# The default value is: NO.\n\nRECURSIVE              = YES\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n#\n# Note that relative paths are relative to the directory from which doxygen is\n# run.\n\nEXCLUDE                =\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n# The default value is: NO.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories.\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       =\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# ANamespace::AClass, ANamespace::*Test\n\nEXCLUDE_SYMBOLS        =\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or directories\n# that contain example code fragments that are included (see the \\include\n# command).\n\nEXAMPLE_PATH           =\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank all\n# files are included.\n\nEXAMPLE_PATTERNS       =\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude commands\n# irrespective of the value of the RECURSIVE tag.\n# The default value is: NO.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or directories\n# that contain images that are to be included in the documentation (see the\n# \\image command).\n\nIMAGE_PATH             =\n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command:\n#\n# <filter> <input-file>\n#\n# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the\n# name of an input file. Doxygen will then use the output that the filter\n# program writes to standard output. If FILTER_PATTERNS is specified, this tag\n# will be ignored.\n#\n# Note that the filter must not add or remove lines; it is applied before the\n# code is scanned, but not when the output code is generated. If lines are added\n# or removed, the anchors will not be placed correctly.\n#\n# Note that doxygen will use the data processed and written to standard output\n# for further processing, therefore nothing else, like debug statements or used\n# commands (so in case of a Windows batch file always use @echo OFF), should be\n# written to standard output.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis. Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match. The filters are a list of the form: pattern=filter\n# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how\n# filters are used. If the FILTER_PATTERNS tag is empty or if none of the\n# patterns match the file name, INPUT_FILTER is applied.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will also be used to filter the input files that are used for\n# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).\n# The default value is: NO.\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and\n# it is also possible to disable source filtering for a specific pattern using\n# *.ext= (so without naming a filter).\n# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.\n\nFILTER_SOURCE_PATTERNS =\n\n# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that\n# is part of the input, its contents will be placed on the main page\n# (index.html). This can be useful if you have a project on for instance GitHub\n# and want to reuse the introduction page also for the doxygen output.\n\nUSE_MDFILE_AS_MAINPAGE =\n\n# The Fortran standard specifies that for fixed formatted Fortran code all\n# characters from position 72 are to be considered as comment. A common\n# extension is to allow longer lines before the automatic comment starts. The\n# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can\n# be processed before the automatic comment starts.\n# Minimum value: 7, maximum value: 10000, default value: 72.\n\nFORTRAN_COMMENT_AFTER  = 72\n\n#---------------------------------------------------------------------------\n# Configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will be\n# generated. Documented entities will be cross-referenced with these sources.\n#\n# Note: To get rid of all source code in the generated output, make sure that\n# also VERBATIM_HEADERS is set to NO.\n# The default value is: NO.\n\nSOURCE_BROWSER         = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body of functions,\n# classes and enums directly into the documentation.\n# The default value is: NO.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any\n# special comment blocks from generated source code fragments. Normal C, C++ and\n# Fortran comments will always remain visible.\n# The default value is: YES.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES then for each documented\n# entity all documented functions referencing it will be listed.\n# The default value is: NO.\n\nREFERENCED_BY_RELATION = NO\n\n# If the REFERENCES_RELATION tag is set to YES then for each documented function\n# all documented entities called/used by that function will be listed.\n# The default value is: NO.\n\nREFERENCES_RELATION    = NO\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set\n# to YES then the hyperlinks from functions in REFERENCES_RELATION and\n# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will\n# link to the documentation.\n# The default value is: YES.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the\n# source code will show a tooltip with additional information such as prototype,\n# brief description and links to the definition and documentation. Since this\n# will make the HTML file larger and loading of large files a bit slower, you\n# can opt to disable this feature.\n# The default value is: YES.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nSOURCE_TOOLTIPS        = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code will\n# point to the HTML generated by the htags(1) tool instead of doxygen built-in\n# source browser. The htags tool is part of GNU's global source tagging system\n# (see https://www.gnu.org/software/global/global.html). You will need version\n# 4.8.6 or higher.\n#\n# To use it do the following:\n# - Install the latest version of global\n# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file\n# - Make sure the INPUT points to the root of the source tree\n# - Run doxygen as normal\n#\n# Doxygen will invoke htags (and that will in turn invoke gtags), so these\n# tools must be available from the command line (i.e. in the search path).\n#\n# The result: instead of the source browser generated by doxygen, the links to\n# source code will now point to the output of htags.\n# The default value is: NO.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a\n# verbatim copy of the header file for each class for which an include is\n# specified. Set to NO to disable this.\n# See also: Section \\class.\n# The default value is: YES.\n\nVERBATIM_HEADERS       = YES\n\n# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the\n# clang parser (see:\n# http://clang.llvm.org/) for more accurate parsing at the cost of reduced\n# performance. This can be particularly helpful with template rich C++ code for\n# which doxygen's built-in parser lacks the necessary type information.\n# Note: The availability of this option depends on whether or not doxygen was\n# generated with the -Duse_libclang=ON option for CMake.\n# The default value is: NO.\n\nCLANG_ASSISTED_PARSING = NO\n\n# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS\n# tag is set to YES then doxygen will add the directory of each input to the\n# include path.\n# The default value is: YES.\n# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.\n\nCLANG_ADD_INC_PATHS    = YES\n\n# If clang assisted parsing is enabled you can provide the compiler with command\n# line options that you would normally use when invoking the compiler. Note that\n# the include paths will already be set by doxygen for the files and directories\n# specified with INPUT and INCLUDE_PATH.\n# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.\n\nCLANG_OPTIONS          =\n\n# If clang assisted parsing is enabled you can provide the clang parser with the\n# path to the directory containing a file called compile_commands.json. This\n# file is the compilation database (see:\n# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the\n# options used when the source files were built. This is equivalent to\n# specifying the -p option to a clang tool, such as clang-check. These options\n# will then be passed to the parser. Any options specified with CLANG_OPTIONS\n# will be added as well.\n# Note: The availability of this option depends on whether or not doxygen was\n# generated with the -Duse_libclang=ON option for CMake.\n\nCLANG_DATABASE_PATH    =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all\n# compounds will be generated. Enable this if the project contains a lot of\n# classes, structs, unions or interfaces.\n# The default value is: YES.\n\nALPHABETICAL_INDEX     = YES\n\n# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)\n# that should be ignored while generating the index headers. The IGNORE_PREFIX\n# tag works for classes, function and member names. The entity will be placed in\n# the alphabetical list under the first letter of the entity name that remains\n# after removing the prefix.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output\n# The default value is: YES.\n\nGENERATE_HTML          = NO\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each\n# generated HTML page (for example: .htm, .php, .asp).\n# The default value is: .html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a user-defined HTML header file for\n# each generated HTML page. If the tag is left blank doxygen will generate a\n# standard header.\n#\n# To get valid HTML the header file that includes any scripts and style sheets\n# that doxygen needs, which is dependent on the configuration options used (e.g.\n# the setting GENERATE_TREEVIEW). It is highly recommended to start with a\n# default header using\n# doxygen -w html new_header.html new_footer.html new_stylesheet.css\n# YourConfigFile\n# and then modify the file new_header.html. See also section \"Doxygen usage\"\n# for information on how to generate the default header that doxygen normally\n# uses.\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. For a description\n# of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_HEADER            =\n\n# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each\n# generated HTML page. If the tag is left blank doxygen will generate a standard\n# footer. See HTML_HEADER for more information on how to generate a default\n# footer and what special commands can be used inside the footer. See also\n# section \"Doxygen usage\" for information on how to generate the default footer\n# that doxygen normally uses.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FOOTER            =\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style\n# sheet that is used by each HTML page. It can be used to fine-tune the look of\n# the HTML output. If left blank doxygen will generate a default style sheet.\n# See also section \"Doxygen usage\" for information on how to generate the style\n# sheet that doxygen normally uses.\n# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as\n# it is more robust and this tag (HTML_STYLESHEET) will in the future become\n# obsolete.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_STYLESHEET        =\n\n# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# cascading style sheets that are included after the standard style sheets\n# created by doxygen. Using this option one can overrule certain style aspects.\n# This is preferred over using HTML_STYLESHEET since it does not replace the\n# standard style sheet and is therefore more robust against future updates.\n# Doxygen will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# Note: Since the styling of scrollbars can currently not be overruled in\n# Webkit/Chromium, the styling will be left out of the default doxygen.css if\n# one or more extra stylesheets have been specified. So if scrollbar\n# customization is desired it has to be added explicitly. For an example see the\n# documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_STYLESHEET  =\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that the\n# files will be copied as-is; there are no commands or markers available.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output\n# should be rendered with a dark or light theme.\n# Possible values are: LIGHT always generate light mode output, DARK always\n# generate dark mode output, AUTO_LIGHT automatically set the mode according to\n# the user preference, use light mode if no preference is set (the default),\n# AUTO_DARK automatically set the mode according to the user preference, use\n# dark mode if no preference is set and TOGGLE allow to user to switch between\n# light and dark mode via a button.\n# The default value is: AUTO_LIGHT.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE        = AUTO_LIGHT\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen\n# will adjust the colors in the style sheet and background images according to\n# this color. Hue is specified as an angle on a color-wheel, see\n# https://en.wikipedia.org/wiki/Hue for more information. For instance the value\n# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300\n# purple, and 360 is red again.\n# Minimum value: 0, maximum value: 359, default value: 220.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_HUE    = 220\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors\n# in the HTML output. For a value of 0 the output will use gray-scales only. A\n# value of 255 will produce the most vivid colors.\n# Minimum value: 0, maximum value: 255, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the\n# luminance component of the colors in the HTML output. Values below 100\n# gradually make the output lighter, whereas values above 100 make the output\n# darker. The value divided by 100 is the actual gamma applied, so 80 represents\n# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not\n# change the gamma.\n# Minimum value: 40, maximum value: 240, default value: 80.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML\n# documentation will contain a main index with vertical navigation menus that\n# are dynamically created via JavaScript. If disabled, the navigation index will\n# consists of multiple levels of tabs that are statically embedded in every HTML\n# page. Disable this option to support browsers that do not have JavaScript,\n# like the Qt help browser.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_MENUS     = YES\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be\n# dynamically folded and expanded in the generated HTML source code.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_CODE_FOLDING      = YES\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries\n# shown in the various tree structured indices initially; the user can expand\n# and collapse entries dynamically later on. Doxygen will expand the tree to\n# such a level that at most the specified number of entries are visible (unless\n# a fully collapsed tree already exceeds this amount). So setting the number of\n# entries 1 will produce a full collapsed tree by default. 0 is a special value\n# representing an infinite number of entries and will result in a full expanded\n# tree by default.\n# Minimum value: 0, maximum value: 9999, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files will be\n# generated that can be used as input for Apple's Xcode 3 integrated development\n# environment (see:\n# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To\n# create a documentation set, doxygen will generate a Makefile in the HTML\n# output directory. Running make will produce the docset in that directory and\n# running make install will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at\n# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy\n# genXcode/_index.html for more information.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_DOCSET        = NO\n\n# This tag determines the name of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# The default value is: Doxygen generated docs.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# This tag determines the URL of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDURL         =\n\n# This tag specifies a string that should uniquely identify the documentation\n# set bundle. This should be a reverse domain-name style string, e.g.\n# com.mycompany.MyDocSet. Doxygen will append .docset to the name.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n# The default value is: org.doxygen.Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.\n# The default value is: Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three\n# additional HTML index files: index.hhp, index.hhc, and index.hhk. The\n# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop\n# on Windows. In the beginning of 2021 Microsoft took the original page, with\n# a.o. the download links, offline the HTML help workshop was already many years\n# in maintenance mode). You can download the HTML help workshop from the web\n# archives at Installation executable (see:\n# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo\n# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).\n#\n# The HTML Help Workshop contains a compiler that can convert all HTML output\n# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML\n# files are now used as the Windows 98 help format, and will replace the old\n# Windows help format (.hlp) on all Windows platforms in the future. Compressed\n# HTML files also contain an index, a table of contents, and you can search for\n# words in the documentation. The HTML workshop also contains a viewer for\n# compressed HTML files.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_HTMLHELP      = NO\n\n# The CHM_FILE tag can be used to specify the file name of the resulting .chm\n# file. You can add a path in front of the file if the result should not be\n# written to the html output directory.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_FILE               =\n\n# The HHC_LOCATION tag can be used to specify the location (absolute path\n# including file name) of the HTML help compiler (hhc.exe). If non-empty,\n# doxygen will try to run the HTML help compiler on the generated index.hhp.\n# The file has to be specified with full path.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nHHC_LOCATION           =\n\n# The GENERATE_CHI flag controls if a separate .chi index file is generated\n# (YES) or that it should be included in the main .chm file (NO).\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nGENERATE_CHI           = NO\n\n# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)\n# and project file content.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_INDEX_ENCODING     =\n\n# The BINARY_TOC flag controls whether a binary table of contents is generated\n# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it\n# enables the Previous and Next buttons.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members to\n# the table of contents of the HTML help documentation and to the tree view.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nTOC_EXPAND             = NO\n\n# The SITEMAP_URL tag is used to specify the full URL of the place where the\n# generated documentation will be placed on the server by the user during the\n# deployment of the documentation. The generated sitemap is called sitemap.xml\n# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL\n# is specified no sitemap is generated. For information about the sitemap\n# protocol see https://www.sitemaps.org\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSITEMAP_URL            =\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that\n# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help\n# (.qch) of the generated HTML documentation.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify\n# the file name of the resulting .qch file. The path specified is relative to\n# the HTML output folder.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help\n# Project output. For more information please see Qt Help Project / Namespace\n# (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt\n# Help Project output. For more information please see Qt Help Project / Virtual\n# Folders (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).\n# The default value is: doc.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom\n# filter to add. For more information please see Qt Help Project / Custom\n# Filters (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see Qt Help Project / Custom\n# Filters (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's filter section matches. Qt Help Project / Filter Attributes (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# The QHG_LOCATION tag can be used to specify the location (absolute path\n# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to\n# run qhelpgenerator on the generated .qhp file.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be\n# generated, together with the HTML files, they form an Eclipse help plugin. To\n# install this plugin and make it available under the help contents menu in\n# Eclipse, the contents of the directory containing the HTML and XML files needs\n# to be copied into the plugins directory of eclipse. The name of the directory\n# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.\n# After copying Eclipse needs to be restarted before the help appears.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the Eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have this\n# name. Each documentation set should have its own identifier.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# If you want full control over the layout of the generated HTML pages it might\n# be necessary to disable the index and replace it with your own. The\n# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top\n# of each HTML page. A value of NO enables the index and the value YES disables\n# it. Since the tabs in the index contain the same information as the navigation\n# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nDISABLE_INDEX          = NO\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information. If the tag\n# value is set to YES, a side panel will be generated containing a tree-like\n# index structure (just like the one that is generated for HTML Help). For this\n# to work a browser that supports JavaScript, DHTML, CSS and frames is required\n# (i.e. any modern browser). Windows users are probably better off using the\n# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can\n# further fine tune the look of the index (see \"Fine-tuning the output\"). As an\n# example, the default style sheet generated by doxygen has an example that\n# shows how to put an image at the root of the tree instead of the PROJECT_NAME.\n# Since the tree basically has the same information as the tab index, you could\n# consider setting DISABLE_INDEX to YES when enabling this option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_TREEVIEW      = NO\n\n# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the\n# FULL_SIDEBAR option determines if the side bar is limited to only the treeview\n# area (value NO) or if it should extend to the full height of the window (value\n# YES). Setting this to YES gives a layout similar to\n# https://docs.readthedocs.io with more room for contents, but less room for the\n# project logo, title, and description. If either GENERATE_TREEVIEW or\n# DISABLE_INDEX is set to NO, this option has no effect.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFULL_SIDEBAR           = NO\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that\n# doxygen will group on one line in the generated HTML documentation.\n#\n# Note that a value of 0 will completely suppress the enum values from appearing\n# in the overview section.\n# Minimum value: 0, maximum value: 20, default value: 4.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used\n# to set the initial width (in pixels) of the frame in which the tree is shown.\n# Minimum value: 0, maximum value: 1500, default value: 250.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nTREEVIEW_WIDTH         = 250\n\n# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to\n# external symbols imported via tag files in a separate window.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email\n# addresses.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nOBFUSCATE_EMAILS       = YES\n\n# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg\n# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see\n# https://inkscape.org) to generate formulas as SVG images instead of PNGs for\n# the HTML output. These images will generally look nicer at scaled resolutions.\n# Possible values are: png (the default) and svg (looks nicer but requires the\n# pdf2svg or inkscape tool).\n# The default value is: png.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FORMULA_FORMAT    = png\n\n# Use this tag to change the font size of LaTeX formulas included as images in\n# the HTML documentation. When you change the font size after a successful\n# doxygen run you need to manually remove any form_*.png images from the HTML\n# output directory to force them to be regenerated.\n# Minimum value: 8, maximum value: 50, default value: 10.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_FONTSIZE       = 10\n\n# The FORMULA_MACROFILE can contain LaTeX \\newcommand and \\renewcommand commands\n# to create new LaTeX commands to be used in formulas as building blocks. See\n# the section \"Including formulas\" for details.\n\nFORMULA_MACROFILE      =\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see\n# https://www.mathjax.org) which uses client side JavaScript for the rendering\n# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX\n# installed or if you want to formulas look prettier in the HTML output. When\n# enabled you may also need to install MathJax separately and configure the path\n# to it using the MATHJAX_RELPATH option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nUSE_MATHJAX            = NO\n\n# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.\n# Note that the different versions of MathJax have different requirements with\n# regards to the different settings, so it is possible that also other MathJax\n# settings have to be changed when switching between the different MathJax\n# versions.\n# Possible values are: MathJax_2 and MathJax_3.\n# The default value is: MathJax_2.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_VERSION        = MathJax_2\n\n# When MathJax is enabled you can set the default output format to be used for\n# the MathJax output. For more details about the output format see MathJax\n# version 2 (see:\n# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3\n# (see:\n# http://docs.mathjax.org/en/latest/web/components/output.html).\n# Possible values are: HTML-CSS (which is slower, but has the best\n# compatibility. This is the name for Mathjax version 2, for MathJax version 3\n# this will be translated into chtml), NativeMML (i.e. MathML. Only supported\n# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This\n# is the name for Mathjax version 3, for MathJax version 2 this will be\n# translated into HTML-CSS) and SVG.\n# The default value is: HTML-CSS.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_FORMAT         = HTML-CSS\n\n# When MathJax is enabled you need to specify the location relative to the HTML\n# output directory using the MATHJAX_RELPATH option. The destination directory\n# should contain the MathJax.js script. For instance, if the mathjax directory\n# is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax\n# Content Delivery Network so you can quickly see the result without installing\n# MathJax. However, it is strongly recommended to install a local copy of\n# MathJax from https://www.mathjax.org before deployment. The default value is:\n# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2\n# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax\n# extension names that should be enabled during MathJax rendering. For example\n# for MathJax version 2 (see\n# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):\n# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols\n# For example for MathJax version 3 (see\n# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):\n# MATHJAX_EXTENSIONS = ams\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_EXTENSIONS     =\n\n# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces\n# of code that will be used on startup of the MathJax code. See the MathJax site\n# (see:\n# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an\n# example see the documentation.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_CODEFILE       =\n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box for\n# the HTML output. The underlying search engine uses javascript and DHTML and\n# should work on any modern browser. Note that when using HTML help\n# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)\n# there is already a search function so this one should typically be disabled.\n# For large projects the javascript based search engine can be slow, then\n# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to\n# search using the keyboard; to jump to the search box use <access key> + S\n# (what the <access key> is depends on the OS and browser, but it is typically\n# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down\n# key> to jump into the search results window, the results can be navigated\n# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel\n# the search. The filter options can be selected when the cursor is inside the\n# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>\n# to select a filter and <Enter> or <escape> to activate or cancel the filter\n# option.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSEARCHENGINE           = YES\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a web server instead of a web client using JavaScript. There\n# are two flavors of web server based searching depending on the EXTERNAL_SEARCH\n# setting. When disabled, doxygen will generate a PHP script for searching and\n# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing\n# and searching needs to be provided by external tools. See the section\n# \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSERVER_BASED_SEARCH    = NO\n\n# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP\n# script for searching. Instead the search results are written to an XML file\n# which needs to be processed by an external indexer. Doxygen will invoke an\n# external search engine pointed to by the SEARCHENGINE_URL option to obtain the\n# search results.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see:\n# https://xapian.org/).\n#\n# See the section \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH        = NO\n\n# The SEARCHENGINE_URL should point to a search engine hosted by a web server\n# which will return the search results when EXTERNAL_SEARCH is enabled.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see:\n# https://xapian.org/). See the section \"External Indexing and Searching\" for\n# details.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHENGINE_URL       =\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed\n# search data is written to a file for indexing by an external tool. With the\n# SEARCHDATA_FILE tag the name of this file can be specified.\n# The default file is: searchdata.xml.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHDATA_FILE        = searchdata.xml\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the\n# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is\n# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple\n# projects and redirect the results back to the right project.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH_ID     =\n\n# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen\n# projects other than the one defined by this configuration file, but that are\n# all added to the same external search index. Each project needs to have a\n# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of\n# to a relative location where the documentation can be found. The format is:\n# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTRA_SEARCH_MAPPINGS  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.\n# The default value is: YES.\n\nGENERATE_LATEX         = NO\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked.\n#\n# Note that when not enabling USE_PDFLATEX the default is latex when enabling\n# USE_PDFLATEX the default is pdflatex and when in the later case latex is\n# chosen this is overwritten by pdflatex. For specific output languages the\n# default can have been set differently, this depends on the implementation of\n# the output language.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate\n# index for LaTeX.\n# Note: This tag is used in the Makefile / make.bat.\n# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file\n# (.tex).\n# The default file is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to\n# generate index for LaTeX. In case there is no backslash (\\) as first character\n# it will be automatically added in the LaTeX code.\n# Note: This tag is used in the generated output file (.tex).\n# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.\n# The default value is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_MAKEINDEX_CMD    = makeindex\n\n# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used by the\n# printer.\n# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x\n# 14 inches) and executive (7.25 x 10.5 inches).\n# The default value is: a4.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPAPER_TYPE             = a4\n\n# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names\n# that should be included in the LaTeX output. The package can be specified just\n# by its name or with the correct syntax as to be used with the LaTeX\n# \\usepackage command. To get the times font for instance you can specify :\n# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}\n# To use the option intlimits with the amsmath package you can specify:\n# EXTRA_PACKAGES=[intlimits]{amsmath}\n# If left blank no extra packages will be included.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for\n# the generated LaTeX document. The header should contain everything until the\n# first chapter. If it is left blank doxygen will generate a standard header. It\n# is highly recommended to start with a default header using\n# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty\n# and then modify the file new_header.tex. See also section \"Doxygen usage\" for\n# information on how to generate the default header that doxygen normally uses.\n#\n# Note: Only use a user-defined header if you know what you are doing!\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. The following\n# commands have a special meaning inside the header (and footer): For a\n# description of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for\n# the generated LaTeX document. The footer should contain everything after the\n# last chapter. If it is left blank doxygen will generate a standard footer. See\n# LATEX_HEADER for more information on how to generate a default footer and what\n# special commands can be used inside the footer. See also section \"Doxygen\n# usage\" for information on how to generate the default footer that doxygen\n# normally uses. Note: Only use a user-defined footer if you know what you are\n# doing!\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_FOOTER           =\n\n# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# LaTeX style sheets that are included after the standard style sheets created\n# by doxygen. Using this option one can overrule certain style aspects. Doxygen\n# will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_STYLESHEET =\n\n# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the LATEX_OUTPUT output\n# directory. Note that the files will be copied as-is; there are no commands or\n# markers available.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_FILES      =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is\n# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will\n# contain links (just like the HTML output) instead of page references. This\n# makes the output suitable for online browsing using a PDF viewer.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPDF_HYPERLINKS         = YES\n\n# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as\n# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX\n# files. Set this option to YES, to get a higher quality PDF documentation.\n#\n# See also section LATEX_CMD_NAME for selecting the engine.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nUSE_PDFLATEX           = YES\n\n# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.\n# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch\n# mode nothing is printed on the terminal, errors are scrolled as if <return> is\n# hit at every error; missing files that TeX tries to input or request from\n# keyboard input (\\read on a not open input stream) cause the job to abort,\n# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,\n# but there is no possibility of user interaction just like in batch mode,\n# SCROLL In scroll mode, TeX will stop only for missing files to input or if\n# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at\n# each error, asking for user intervention.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BATCHMODE        = NO\n\n# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the\n# index chapters (such as File Index, Compound Index, etc.) in the output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HIDE_INDICES     = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. See\n# https://en.wikipedia.org/wiki/BibTeX and \\cite for more info.\n# The default value is: plain.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BIB_STYLE        = plain\n\n# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)\n# path from which the emoji images will be read. If a relative path is entered,\n# it will be relative to the LATEX_OUTPUT directory. If left blank the\n# LATEX_OUTPUT directory will be used.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EMOJI_DIRECTORY  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The\n# RTF output is optimized for Word 97 and may not look too pretty with other RTF\n# readers/editors.\n# The default value is: NO.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: rtf.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will\n# contain hyperlink fields. The RTF file will contain links (just like the HTML\n# output) instead of page references. This makes the output suitable for online\n# browsing using Word or some other Word compatible readers that support those\n# fields.\n#\n# Note: WordPad (write) and others do not support links.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's\n# configuration file, i.e. a series of assignments. You only have to provide\n# replacements, missing definitions are set to their default value.\n#\n# See also section \"Doxygen usage\" for information on how to generate the\n# default style sheet that doxygen normally uses.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an RTF document. Syntax is\n# similar to doxygen's configuration file. A template extensions file can be\n# generated using doxygen -e rtf extensionFile.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_EXTENSIONS_FILE    =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for\n# classes and files.\n# The default value is: NO.\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it. A directory man3 will be created inside the directory specified by\n# MAN_OUTPUT.\n# The default directory is: man.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to the generated\n# man pages. In case the manual section does not start with a number, the number\n# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is\n# optional.\n# The default value is: .3.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_EXTENSION          = .3\n\n# The MAN_SUBDIR tag determines the name of the directory created within\n# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by\n# MAN_EXTENSION with the initial . removed.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_SUBDIR             =\n\n# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it\n# will generate one additional man file for each entity documented in the real\n# man page(s). These additional files only source the real man page, but without\n# them the man command would be unable to find the correct page.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that\n# captures the structure of the code including all documentation.\n# The default value is: NO.\n\nGENERATE_XML           = YES\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: xml.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_OUTPUT             = _xml\n\n# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program\n# listings (including syntax highlighting and cross-referencing information) to\n# the XML output. Note that enabling this will significantly increase the size\n# of the XML output.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_PROGRAMLISTING     = NO\n\n# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include\n# namespace members in file scope as well, matching the HTML output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_NS_MEMB_FILE_SCOPE = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the DOCBOOK output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files\n# that can be used to generate PDF.\n# The default value is: NO.\n\nGENERATE_DOCBOOK       = NO\n\n# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in\n# front of it.\n# The default directory is: docbook.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_OUTPUT         = docbook\n\n#---------------------------------------------------------------------------\n# Configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an\n# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures\n# the structure of the code including all documentation. Note that this feature\n# is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to Sqlite3 output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3\n# database with symbols found by doxygen stored in tables.\n# The default value is: NO.\n\nGENERATE_SQLITE3       = NO\n\n# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be\n# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put\n# in front of it.\n# The default directory is: sqlite3.\n# This tag requires that the tag GENERATE_SQLITE3 is set to YES.\n\nSQLITE3_OUTPUT         = sqlite3\n\n# The SQLITE3_OVERWRITE_DB tag is set to YES, the existing doxygen_sqlite3.db\n# database file will be recreated with each doxygen run. If set to NO, doxygen\n# will warn if an a database file is already found and not modify it.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_SQLITE3 is set to YES.\n\nSQLITE3_RECREATE_DB    = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module\n# file that captures the structure of the code including all documentation.\n#\n# Note that this feature is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary\n# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI\n# output from the Perl module output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely\n# formatted so it can be parsed by a human reader. This is useful if you want to\n# understand what is going on. On the other hand, if this tag is set to NO, the\n# size of the Perl module output will be much smaller and Perl will parse it\n# just the same.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file are\n# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful\n# so different doxyrules.make files included by the same Makefile don't\n# overwrite each other's variables.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all\n# C-preprocessor directives found in the sources and include files.\n# The default value is: YES.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names\n# in the source code. If set to NO, only conditional compilation will be\n# performed. Macro expansion can be done in a controlled way by setting\n# EXPAND_ONLY_PREDEF to YES.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then\n# the macro expansion is limited to the macros specified with the PREDEFINED and\n# EXPAND_AS_DEFINED tags.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES, the include files in the\n# INCLUDE_PATH will be searched if a #include is found.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by the\n# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of\n# RECURSIVE has no effect here.\n# This tag requires that the tag SEARCH_INCLUDES is set to YES.\n\nINCLUDE_PATH           =\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will be\n# used.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that are\n# defined before the preprocessor is started (similar to the -D option of e.g.\n# gcc). The argument of the tag is a list of macros of the form: name or\n# name=definition (no spaces). If the definition and the \"=\" are omitted, \"=1\"\n# is assumed. To prevent a macro definition from being undefined via #undef or\n# recursively expanded use the := operator instead of the = operator.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nPREDEFINED             =\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this\n# tag can be used to specify a list of macro names that should be expanded. The\n# macro definition that is found in the sources will be used. Use the PREDEFINED\n# tag if you want to use a different macro definition that overrules the\n# definition found in the source code.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will\n# remove all references to function-like macros that are alone on a line, have\n# an all uppercase name, and do not end with a semicolon. Such function macros\n# are typically used for boiler-plate code, and will confuse the parser if not\n# removed.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES tag can be used to specify one or more tag files. For each tag\n# file the location of the external documentation should be added. The format of\n# a tag file without this location is as follows:\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where loc1 and loc2 can be relative or absolute paths or URLs. See the\n# section \"Linking to external documentation\" for more information about the use\n# of tag files.\n# Note: Each tag file must have a unique name (where the name does NOT include\n# the path). If a tag file is not located in the directory in which doxygen is\n# run, you must also specify the path to the tagfile here.\n\nTAGFILES               =\n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create a\n# tag file that is based on the input files it reads. See section \"Linking to\n# external documentation\" for more information about the usage of tag files.\n\nGENERATE_TAGFILE       =\n\n# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces\n# will be listed in the class and namespace index. If set to NO, only the\n# inherited external classes will be listed.\n# The default value is: NO.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed\n# in the topic index. If set to NO, only the current project's groups will be\n# listed.\n# The default value is: YES.\n\nEXTERNAL_GROUPS        = YES\n\n# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in\n# the related pages index. If set to NO, only the current project's pages will\n# be listed.\n# The default value is: YES.\n\nEXTERNAL_PAGES         = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to diagram generator tools\n#---------------------------------------------------------------------------\n\n# If set to YES the inheritance and collaboration graphs will hide inheritance\n# and usage relations if the target is undocumented or is not a class.\n# The default value is: YES.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz (see:\n# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent\n# Bell Labs. The other options in this section have no effect if this option is\n# set to NO\n# The default value is: YES.\n\nHAVE_DOT               = YES\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed\n# to run in parallel. When set to 0 doxygen will base this on the number of\n# processors available in the system. You can set it explicitly to a value\n# larger than 0 to get control over the balance between CPU load and processing\n# speed.\n# Minimum value: 0, maximum value: 32, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NUM_THREADS        = 0\n\n# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of\n# subgraphs. When you want a differently looking font in the dot files that\n# doxygen generates you can specify fontname, fontcolor and fontsize attributes.\n# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,\n# Edge and Graph Attributes specification</a> You need to make sure dot is able\n# to find the font, which can be done by putting it in a standard location or by\n# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the\n# directory containing the font. Default graphviz fontsize is 14.\n# The default value is: fontname=Helvetica,fontsize=10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_COMMON_ATTR        = \"fontname=Helvetica,fontsize=10\"\n\n# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can\n# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a\n# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about\n# arrows shapes.</a>\n# The default value is: labelfontname=Helvetica,labelfontsize=10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_EDGE_ATTR          = \"labelfontname=Helvetica,labelfontsize=10\"\n\n# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes\n# around nodes set 'shape=plain' or 'shape=plaintext' <a\n# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>\n# The default value is: shape=box,height=0.2,width=0.4.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NODE_ATTR          = \"shape=box,height=0.2,width=0.4\"\n\n# You can set the path where dot can find font specified with fontname in\n# DOT_COMMON_ATTR and others dot attributes.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will\n# generate a graph for each documented class showing the direct and indirect\n# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and\n# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case\n# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the\n# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.\n# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance\n# relations will be shown as texts / links.\n# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.\n# The default value is: YES.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a\n# graph for each documented class showing the direct and indirect implementation\n# dependencies (inheritance, containment, and class references variables) of the\n# class with other documented classes. Explicit enabling a collaboration graph,\n# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the\n# command \\collaborationgraph. Disabling a collaboration graph can be\n# accomplished by means of the command \\hidecollaborationgraph.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for\n# groups, showing the direct groups dependencies. Explicit enabling a group\n# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means\n# of the command \\groupgraph. Disabling a directory graph can be accomplished by\n# means of the command \\hidegroupgraph. See also the chapter Grouping in the\n# manual.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LOOK               = NO\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside the\n# class node. If there are many fields or methods and many nodes the graph may\n# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the\n# number of items for each type to make the size more manageable. Set this to 0\n# for no limit. Note that the threshold may be exceeded by 50% before the limit\n# is enforced. So when you set the threshold to 10, up to 15 fields may appear,\n# but if the number exceeds 15, the total amount of fields shown is limited to\n# 10.\n# Minimum value: 0, maximum value: 100, default value: 10.\n# This tag requires that the tag UML_LOOK is set to YES.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and\n# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS\n# tag is set to YES, doxygen will add type and arguments for attributes and\n# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen\n# will not generate fields with class member information in the UML graphs. The\n# class diagrams will look similar to the default class diagrams but using UML\n# notation for the relationships.\n# Possible values are: NO, YES and NONE.\n# The default value is: NO.\n# This tag requires that the tag UML_LOOK is set to YES.\n\nDOT_UML_DETAILS        = NO\n\n# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters\n# to display on a single line. If the actual line length exceeds this threshold\n# significantly it will wrapped across multiple lines. Some heuristics are apply\n# to avoid ugly line breaks.\n# Minimum value: 0, maximum value: 1000, default value: 17.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_WRAP_THRESHOLD     = 17\n\n# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and\n# collaboration graphs will show the relations between templates and their\n# instances.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to\n# YES then doxygen will generate a graph for each documented file showing the\n# direct and indirect include dependencies of the file with other documented\n# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,\n# can be accomplished by means of the command \\includegraph. Disabling an\n# include graph can be accomplished by means of the command \\hideincludegraph.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDE_GRAPH          = YES\n\n# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are\n# set to YES then doxygen will generate a graph for each documented file showing\n# the direct and indirect include dependencies of the file with other documented\n# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set\n# to NO, can be accomplished by means of the command \\includedbygraph. Disabling\n# an included by graph can be accomplished by means of the command\n# \\hideincludedbygraph.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH tag is set to YES then doxygen will generate a call\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable call graphs for selected\n# functions only using the \\callgraph command. Disabling a call graph can be\n# accomplished by means of the command \\hidecallgraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALL_GRAPH             = NO\n\n# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable caller graphs for selected\n# functions only using the \\callergraph command. Disabling a caller graph can be\n# accomplished by means of the command \\hidecallergraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALLER_GRAPH           = NO\n\n# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical\n# hierarchy of all classes instead of a textual one.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the\n# dependencies a directory has on other directories in a graphical way. The\n# dependency relations are determined by the #include relations between the\n# files in the directories. Explicit enabling a directory graph, when\n# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command\n# \\directorygraph. Disabling a directory graph can be accomplished by means of\n# the command \\hidedirectorygraph.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDIRECTORY_GRAPH        = YES\n\n# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels\n# of child directories generated in directory dependency graphs by dot.\n# Minimum value: 1, maximum value: 25, default value: 1.\n# This tag requires that the tag DIRECTORY_GRAPH is set to YES.\n\nDIR_GRAPH_MAX_DEPTH    = 1\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. For an explanation of the image formats see the section\n# output formats in the documentation of the dot tool (Graphviz (see:\n# https://www.graphviz.org/)).\n# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order\n# to make the SVG files visible in IE 9+ (other browsers do not have this\n# requirement).\n# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd,\n# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd,\n# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and\n# png:gdiplus:gdiplus.\n# The default value is: png.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_IMAGE_FORMAT       = png\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n#\n# Note that this requires a modern browser other than Internet Explorer. Tested\n# and working are Firefox, Chrome, Safari, and Opera.\n# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make\n# the SVG files visible. Older versions of IE do not have SVG support.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINTERACTIVE_SVG        = NO\n\n# The DOT_PATH tag can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_PATH               =\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the \\dotfile\n# command).\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOTFILE_DIRS           =\n\n# You can include diagrams made with dia in doxygen documentation. Doxygen will\n# then run dia to produce the diagram and insert it in the documentation. The\n# DIA_PATH tag allows you to specify the directory where the dia binary resides.\n# If left empty dia is assumed to be found in the default search path.\n\nDIA_PATH               =\n\n# The DIAFILE_DIRS tag can be used to specify one or more directories that\n# contain dia files that are included in the documentation (see the \\diafile\n# command).\n\nDIAFILE_DIRS           =\n\n# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the\n# path where java can find the plantuml.jar file or to the filename of jar file\n# to be used. If left blank, it is assumed PlantUML is not used or called during\n# a preprocessing step. Doxygen will generate a warning when it encounters a\n# \\startuml command in this case and will not generate output for the diagram.\n\nPLANTUML_JAR_PATH      =\n\n# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a\n# configuration file for plantuml.\n\nPLANTUML_CFG_FILE      =\n\n# When using plantuml, the specified paths are searched for files specified by\n# the !include statement in a plantuml block.\n\nPLANTUML_INCLUDE_PATH  =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes\n# that will be shown in the graph. If the number of nodes in a graph becomes\n# larger than this value, doxygen will truncate the graph, which is visualized\n# by representing a node as a red box. Note that doxygen if the number of direct\n# children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that\n# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n# Minimum value: 0, maximum value: 10000, default value: 50.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_GRAPH_MAX_NODES    = 50\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs\n# generated by dot. A depth value of 3 means that only nodes reachable from the\n# root by following a path via at most 3 edges will be shown. Nodes that lay\n# further from the root node will be omitted. Note that setting this option to 1\n# or 2 may greatly reduce the computation time needed for large code bases. Also\n# note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n# Minimum value: 0, maximum value: 1000, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10) support\n# this, this feature is disabled by default.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page\n# explaining the meaning of the various boxes and arrows in the dot generated\n# graphs.\n# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal\n# graphical representation for inheritance and collaboration diagrams is used.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate\n# files that are used to generate the various graphs.\n#\n# Note: This setting is not only used for dot files but also for msc temporary\n# files.\n# The default value is: YES.\n\nDOT_CLEANUP            = YES\n\n# You can define message sequence charts within doxygen comments using the \\msc\n# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will\n# use a built-in version of mscgen tool to produce the charts. Alternatively,\n# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,\n# specifying prog as the value, doxygen will call the tool as prog -T\n# <outfile_format> -o <outputfile> <inputfile>. The external tool should support\n# output file formats \"png\", \"eps\", \"svg\", and \"ismap\".\n\nMSCGEN_TOOL            =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the \\mscfile\n# command).\n\nMSCFILE_DIRS           =\n"
  },
  {
    "path": "docs/README.md",
    "content": "cocotb documentation\n====================\n\nThis directory contains the documentation of cocotb, which is built with Doxygen and Sphinx.\nThe documentation is automatically built and uploaded with every pull request.\nThe documentation for the `master` branch can be found [here](https://docs.cocotb.org/en/development/).\n\n`nox -e docs` can be used to create an appropriate virtual environment and\ninvoke `sphinx-build` to generate the HTML docs.\n\nIn addition to the Python dependencies managed by `nox`, `doxygen` must be\ninstalled.\n\nOther nox environments (run with `nox -e <env>`):\n* `docs_linkcheck` - run the Sphinx `linkcheck` builder\n* `docs_spelling` - run a spellchecker on the documentation\n"
  },
  {
    "path": "docs/source/_static/cocotb.css",
    "content": "/*\n\nhttps://github.com/cocotb/cocotb-web/blob/master/_sass/_custom-styles.scss\nhttps://github.com/cocotb/cocotb-web/blob/master/_sass/_custom-variables.scss\n\nhttps://www.cocotb.org/assets/css/bootstrap-theme.css\n\n*/\n\n:root {\n    --color-cocotb-blue: #3776ab;\n    --color-cocotb-blue-darker: rgb(44, 94, 137);\n    --color-cocotb-red: #b41d2e;\n    --color-cocotb-yellow: #ffcd3c;\n    --color-cocotb-green: rgb(79, 196, 100);\n    --color-cocotb-green-bg: #e7f6f1;\n    --bs-primary: var(--color-cocotb-blue) !important;\n    --bs-secondary: var(--color-cocotb-yellow) !important;\n}\n\nhtml {\n    --bs-border-radius: 0 !important;\n    --bs-border-radius-sm: 0 !important;\n    --bs-border-radius-ls: 0 !important;\n    --bs-border-radius-pill: 0 !important;\n\n    --pst-font-family-base: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\", var(--pst-font-family-base-system);\n    --pst-font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", var(--pst-font-family-monospace-system);\n\n    /* base font size - applied at body/html level */\n    --pst-font-size-base: 1.0rem;\n    --pst-sidebar-font-size: 1.0rem;\n    --pst-sidebar-header-font-size: unset;\n    --pst-sidebar-header-font-weight: bold;\n\n    /* heading font sizes based on bootstrap sizing */\n    --pst-font-size-h1: 2.0rem;\n    --pst-font-size-h2: 1.75rem;\n    --pst-font-size-h3: 1.5rem;\n    --pst-font-size-h4: 1.4rem;\n    --pst-font-size-h5: 1.3rem;\n    --pst-font-size-h6: 1.2rem;\n\n    --pst-font-size-milli: 0.75rem;\n\n    /* --pst-font-weight-caption: 300; */\n    --pst-font-weight-caption: 400;\n    --pst-font-weight-heading: 700;\n    --pst-admonition-font-weight-heading: 700;\n\n    --pst-icon-admonition-attention: none;\n    --pst-icon-admonition-caution: none;\n    --pst-icon-admonition-danger: none;\n    --pst-icon-admonition-default: none;\n    --pst-icon-admonition-error: none;\n    --pst-icon-admonition-hint: none;\n    --pst-icon-admonition-important: none;\n    --pst-icon-admonition-note: none;\n    --pst-icon-admonition-seealso: none;\n    --pst-icon-admonition-tip: none;\n    --pst-icon-admonition-todo: none;\n    --pst-icon-admonition-warning: none;\n\n    --pst-icon-versionmodified-default: none;\n    --pst-icon-versionmodified-added: none;\n    --pst-icon-versionmodified-changed: none;\n    --pst-icon-versionmodified-deprecated: none;\n\n    --pst-color-primary: var(--color-cocotb-blue) !important;\n    --pst-color-secondary: var(--color-cocotb-yellow) !important;\n    --pst-color-secondary-highlight: var(--color-cocotb-blue) !important;\n    --pst-color-accent: var(--color-cocotb-yellow) !important;\n\n    --pst-color-link: var(--color-cocotb-blue) !important;\n    --pst-color-link-hover: var(--color-cocotb-blue-darker) !important;\n}\n\nbody {\n    line-height: 1.5;\n}\n\nh1 {\n    color: var(--color-cocotb-blue) !important;\n    line-height: 60px !important;\n}\n\nh1, h2, h3, h4, h5, h6 {\n    margin: calc(0.7 * 2.75rem) 0 calc(0.7 * 1.05rem) !important;\n}\n\nh1, h2, h3, h4, h5 {\n    font-weight: bold !important;\n}\n\nh6 {\n    font-style: italic !important;\n}\n\n/* settings based on the ones from https://cocotb.org, but apply non-linear scaling of font sizes */\nh1 { font-size: calc(0.9 * (1.375rem + 1.5vw)); }\n@media (min-width: 1200px) { h1 { font-size: calc(0.9 * 2.5rem); } }\n\nh2 { font-size: calc(0.8 * (1.325rem + 0.9vw)); }\n@media (min-width: 1200px) { h2 { font-size: calc(0.8 * 2rem); } }\n\nh3 { font-size: calc(0.7 * (1.3rem + 0.6vw)); }\n@media (min-width: 1200px) { h3 { font-size: calc(0.7 * 1.75rem); } }\n\nh4 { font-size: calc(0.7 * (1.275rem + 0.3vw)); }\n@media (min-width: 1200px) { h4 { font-size: calc(0.7 * 1.5rem); } }\n\nh5, h6 { font-size: 1.0rem; }\n\n.admonition-title {\n    background-color: white !important;\n    font-style: normal !important;\n}\n\ndiv.admonition > p.admonition-title,\ndiv.admonition > p.admonition-title + p {\n    display: inline;\n}\n\n.admonition p.admonition-title ~ *,\ndiv.admonition p.admonition-title ~ * {\n    margin: 0;\n}\n\n.admonition > .admonition-title,\ndiv.admonition > .admonition-title {\n    display: inline;\n    margin: 0;\n    margin-right: 0.2rem;\n    padding: 0;\n}\n\nblockquote {\n    border-radius: 0 !important;\n    box-shadow: none !important;\n    padding-top: 0.25rem !important;\n    padding-bottom: 0.25rem !important;\n}\n\ndiv.admonition {\n    border-radius: 0 !important;\n    border-color: var(--color-cocotb-blue) !important;\n    box-shadow: none !important;\n    padding-bottom: 0 !important;\n    margin: 1rem auto !important;\n}\n\ndiv.deprecated,\ndiv.versionadded,\ndiv.versionchanged,\ndiv.versionremoved {\n    background-color: white !important;\n    /* font-size: 0.75rem !important; */ /* TODO: decide on this */\n    border-radius: 0 !important;\n    box-shadow: none !important;\n    margin: 1.0rem auto;\n}\n\n.admonition.warning,\ndiv.deprecated,\ndiv.versionremoved {\n    border-color: var(--color-cocotb-yellow) !important;\n}\n\ndiv.versionadded {\n    border-color: var(--color-cocotb-green) !important;\n}\n\nblockquote,\n.admonition.note,\ndiv.versionchanged {\n    border-color: var(--color-cocotb-blue) !important;\n}\n\ndiv.deprecated > p,\ndiv.versionadded > p,\ndiv.versionchanged > p,\ndiv.versionremoved > p {\n    margin: 0 !important;\n}\n\n/* TODO: can be removed once https://github.com/pydata/pydata-sphinx-theme/pull/2087 is in a release */\ndiv.versionremoved {\n    vertical-align: middle;\n    margin: 1.5625em auto;\n    padding: 0 0.6rem;\n    overflow: hidden;\n    /* break-inside has replaced page-break-inside and is widely usable since 2019 */\n    page-break-inside: avoid;\n    break-inside: avoid;\n    border-left: 0.2rem solid;\n    border-color: var(--pst-color-info);\n    background-color: var(--pst-color-on-background);\n    /* @include box-shadow; */\n    position: relative;\n}\n\n/* TODO: can be removed once https://github.com/pydata/pydata-sphinx-theme/pull/2087 is in a release */\ndiv.versionremoved > p {\n    margin-bottom: 0.6rem;\n    margin-top: 0.6rem;\n}\n\nspan.versionmodified {\n    font-style: italic !important;\n    font-weight: normal !important;\n}\n\na.headerlink {\n    color: var(--pst-color-secondary) !important;\n}\n\na {\n    color: var(--pst-color-primary) !important;\n    text-decoration-style: solid !important;\n}\n\n/* \"Hide Search Matches\" */\ndiv#searchbox p.highlight-link a {\n    background-color: var(--pst-color-on-background) !important;\n}\n\na:hover {\n    color: var(--color-cocotb-blue-darker) !important;\n    text-decoration-thickness: 1px !important;\n}\n\nlabel.sd-tab-label:hover {\n    color: var(--color-cocotb-blue-darker) !important;\n    text-decoration-thickness: unset !important;\n}\n\n/* code.literal, */\nstrong.command {\n    color: var(--color-cocotb-blue) !important;\n    background-color: var(--pst-color-surface) !important;\n    font-family: var(--pst-font-family-monospace) !important;\n    font-size: 0.875rem !important;\n    font-weight: normal !important;\n    border: 1px solid var(--pst-color-border) !important;\n    border-radius: 0 !important;\n    padding: .1rem .25rem !important;\n}\n\n.pre {\n    color: var(--color-cocotb-blue) !important;\n    font-size: 16px;\n}\n\ncode.xref {\n  background-color: transparent;\n  font-weight: normal;\n}\n\nh1:has(code.xref) code.xref, h2:has(code.xref) code.xref, h3:has(code.xref) code.xref, h4:has(code.xref) code.xref, h5:has(code.xref) code.xref, h6:has(code.xref) code.xref {\n  font-weight: bold !important;\n}\n\n/* horizontal rule above */\ndl.py.class dt.sig.sig-object,\ndl.py.exception dt.sig.sig-object,\ndl.py.type dt.sig.sig-object,\ndl.py.data dt.sig.sig-object,\ndl.py.decorator dt.sig.sig-object,\ndl.py.function dt.sig.sig-object {\n  padding-top: 1.0rem !important;\n  border-top: 1.5px solid var(--color-cocotb-blue);\n  margin-top: 1.0rem !important;\n  font-size: 1.1rem !important;\n  font-weight: bold !important;\n}\n\n/* remove horizontal rule when this is the first element belonging to this group of classes */\ndl.py.class:first-of-type dt.sig.sig-object,\ndl.py.exception:first-of-type dt.sig.sig-object,\ndl.py.type:first-of-type dt.sig.sig-object,\ndl.py.data:first-of-type dt.sig.sig-object,\ndl.py.decorator:first-of-type dt.sig.sig-object,\ndl.py.function:first-of-type dt.sig.sig-object {\n  border-top: none;\n}\n\ndl.py.attribute dt.sig.sig-object,\ndl.py.classmethod dt.sig.sig-object,\ndl.py.decoratormethod dt.sig.sig-object,\ndl.py.staticmethod dt.sig.sig-object,\ndl.py.method dt.sig.sig-object,\ndl.py.property dt.sig.sig-object {\n  border-top: none;\n  margin-top: 0 !important;\n  font-size: 1.0rem !important;\n  /* font-weight: normal !important; */\n}\n\ndl.py.attribute dt.sig.sig-object .sig-name,\ndl.py.classmethod dt.sig.sig-object .sig-name,\ndl.py.decoratormethod dt.sig.sig-object .sig-name,\ndl.py.staticmethod dt.sig.sig-object .sig-name,\ndl.py.method dt.sig.sig-object .sig-name,\ndl.py.property dt.sig.sig-object .sig-name {\n  font-size: 1.0rem !important;\n  /* font-weight: normal !important; */\n}\n\n/* remove top margin if preceded by a heading, admonition or version modified */\nh1 + dl.py,\nh2 + dl.py,\nh3 + dl.py,\nh4 + dl.py,\nh5 + dl.py,\nh6 + dl.py,\n.admonition + dl.py,\n.versionadded + dl.py,\n.versionchanged + dl.py,\n.versionremoved + dl.py,\n.deprecated + dl.py {\n  margin-top: 0 !important;\n}\n\ndl[class]:not(.option-list, .field-list, .footnote, .glossary, .simple) {\n  margin-bottom: 0.5rem !important;\n}\n\n/* apidoc \"[source]\" link */\nspan.viewcode-link {\n    font-weight: normal !important;\n    font-size: 0.875rem !important;\n}\n\n/* apidoc \"Parameters:\", \"Returns:\" etc. */\ndl.field-list > dt {\n    background-color: white !important;\n    padding-left: 0px !important;\n}\n\ndl.field-list > dd {\n    padding-left: 0px !important;\n}\n\n/* highlighted code */\n.highlight .hll,\ndt:target,\nspan.highlighted {\n    background-color: var(--color-cocotb-yellow) !important;\n}\n\ndiv.code-block-caption span.caption-text {\n    font-style: italic;\n}\n\n/* search bar */\n.bd-search,\n.search-button-field {\n    border-radius: unset !important;\n}\n\ncode.download {\n    font-weight: normal !important;\n}\n\nimg {\n    margin-top: 1.15rem !important;\n    margin-bottom: 1.15rem !important;\n}\n\n/* make left and right TOCs a bit tighter */\nnav.bd-links li > a,\n.toc-entry a.nav-link {\n    padding-top: 0.175rem !important;\n    padding-bottom: 0.175rem !important;\n}\n\n/* disable dark mode button (https://github.com/executablebooks/sphinx-book-theme/issues/750) */\nbutton.theme-switch-button {\n    display: none !important;\n}\n\n/*\n\"Usage:\" etc. sections in docstrings\n\nThis handles any sections that are *not* listed in\nhttps://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html#docstring-sections\n\nSections that *are* listed in there likely have a different behaviour,\ne.g. the documented \"Example(s):\" leads to a '.. rubric::'\n(or an .. admonition::' if 'napoleon_use_admonition_for_examples = True').\n\nSuch a rubric could be handled with code like the following,\nbut it is likely not selecting all elements that it should\nand might mis-select elements that should be left alone.\n\n//// \"dl and any subsequent siblings (but not .versionchanged etc.)\" - for \"Examples\" in apidoc\n// dl.field-list.simple ~ *:not(.versionadded):not(.versionchanged):not(.deprecated):not(.versionremoved) {\n//     margin-left: 2.5rem;\n// }\n//\n//\n//// \"dl and next p.rubric sibling...\" - \"Examples:\" in apidoc\n// dl.field-list.simple + p.rubric {\n//     font-weight: bold;\n//     margin-left: 0.5rem !important;\n//     border-bottom: unset !important;\n// }\n*/\ndl > dd > dl:not(.field-list.simple) {\n    margin-left: 0rem !important;\n}\n\n/* fix for extra linebreak in apidoc (https://github.com/pydata/pydata-sphinx-theme/issues/2098) */\nsimple li p:first-child, .simple dd p:first-child {\n    display: inline;\n}\n.simple li p:first-child + p, .simple dd p:first-child + p {\n    display: inline;\n}\n.simple li p + p + p, .simple dd p + p + p {\n    display: block;\n}\n\n/* add space between consecutive paragraphs */\np + p {\n    margin-top: 0.5rem !important;\n}\n\n/* reduce distance after paragraphs a bit */\np {\n    margin-bottom: 0.5rem !important;\n}\n\n\n/* reduce big bottom margin in apidoc */\n/*\n// original from pydata-sphinx-theme:\ndl[class]:not(.option-list, .field-list, .footnote, .glossary, .simple) {\n    margin-bottom: 3rem;\n}\n*/\ndl.py.attribute,\ndl.py.class,\ndl.py.classmethod,\ndl.py.data,\ndl.py.decorator,\ndl.py.decoratormethod,\ndl.py.exception,\ndl.py.function,\ndl.py.method,\ndl.py.property,\ndl.py.staticmethod,\ndl.py.type {\n    margin-bottom: 1rem;\n}\n\n/* dl.cpp.macro seems to be defined in breathe */\ndl.cpp.class,\ndl.cpp.concept,\ndl.cpp.enum,\ndl.cpp.enum-class,\ndl.cpp.enum-struct,\ndl.cpp.function,\ndl.cpp.member,\ndl.cpp.struct,\ndl.cpp.type,\ndl.cpp.union,\ndl.cpp.var,\ndl.cpp.macro {\n    margin-bottom: 1rem !important;\n}\n\ndl.cpp.enumerator {\n    margin-bottom: 0.25rem;\n}\n\n/*\nMake autolinks to reference documentation less prominent\n(https://sphinx-codeautolink.readthedocs.io/en/latest/examples.html#custom-link-styles)\n*/\n.sphinx-codeautolink-a {\n    text-decoration-style: solid !important;\n    text-decoration-color: #aaa;\n}\n.sphinx-codeautolink-a:hover {\n    text-decoration-color: black;\n}\n\n/*\nClasses that are manually set (using :class:)\non e.g. .. code-block:: in the \"Upgrading to cocotb 2.0\" section\n*/\n.removed.highlight-python {\n    border-left: 0.2rem solid;\n    border-color: var(--color-cocotb-red);\n}\n\n.deprecated.highlight-python {\n    border-left: 0.2rem solid;\n    border-color: var(--color-cocotb-yellow);\n}\n\n.new.highlight-python {\n    border-left: 0.2rem solid;\n    border-color: var(--color-cocotb-green);\n}\n\n/* A manually inserted horizontal rule */\nhr.docutils {\n    border: 0;\n    border-top: 1.5px solid var(--color-cocotb-blue);\n    margin: 1.5rem 0;\n    opacity: 1.0;\n}\n\n/* Add badges for links that point to docs of specific cocotb versions */\na[href*=\"docs.cocotb.org\"]::after {\n    background-color: white;\n    color: var(--color-cocotb-blue);\n    border: 1px solid;\n    border-radius: 4px;\n    font-size: 0.6rem;\n    font-weight: bold;\n    padding: 0px 3px;\n    margin-left: 0.1rem;\n    vertical-align: super;\n    display: inline-block;\n    text-decoration: none;\n}\n\na[href*=\"docs.cocotb.org\"][href*=\"v2.0\"]::after {\n    content: \"v2.0\";\n}\na[href*=\"docs.cocotb.org\"][href*=\"v1.9\"]::after {\n    content: \"v1.9\";\n}\na[href*=\"docs.cocotb.org\"][href*=\"v1.8\"]::after {\n    content: \"v1.8\";\n}\na[href*=\"docs.cocotb.org\"][href*=\"v1.7\"]::after {\n    content: \"v1.7\";\n}\na[href*=\"docs.cocotb.org\"][href*=\"v1.6\"]::after {\n    content: \"v1.6\";\n}\na[href*=\"docs.cocotb.org\"][href*=\"v1.5\"]::after {\n    content: \"v1.5\";\n}\na[href*=\"docs.cocotb.org\"][href*=\"v1.4\"]::after {\n    content: \"v1.4\";\n}\na[href*=\"docs.cocotb.org\"][href*=\"v1.3\"]::after {\n    content: \"v1.3\";\n}\na[href*=\"docs.cocotb.org\"][href*=\"v1.2\"]::after {\n    content: \"v1.2\";\n}\na[href*=\"docs.cocotb.org\"][href*=\"v1.1\"]::after {\n    content: \"v1.1\";\n}\n\n\n/*\nSticky headings for Release Notes only (where we know the heading text spans only one line).\nThe \"release-notes\" class on \"body\" is dynamically set in cocotb.js\n*/\nbody.release-notes h1,\nbody.release-notes h2,\nbody.release-notes h3 {\n  position: sticky;\n  /* top: 48px; */\n  height: 48px;\n  display: flex;\n  align-items: center;\n  background-color: var(--pst-color-background);\n}\n\nbody.release-notes h1 {\n  top: calc(1 * 48px);\n  z-index: 990;\n}\n\nbody.release-notes h2 {\n  top: calc(2 * 48px);\n  z-index: 980;\n}\n\nbody.release-notes h3 {\n  top: calc(3 * 48px);\n  z-index: 970;\n}\n\n\ncode.literal {\n  border: none;\n  background-color: unset;\n  padding: 0;\n}\n\n\n/* add text \"envvar\" before environment variable definitions */\ndl.std.envvar > dt::before {\n    content: \"envvar \";\n    color: var(--color-cocotb-blue);\n    font-style: italic;\n}\n\ndl.std.envvar > dt {\n    margin-top: 1.5rem;\n}\n\n/* Make sure typewriter text has the same font size as the surrounding headings */\nh1 .pre,\nh2 .pre,\nh3 .pre,\nh4 .pre,\nh5 .pre,\nh6 .pre,\nh1 code,\nh2 code,\nh3 code,\nh4 code,\nh5 code,\nh6 code {\n    font-size: inherit;\n}\n"
  },
  {
    "path": "docs/source/_static/cocotb.js",
    "content": "document.addEventListener(\"DOMContentLoaded\", function () {\n    if (window.location.href.includes(\"release_notes\")) {\n        document.body.classList.add(\"release-notes\");\n    }\n});\n"
  },
  {
    "path": "docs/source/analog_model.rst",
    "content": ".. _analog_model:\n\n#########################\nModels of Analog Circuits\n#########################\n\n.. versionadded:: 1.6\n\nThis is the example :mod:`analog_model` showing how to use Python models\nfor analog circuits together with a digital part.\nFor an FPGA, these analog circuits would be implemented off-chip,\nwhile for an ASIC, they would usually co-exist with the digital part on the same die.\n\nThe Python model consists of an Analog Front-End (AFE) in file :file:`afe.py` containing\na Programmable Gain Amplifier (PGA) with a selectable gain of ``5.0`` and ``10.0``,\nand a 13-bit Analog-to-Digital Converter (ADC) with a reference voltage of ``2.0 V``.\nThese analog models hand over data via a blocking :class:`cocotb.queue.Queue`.\n\nThe digital part (in :file:`digital.sv`)\nmonitors the measurement value converted by the ADC\nand selects the gain of the PGA based on the received value.\n\nA test :file:`test_analog_model.py` exercises these submodules.\n\nWhen running the example, you will get the following output:\n\n.. code-block:: none\n\n        0.00ns INFO     ...test_analog_model.0x7ff913700490       decorators.py:313  in _advance                        Starting test: \"test_analog_model\"\n                                                                                                                        Description: Exercise an Analog Front-end and its digital controller.\n     1001.00ns INFO     cocotb.digital                     test_analog_model.py:55   in test_analog_model               AFE converted input value 0.1V to 2047\n     3000.00ns (digital) HDL got meas_val=2047 (0x07ff)\n     3000.00ns (digital) PGA gain select was 0 --> calculated AFE input value back to 0.099963\n     3000.00ns (digital) Measurement value is less than 30% of max, switching PGA gain from 5.0 to 10.0\n     7301.00ns INFO     cocotb.digital                     test_analog_model.py:55   in test_analog_model               AFE converted input value 0.1V to 4095\n     9000.00ns (digital) HDL got meas_val=4095 (0x0fff)\n     9000.00ns (digital) PGA gain select was 1 --> calculated AFE input value back to 0.099988\n    13301.00ns INFO     cocotb.digital                     test_analog_model.py:55   in test_analog_model               AFE converted input value 0.0V to 0\n    15000.00ns (digital) HDL got meas_val=0 (0x0000)\n    15000.00ns (digital) PGA gain select was 1 --> calculated AFE input value back to 0.000000\n   Saturating measurement value 10238 to [0:8191]!\n    19301.00ns INFO     cocotb.digital                     test_analog_model.py:55   in test_analog_model               AFE converted input value 0.25V to 8191\n    21000.00ns (digital) HDL got meas_val=8191 (0x1fff)\n    21000.00ns (digital) PGA gain select was 1 --> calculated AFE input value back to 0.200000\n    21000.00ns (digital) Measurement value is more than 70% of max, switching PGA gain from 10.0 to 5.0\n    25301.00ns INFO     cocotb.digital                     test_analog_model.py:55   in test_analog_model               AFE converted input value 0.25V to 5119\n    27000.00ns (digital) HDL got meas_val=5119 (0x13ff)\n    27000.00ns (digital) PGA gain select was 0 --> calculated AFE input value back to 0.249982\n    30301.00ns INFO     cocotb.regression                         regression.py:364  in _score_test                     Test Passed: test_analog_model\n\n\nYou can view the source code of the example by clicking the file names below.\n\n.. dropdown:: :file:`afe.py`\n   :icon: file\n\n   .. literalinclude:: ../../examples/analog_model/afe.py\n      :language: python\n\n.. dropdown:: :file:`digital.sv`\n   :icon: file\n\n   .. literalinclude:: ../../examples/analog_model/digital.sv\n      :language: systemverilog\n\n.. dropdown:: :file:`test_analog_model.py`\n   :icon: file\n\n   .. literalinclude:: ../../examples/analog_model/test_analog_model.py\n      :language: python\n\n.. dropdown:: :file:`Makefile`\n   :icon: file\n\n   .. literalinclude:: ../../examples/analog_model/Makefile\n      :language: make\n"
  },
  {
    "path": "docs/source/building.rst",
    "content": ".. _building:\n\n*******************************************\nMakefile-based Build System and Test Runner\n*******************************************\n\ncocotb has traditionally provided a Makefile-based design build system and test runner.\nThe build system should be *sufficient*, but may not be easy to use for more serious projects.\n\nMakefiles are provided for a variety of simulators in :file:`src/cocotb-tools/makefiles/simulators`.\n\nThe common Makefile :file:`src/cocotb-tools/makefiles/Makefile.sim` includes the appropriate simulator Makefile based on the contents of the :make:var:`SIM` variable.\n\nMake Targets\n============\n\nMakefiles defines the targets ``regression`` and ``sim``, the default target is ``sim``.\n\nBoth rules create a results file with the name taken from :envvar:`COCOTB_RESULTS_FILE`, defaulting to ``results.xml``.\nThis file is a xUnit-compatible output file suitable for use with e.g. `Jenkins <https://jenkins.io/>`_.\nThe ``sim`` targets unconditionally re-runs the simulator whereas the ``regression`` target only re-builds if any dependencies have changed.\n\nIn addition, the target ``clean`` can be used to remove build and simulation artifacts.\nThe target ``help`` lists these available targets and the variables described below.\n\nMake Phases\n===========\n\nTypically the makefiles provided with cocotb for various simulators use a separate ``compile`` and ``run`` target.\nThis allows for a rapid re-running of a simulator if none of the :term:`RTL` source files have changed and therefore the simulator does not need to recompile the RTL.\n\nMake Variables\n==============\n\n..\n  If you edit the following sections, please also update the \"helpmsg\" text in src/cocotb_tools/config.py\n\n.. make:var:: GUI\n\n      Set this to 1 to enable the GUI mode in the simulator (if supported).\n\n.. make:var:: SIM\n\n      Set this to the desired value from :ref:`Supported Simulators <simulator-support>`.\n\n      In the makefile flow, selects which simulator Makefile to use.\n      Attempts to include a simulator specific makefile from :file:`src/cocotb/share/makefiles/simulators/makefile.$(SIM)`\n\n      In the :ref:`Python Runner <howto-python-runner>` flow,\n      selects the :ref:`Simulator Runner <api-runner-sim>` to use.\n\n.. make:var:: WAVES\n\n      Set this to 1 to enable wave traces dump for the Aldec Riviera-PRO, Mentor Graphics Questa, and Icarus Verilog simulators.\n      To get wave traces in Verilator see :ref:`sim-verilator-waveforms`.\n\n.. make:var:: TOPLEVEL_LANG\n\n    Used to inform the makefile scripts which :term:`HDL` language the top-level design element is written in.\n    Currently it supports the values ``verilog`` for Verilog or SystemVerilog toplevels, and ``vhdl`` for VHDL toplevels.\n    This is used by simulators that support more than one interface (:term:`VPI`, :term:`VHPI`, or :term:`FLI`) to select the appropriate interface to start cocotb.\n\n.. make:var:: VHDL_GPI_INTERFACE\n\n    Explicitly sets the simulator interface to use when :make:var:`TOPLEVEL_LANG` is ``vhdl``.\n    This includes the initial GPI interface loaded, and :envvar:`GPI_EXTRA` library loaded in mixed language simulations.\n    Valid values are ``vpi``, ``vhpi``, or ``fli``.\n    Not all simulators support all values; refer to the :ref:`simulator-support` section for details.\n\n    Setting this variable is rarely needed as cocotb chooses a suitable default value depending on the simulator used.\n\n.. make:var:: VERILOG_SOURCES\n\n      A list of the Verilog source files to include.\n      Paths can be absolute or relative; if relative, they are interpreted as relative to the location where ``make`` was invoked.\n\n.. make:var:: VERILOG_INCLUDE_DIRS\n\n      A list of the Verilog directories to search for include files.\n      Paths can be absolute or relative; if relative, they are interpreted as relative to the location where ``make`` was invoked.\n\n.. make:var:: VHDL_SOURCES\n\n      A list of the VHDL source files to include.\n      Paths can be absolute or relative; if relative, they are interpreted as relative to the location where ``make`` was invoked.\n\n.. make:var:: VHDL_SOURCES_<lib>\n\n      A list of the VHDL source files to include in the VHDL library *lib* (currently for GHDL/ModelSim/Questa/Xcelium/Incisive/Riviera-PRO only).\n\n.. make:var:: VHDL_LIB_ORDER\n\n      A space-separated list defining the order in which VHDL libraries should be compiled (needed for ModelSim/Questa/Xcelium/Incisive, GHDL determines the order automatically).\n\n.. make:var:: COMPILE_ARGS\n\n      Any arguments or flags to pass to the compile (analysis) stage of the simulation.\n\n.. make:var:: SIM_ARGS\n\n      Any arguments or flags to pass to the execution of the compiled simulation.\n\n.. make:var:: RUN_ARGS\n\n      Any argument to be passed to the \"first\" invocation of a simulator that runs via a TCL script.\n      One motivating usage is to pass ``-noautoldlibpath`` to Questa to prevent it from loading the out-of-date libraries it ships with.\n      Used by the Riviera-PRO and Questa simulators.\n\n.. make:var:: EXTRA_ARGS\n\n      Passed to both the compile and execute phases of simulators with two rules, or passed to the single compile and run command for simulators which don't have a distinct compilation stage.\n\n.. make:var:: COCOTB_HDL_TIMEUNIT\n\n      The default time unit that should be assumed for simulation when not specified by modules in the design.\n      If this isn't specified then it is assumed to be ``1ns``.\n      Allowed values are 1, 10, and 100.\n      Allowed units are ``s``, ``ms``, ``us``, ``ns``, ``ps``, ``fs``.\n\n      .. versionadded:: 1.3\n\n.. make:var:: COCOTB_HDL_TIMEPRECISION\n\n      The default time precision that should be assumed for simulation when not specified by modules in the design.\n      If this isn't specified then it is assumed to be ``1ps``.\n      Allowed values are 1, 10, and 100.\n      Allowed units are ``s``, ``ms``, ``us``, ``ns``, ``ps``, ``fs``.\n\n      .. versionadded:: 1.3\n\n.. make:var:: CUSTOM_COMPILE_DEPS\n\n      Use to add additional dependencies to the compilation target; useful for defining additional rules to run pre-compilation or if the compilation phase depends on files other than the :term:`RTL` sources listed in :make:var:`VERILOG_SOURCES` or :make:var:`VHDL_SOURCES`.\n\n.. make:var:: CUSTOM_SIM_DEPS\n\n      Use to add additional dependencies to the simulation target.\n\n.. make:var:: SIM_BUILD\n\n      Use to define a scratch directory for use by the simulator. The path is relative to the location where ``make`` was invoked.\n      If not provided, the default scratch directory is :file:`sim_build`.\n\n.. make:var:: SCRIPT_FILE\n\n    The name of a simulator script that is run as part of the simulation, e.g. for setting up wave traces.\n    You can usually write out such a file from the simulator's GUI.\n    This is currently supported for the Mentor Questa, Mentor ModelSim and Aldec Riviera simulators.\n\n.. make:var:: TOPLEVEL_LIBRARY\n\n    The name of the library that contains the :envvar:`COCOTB_TOPLEVEL` module/entity.\n    Only supported by the Aldec Riviera-PRO, Aldec Active-HDL, and Siemens EDA Questa simulators.\n\n.. make:var:: PYTHON_BIN\n\n    The path to the Python binary.\n    Set to the result of ``cocotb-config --python-bin`` if ``cocotb-config`` is present on the ``PATH``.\n    Otherwise defaults to ``python3``.\n\n.. make:var:: LIBPYTHON_LOC\n\n    The absolute path to the Python library associated with the current Python installation;\n    i.e. ``libpython.so`` or ``python.dll`` on Windows.\n    This is determined with ``cocotb-config --libpython`` during build.\n\n    This is only used if :envvar:`GPI_USERS` is not already defined by the user.\n\nThe :envvar:`COCOTB_TOPLEVEL` variable is also often used by the Makefile-based build and runner system.\n\nThe :envvar:`SIM_CMD_PREFIX` and :envvar:`SIM_CMD_SUFFIX` environment variables are also supported by the Makefile-based build and runner system.\n"
  },
  {
    "path": "docs/source/conf.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# cocotb documentation build configuration file\n#\n# This file is execfile()d with the current directory set to its containing dir.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\nimport datetime\nimport os\nimport subprocess\nimport sys\nimport textwrap\n\n# Add in-tree extensions to path\nsys.path.insert(0, os.path.abspath(\"../sphinxext\"))\n\nimport cocotb\nfrom cocotb_tools._vendor.distutils_version import LooseVersion\n\nos.environ[\"SPHINX_BUILD\"] = \"1\"\n\n# -- General configuration -----------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n# needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be extensions\n# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.\nextensions = [\n    \"sphinx.ext.autodoc\",\n    \"sphinx.ext.doctest\",\n    \"sphinx.ext.todo\",\n    \"sphinx.ext.coverage\",\n    \"sphinx.ext.imgmath\",\n    \"sphinx.ext.viewcode\",\n    \"sphinx.ext.napoleon\",\n    \"sphinx.ext.extlinks\",\n    \"sphinx.ext.intersphinx\",\n    \"sphinxcontrib.makedomain\",\n    \"sphinx.ext.inheritance_diagram\",\n    \"sphinxcontrib.cairosvgconverter\",\n    \"breathe\",\n    \"sphinx_issues\",\n    \"sphinx_argparse_cli\",\n    \"sphinxcontrib.spelling\",\n    \"sphinx_design\",\n    \"enum_tools.autoenum\",\n    \"sphinx_codeautolink\",\n    \"sphinxarg.ext\",\n    \"sphinx_autofixture\",\n]\n\nintersphinx_mapping = {\n    \"python\": (\"https://docs.python.org/3\", None),\n    \"ghdl\": (\"https://ghdl.github.io/ghdl\", None),\n    \"scapy\": (\"https://scapy.readthedocs.io/en/latest\", None),\n    \"pytest\": (\"https://docs.pytest.org/en/latest/\", None),\n    \"coverage\": (\"https://coverage.readthedocs.io/en/latest/\", None),\n    \"remote_pdb\": (\"https://python-remote-pdb.readthedocs.io/en/latest/\", None),\n    \"cocotb20\": (\"https://docs.cocotb.org/en/v2.0.1/\", None),\n    \"cocotb19\": (\"https://docs.cocotb.org/en/v1.9.2/\", None),\n    \"cocotb18\": (\"https://docs.cocotb.org/en/v1.8.1/\", None),\n    \"cocotb17\": (\"https://docs.cocotb.org/en/v1.7.2/\", None),\n    \"cocotb16\": (\"https://docs.cocotb.org/en/v1.6.2/\", None),\n    \"cocotb15\": (\"https://docs.cocotb.org/en/v1.5.2/\", None),\n    \"cocotb14\": (\"https://docs.cocotb.org/en/v1.4.0/\", None),\n    \"cocotb13\": (\"https://docs.cocotb.org/en/v1.3.1/\", None),\n    \"cocotb12\": (\"https://docs.cocotb.org/en/v1.2.0/\", None),\n    \"cocotb11\": (\"https://docs.cocotb.org/en/v1.1/\", None),\n}\n\n# Github repo\nissues_github_path = \"cocotb/cocotb\"\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = [\"_templates\"]\n\n# The suffix of source filenames.\nsource_suffix = {\n    '.rst': 'restructuredtext'\n}\n\n# The master toctree document.\nmaster_doc = \"index\"\n\n# General information about the project.\nproject = \"cocotb\"\nauthor = \"\"  # prevent printing extra \"By {author}\" above copyright line in HTML footer\nyears = f\"2014-{datetime.datetime.now().year}\"\ncopyright = f\"{years}, cocotb contributors\"\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The full version, including alpha/beta/rc tags.\nrelease = cocotb.__version__\n# The short X.Y version.\nv_major, v_minor = LooseVersion(release).version[:2]\nversion = \"{}.{}\".format(v_major, v_minor)\n# cocotb commit ID\ntry:\n    commit_id = (\n        subprocess.check_output([\"git\", \"rev-parse\", \"HEAD\"]).strip().decode(\"ascii\")\n    )\nexcept subprocess.CalledProcessError:\n    commit_id = \"master\"\n\n# Is this documentation build a ReadTheDocs build for a git tag, i.e., a\n# release? Set the 'is_release_build' tag then, which can be used by the\n# '.. only::' directive.\n# https://docs.readthedocs.io/en/stable/reference/environment-variables.html\nis_rtd_tag = 'READTHEDOCS' in os.environ and os.environ.get('READTHEDOCS_VERSION_TYPE', 'unknown') == 'tag'\n\nif is_rtd_tag:\n    tags.add('is_release_build')\n\nautoclass_content = \"class\"\n\nautodoc_typehints = \"signature\"  # show type hints in the list of parameters\nautodoc_typehints_description_target = \"documented\"\nmaximum_signature_line_length = 78\n\n# use short \"a | b\" syntax for Literal types\npython_display_short_literal_types = True\n\n# Options for automatic links from code examples to reference docs\n# (https://sphinx-codeautolink.readthedocs.io/)\ncodeautolink_warn_on_missing_inventory = True\ncodeautolink_warn_on_failed_resolve = True\ncodeautolink_autodoc_inject = True  # Inject an autolink-examples table to the end of all autodoc definitions\n# import statements that are often used in code examples\ncodeautolink_global_preface = textwrap.dedent(\"\"\"\\\n    import random\n    import cocotb\n    from cocotb.clock import *\n    from cocotb.handle import *\n    from cocotb.logging import *\n    from cocotb.queue import *\n    from cocotb.regression import *\n    from cocotb.result import *\n    from cocotb.task import *\n    from cocotb.triggers import *\n    from cocotb.utils import *\n    \"\"\"\n)\n\ncodeautolink_custom_blocks = {\n    # https://sphinx-codeautolink.readthedocs.io/en/latest/examples.html#doctest-code-blocks\n    \"pycon\": \"sphinx_codeautolink.clean_pycon\",\n}\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n# language = None\n\n# There are two options for replacing |today|: either, you set today to some\n# non-false value, then it is used:\n# today = ''\n# Else, today_fmt is used as the format for a strftime call.\n# today_fmt = '%B %d, %Y'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\nexclude_patterns = [\n    # these are compiled into a single file at build-time,\n    # so there is no need to build them separately:\n    \"newsfragments/*.rst\",\n    # unused outputs from breathe:\n    \"generated/namespacelist.rst\",\n    \"generated/namespace/*.rst\",\n]\n\n# The reST default role (used for this markup: `text`) to use for all documents.\n# default_role = None\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\n# add_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\n# add_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\n# show_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = \"sphinx\"\n\n# A list of ignored prefixes for module index sorting.\n# modindex_common_prefix = []\n\n# If true, keep warnings as \"system message\" paragraphs in the built documents.\n# keep_warnings = False\n\n\n# -- Options for HTML output ---------------------------------------------------\n\n# We are using https://github.com/executablebooks/sphinx-book-theme\n# Install with ``pip install sphinx-book-theme``\nhtml_theme = \"sphinx_book_theme\"\n\n# A dictionary of values to pass into the template engine’s context for all pages.\n# https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/light-dark.html#configure-default-theme-mode\nhtml_context = {\n    \"default_mode\": \"light\",\n}\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\nhtml_theme_options = {\n    \"logo\": {\n        \"image_light\": \"_static/cocotb-logo.svg\",\n        \"image_dark\": \"_static/cocotb-logo-dark.svg\",\n        \"link\": \"https://cocotb.org\",\n    },\n    # https://pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/version-dropdown.html\n    # https://pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/readthedocs.html#version-switcher\n    # \"switcher\": {\n    #     \"json_url\": f\"<...>/switcher.json\",\n    #     \"version_match\": ...,\n    #     \"check_switcher\": False,\n    #     \"show_version_warning_banner\": True,\n    # },\n    \"repository_provider\": \"github\",  # \"gitlab\", \"github\", \"bitbucket\"\n    \"repository_url\": \"https://github.com/cocotb/cocotb\",\n    \"use_repository_button\": True,\n    # \"use_edit_page_button\": True,\n    \"use_issues_button\": True,\n    # \"use_fullscreen_button\": False,\n    \"home_page_in_toc\": True,\n    # \"primary_sidebar_end\": [\"indices.html\"],\n}\n\n# Add any paths that contain custom themes here, relative to this directory.\n# html_theme_path = []\n\n# The name for this set of Sphinx documents.  If None, it defaults to\n# \"<project> v<release> documentation\".\n# html_title = None\n\n# A shorter title for the navigation bar.  Default is the same as html_title.\n# html_short_title = None\n\n# If given, this must be the name of an image file (path relative to the configuration directory)\n# that is the favicon of the documentation, or a URL that points an image file for the favicon.\n# Browsers use this as the icon for tabs, windows and bookmarks.\n# It should be a 16-by-16 pixel icon in the PNG, SVG, GIF, or ICO file formats.\nhtml_favicon = \"_static/cocotb-favicon.svg\"\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = ['_static']\nhtml_css_files = [\"cocotb.css\"]\nhtml_js_files = [\"cocotb.js\"]\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,\n# using the given strftime format.\n# html_last_updated_fmt = '%b %d, %Y'\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n# html_use_smartypants = True\n\n# Custom sidebar templates, maps document names to template names.\n# html_sidebars = {}\n\n# Additional templates that should be rendered to pages, maps page names to\n# template names.\n# html_additional_pages = {}\n\n# If false, no module index is generated.\n# html_domain_indices = True\n\n# If false, no index is generated.\n# html_use_index = True\n\n# If true, the index is split into individual pages for each letter.\n# html_split_index = False\n\n# If true, links to the reST sources are added to the pages.\n# html_show_sourcelink = True\n\n# If true, \"Created using Sphinx\" is shown in the HTML footer. Default is True.\n# html_show_sphinx = True\n\n# If true, \"(C) Copyright ...\" is shown in the HTML footer. Default is True.\n# html_show_copyright = True\n\n# If true, an OpenSearch description file will be output, and all pages will\n# contain a <link> tag referring to it.  The value of this option must be the\n# base URL from which the finished HTML is served.\n# html_use_opensearch = ''\n\n# This is the file name suffix for HTML files (e.g. \".xhtml\").\n# html_file_suffix = None\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = \"cocotbdoc\"\n\n\n# -- Options for LaTeX output --------------------------------------------------\n\nlatex_elements = {\n    # The paper size ('letterpaper' or 'a4paper').\n    #'papersize': 'letterpaper',\n    # The font size ('10pt', '11pt' or '12pt').\n    #'pointsize': '10pt',\n    # Additional stuff for the LaTeX preamble.\n    #'preamble': '',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title, author, documentclass [howto/manual]).\nlatex_documents = [\n    (\"index\", \"cocotb.tex\", \"cocotb Documentation\", \"cocotb contributors\", \"manual\"),\n]\n\n# The name of an image file (relative to this directory) to place at the top of\n# the title page.\n# latex_logo = None\n\n# For \"manual\" documents, if this is true, then toplevel headings are parts,\n# not chapters.\n# latex_use_parts = False\n\n# If true, show page references after internal links.\n# latex_show_pagerefs = False\n\n# If true, show URL addresses after external links.\n# latex_show_urls = False\n\n# Documents to append as an appendix to all manuals.\n# latex_appendices = []\n\n# If false, no module index is generated.\n# latex_domain_indices = True\n\n\n# -- Options for manual page output --------------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [(\"index\", \"cocotb\", \"cocotb Documentation\", [\"cocotb contributors\"], 1)]\n\n# If true, show URL addresses after external links.\n# man_show_urls = False\n\n\n# -- Options for Texinfo output ------------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n    (\n        \"index\",\n        \"cocotb\",\n        \"cocotb Documentation\",\n        \"cocotb contributors\",\n        \"cocotb\",\n        \"Coroutine Cosimulation TestBench \\\n     environment for efficient verification of RTL using Python.\",\n        \"Miscellaneous\",\n    ),\n]\n\n# Documents to append as an appendix to all manuals.\n# texinfo_appendices = []\n\n# If false, no module index is generated.\n# texinfo_domain_indices = True\n\n# How to display URL addresses: 'footnote', 'no', or 'inline'.\n# texinfo_show_urls = 'footnote'\n\n# If true, do not generate a @detailmenu in the \"Top\" node's menu.\n# texinfo_no_detailmenu = False\n\ntodo_include_todos = False\n\n# -- Extra setup for C documentation with Doxygen and breathe ------------------\n# see also https://breathe.readthedocs.io/en/latest/readthedocs.html\nsubprocess.run(\"doxygen\", cwd=\"..\")\n\ncpp_id_attributes = [\"GPI_EXPORT\"]\nbreathe_projects = {\"cocotb\": \"doxygen/_xml\"}\nbreathe_default_project = \"cocotb\"\nbreathe_domain_by_extension = {\n    \"h\": \"cpp\",\n}\nbreathe_show_define_initializer = True\n\n# -- Extra setup for spelling check --------------------------------------------\n\n# Spelling language.\nspelling_lang = \"en_US\"\ntokenizer_lang = spelling_lang\n\n# Location of word list.\nspelling_word_list_filename = [\"spelling_wordlist.txt\"]\nspelling_exclude_patterns = [\"generated/**\", \"master-notes.rst\"]\n\nspelling_ignore_pypi_package_names = False\nspelling_ignore_wiki_words = False\nspelling_show_suggestions = True\nspelling_ignore_acronyms = True\n\n# -- Extra setup for inheritance_diagram directive which uses graphviz ---------\n\ngraphviz_output_format = \"svg\"\n\n# -- Extra setup for towncrier -------------------------------------------------\n# see also https://towncrier.readthedocs.io/en/actual-freaking-docs/\n\n# we pass the name and version directly, to avoid towncrier failing to import the non-installed version\nin_progress_notes = subprocess.check_output(\n    [\"towncrier\", \"--draft\", \"--name\", \"cocotb\", \"--version\", release],\n    cwd=\"../..\",\n    universal_newlines=True,\n)\nwith open(\"master-notes.rst\", \"w\") as f:\n    f.write(in_progress_notes)\n\n# -- External link helpers -----------------------------------------------------\n\nextlinks = {\n    \"wikipedia\": (\"https://en.wikipedia.org/wiki/%s\", None),\n    \"reposharp\": (\"https://github.com/cocotb/cocotb/issues/%s\", \"#\"),\n    \"reposrc\": (\n        f\"https://github.com/cocotb/cocotb/blob/{commit_id}/%s\",\n        None,\n    ),\n}\n\n# -- intersphinx missing-reference interception --------------------------------\nfrom sphinx.errors import NoUri\nfrom sphinx.util.logging import getLogger\n\ndef block_gpi_links(app, env, node, contnode):\n    target = node.get('reftarget', '')\n\n    # Stop intersphinx from linking to old GPI docs\n    if target in ('GpiObjHdl', 'GpiIterator', 'GpiCbHdl'):\n        getLogger(\"cocotb.conf\").info(f\"Stopping intersphinx link for {target}\")\n        raise NoUri\n\n# -- Custom setup function -----------------------------------------------------\ndef setup(app):\n    app.connect('missing-reference', block_gpi_links)\n"
  },
  {
    "path": "docs/source/contributing.rst",
    "content": "****************\nGetting Involved\n****************\n\nWelcome to the cocotb development!\nWe are an inclusive community with the common goal of improving the cocotb, a coroutine based cosimulation library for writing VHDL and Verilog testbenches in Python.\nThis guide explains how to contribute to cocotb, and documents the processes we agreed on to manage the project.\nAll processes in this document are designed to streamline the development effort, to avoid bottlenecks, and to ultimately give a pleasant experience to all involved.\n\nFeeling lost?\n=============\n\ncocotb is a diverse and challenging project to contribute to.\nIf you ever feel lost, out of your depth, or simply want to know more, the `cocotb Gitter channel <https://gitter.im/cocotb/Lobby>`__ is actively watched by many cocotb users, contributors, and maintainers.\nIt is a good idea if you are unsure whether your problem or question is worthy of a Github Issue to first post it to the Gitter channel.\nYou may also ask questions in `Github issues <https://github.com/cocotb/cocotb/issues>`_.\nIf you don't receive any response on the Gitter channel or a Github issue, or you want help privately, you may directly contact a maintainer.\n\nArchitecture and Scope of cocotb\n================================\n\ncocotb has seen adoption in a wide variety of scenarios with sometimes conflicting requirements.\nTo foster experimentation and to decentralize the development process the architecture of cocotb is highly modular.\nA solid core forms the foundation upon which extensions can provide higher-level functionality.\n\nThe core of cocotb are\n\n- the infrastructure to write testbenches with coroutines, threads, etc.,\n- the abstraction and interaction with simulators through interfaces like VPI, GPI, etc.,\n- tooling to run tests, and\n- core primitives to interact with the simulation: triggers, data access classes, etc.\n\nAs a general rule, functionality beyond this core set should go into extensions.\nHowever, none of these rules are set in stone.\nThey can and should be challenged at times to ensure the project stays relevant to the majority of its users.\n\nWhat to Work On\n===============\n\nThere is *a lot* of work to do on this project, no matter your area of expertise or skill level.\n\nIf you are a beginner there are several `Github issues <https://github.com/cocotb/cocotb/issues>`__ marked `good first issue <https://github.com/cocotb/cocotb/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22>`__ you can look at.\nThere are also a number of things you can work on that aren't in Github issues and don't require in-depth knowledge of the cocotb internals.\nThey including the following:\n\n-  Documentation improvements\n-  Managing Github issues and the Gitter channel\n-  Testing and coverage improvements\n\ncocotb is still not perfect.\nThere are plenty of `bug fixes <https://github.com/cocotb/cocotb/issues?q=is%3Aopen+is%3Aissue+label%3Atype%3Abug>`__ and `features <https://github.com/cocotb/cocotb/issues?q=is%3Aopen+is%3Aissue+label%3Atype%3Afeature>`__ that can be worked on.\nMost of these are recorded as Github issues.\n\nDocumentation\n-------------\n\ncocotb's documentation is always open to improvements.\nImproving documentation will help users better understand and use cocotb;\nand may decrease the number of questions the Gitter channel and Github issue page.\nUpdating documentation requires knowledge of:\n\n-  `reStructuredText <https://docutils.sourceforge.io/rst.html>`__\n-  `Sphinx documentation generator <https://www.sphinx-doc.org/en/master/>`__\n-  `Markdown <https://www.markdownguide.org/>`__\n-  `How to architect documentation <https://documentation.divio.com/>`__\n\nSome documentation should be located in the official documentation on `Read the Docs/RTD <https://docs.cocotb.org/en/development/>`__, while the rest belongs on the `Wiki <https://github.com/cocotb/cocotb/wiki>`__.\nThere are several ways to improve the documentation:\n\n-  Better documenting core functionality (RTD)\n-  Documenting common \"gotchas\" (RTD)\n-  Documenting difficult and niche use cases (Wiki)\n-  Documenting common design patterns (Wiki)\n-  Documenting internal components (Wiki)\n\nSee the documentation on `building the documentation <#building-documentation-locally>`__ and the `guidelines on submitting pull requests <#patch-requirements>`__.\nDocumentation improvements typically require no maintainer pre-approval;\nyou can simply work on the documentation and open a pull request.\nDocumentation on the Wiki does not require a pull request;\nany user with a Github account can contribute to it.\nPlease be responsible with that power.\n\nProject Management\n------------------\n\nThe cocotb project is `fairly popular <https://larsasplund.github.io/github-facts/verification-practices.html#frameworks>`__ and the `Gitter channel <https://gitter.im/cocotb/Lobby>`__ and `Github issues <https://github.com/cocotb/cocotb>`__ page receive a fair amount\nof traffic;\nwhich is only expected to increase.\nPeople are needed to categorize issues and pull requests, and respond to questions.\nWorking this task is the quickest way to learn how cocotb works.\nTending to this task requires the following:\n\n-  people skills\n-  an understanding of the scope of cocotb\n-  general understanding about how cocotb works\n\nSomeone working this task should set notifications on the Gitter channel to be notified of any new comments.\nThey should also \"watch\" the Github repo by selecting the \"Watching\" notification level button in the upper right corner of the main Github page.\nFinally, they should notify the maintainers that they are able and willing to accept questions.\n\nTo be able to add labels and close issues and PRs you will need special permissions.\nContact a `maintainer <#maintainer>`__ if you are interested in receiving these permissions.\nThey will be granted according to the project's need and the requestor's familiarity with cocotb.\nOnce you have those permissions, see the guidelines on `managing issues and pull requests <#Managing-of-Issues-and-Pull-Requests>`__.\n\nThis task can also be done without special repo permissions, by just commenting on the issue or PR. This is especially helpful for Github issues about bugs.\nIf you can duplicate the bug or confirm the bug report is invalid, that helps maintainers *a lot*.\n\nTests and Coverage\n------------------\n\ncocotb has a suite of unit tests (located in the ``tests`` directory) and examples (located in the ``examples`` directory) which are functional acceptance tests.\nIf a pull request cannot pass *all* of these tests, it will likely be rejected.\nTo ensure cocotb only includes the highest quality code, these test should be exhaustive.\nWe use code coverage as a quantifiable metric of the \"exhaustiveness\" of these tests, and wish to improve this metric.\n\nWorking on this task requires a familiarity with:\n\n-  cocotb's core functionality\n-  How to write Verilog and VHDL\n-  How to write cocotb tests in Python\n-  (Optionally) `codecov <https://docs.codecov.io/docs>`__; coverage aggregator and Github bot\n-  (Optionally) the `coverage <https://coverage.readthedocs.io/en/latest/>`__ module, for Python code coverage\n-  (Optionally) `gcov <https://gcc.gnu.org/onlinedocs/gcc/Gcov.html>`__, for C++ code coverage\n-  (Optionally) `Github Actions <https://docs.github.com/en/free-pro-team@latest/actions>`__, for automatic acceptance testing\n\ncocotb's regression tests can be improved by:\n\n-  Testing more of cocotb's core functionality\n-  Testing corner cases left out of the current set of tests (identified by looking at code coverage)\n-  Increasing the matrix of simulators, operating system, and Python installations tested in CI\n\nTesting improvements don't require maintainer pre-approval, but require a pull request.\nPlease see the `guidelines on submitting pull requests <#patch-requirements>`__.\n\nFeatures\n--------\n\ncocotb is still in development and new features are still welcome and appreciated;\nas long as they stay `in scope <#Architecture-and-Scope-of-cocotb>`__.\ncocotb is comprised of several major codebases, each requiring different sets of skills and development process.\nInstead of including that breakdown here, it is done in the `internal documentation <https://github.com/cocotb/cocotb/wiki/cocotb-Internals>`__.\n\nSmall improvements to existing features generally do not require maintainer pre-approval.\nLarge changes, approximately >150 LOC changed, and new features generally require maintainer pre-approval.\nIf a change is deemed too large for the main repo, or out of scope, please feel free to make it an `extension <https://docs.cocotb.org/en/development/extensions.html>`__.\n\n**New features must not break existing features.**\n\nFeature changes require full coverage of the added feature.\nThis likely requires adding new unit tests to the ``tests`` directory.\nIssue-specific test directories will not be accepted, unless a special HDL entity is required. Instead, place the test in an existing test suite (``test_cocotb``, ``test_discovery``, etc.).\n\nFeatures should generally follow the following design principles:\n\n-  Something the user cannot do without assistance of cocotb-specific code\n-  Orthogonal to existing features\n-  Easily composed with existing features\n-  Limited in scope and impervious to scope creep\n\nBugfixes\n--------\n\n.. warning::\n   Bugfixing cocotb is not for the faint of heart!\n\nBugs happen.\ncocotb supports many simulators that have inconsistent support for the procedural interfaces cocotb depends on, and it has a number of features that aren't wholly tested yet.\nThere are likely many bugs lurking, waiting to be found;\nwhich is why increasing testing and code coverage is important.\nWorking on bugfixing can be very challenging, depending on the cause of the bug.\nIn general, bugfixing requires knowledge of:\n\n-  How cocotb works\n-  `cocotb's debugging utilities <https://github.com/cocotb/cocotb/wiki/Debugging-HOW-TOs#cocotb-debugging-functionality>`__\n-  (Optional) Simulator interfaces (VPI, VHPI, and FLI)\n-  (Optional) Python debugging tools (`pdb <https://github.com/cocotb/cocotb/wiki/Debugging-HOW-TOs#using-a-remote-python-debugger>`__, `dowser <https://github.com/cocotb/cocotb/wiki/Debugging-HOW-TOs#debugging-python-memory-usage>`__)\n-  (Optional) C/C++ debugging tools (`gdb <https://github.com/cocotb/cocotb/wiki/Debugging-HOW-TOs#using-a-remote-cc-debugger>`__, `valgrind <https://github.com/cocotb/cocotb/wiki/Debugging-HOW-TOs#debugging-cc-memory-usage>`__)\n-  (Optional) Specific simulators (sometimes the bug exists in the simulator and not cocotb)\n\nFixing a bug follows the procedure:\n\n1. Locate buggy behavior, make a Github issue\n\n   -  Maintainers may be able to offer more information, confirm it as a bug, or confirm it as expected behavior\n\n2. Make a Minimum Reproducible Failing Example (MRFE, pronounced like Murphy, like the law :)\n\n   -  Confirms the bug\n   -  Add to `regressions <#running-tests-locally>`__\n\n3. Open a new draft pull request with the MRFE test\n\n   -  It should cause CI to fail\n\n4. Determine scope of the bug, and add that detail to the pull request\n\n   -  Which simulators/interfaces are affected?\n   -  Which Python versions?\n   -  Which operating systems?\n\n5. Determine the cause of the bug, and add that detail to the pull request\n\n   -  May require Python or C debugging, or the built-in cocotb debugging utilities\n\n6. Make a fix, and push it up on the PR branch\n\n   -  It should cause the CI to pass\n   -  The fix should not break other existing functionality\n\nDetails on how to debug cocotb can be found on the `Wiki <https://github.com/cocotb/cocotb/wiki/Debugging-HOW-TOs>`__.\n\nDeprecations and Removals\n-------------------------\n\ncocotb's treatment of deprecations and removal follows guidelines laid out `here <https://symfony.com/doc/current/setup/upgrade_major.html#1-make-your-code-deprecation-free>`__.\nDeprecations serve the following purposes:\n\n-  Remove legacy code that has been deemed out of scope\n-  Remove support for a simulator, OS, or Python version that is past end-of-life\n-  Remove potentially dangerous, broken, and misunderstood interfaces (usually accompanied with a superior alternative)\n\nDeprecations can be incorporated at any time.\nThey are implemented in Python by issuing a :class:`DeprecationWarning` or using the ``@deprecated`` decorator.\nIn C++ code, deprecations are implemented by `issuing a LOG_WARN <https://docs.cocotb.org/en/stable/generated/file/gpi__logging_8h.html?highlight=LOG_WARN#c.LOG_WARN>`__ with ``DEPRECATED`` in the message.\n\nRemovals only occur on major version bumps.\nOne can create removal pull requests at any time, on the condition they will not be accepted until\nthe next release is known to be a major version release.\n\nBreaking Changes\n----------------\n\nBreaking changes are changes to the interface or behavior of a user-facing entity.\nThey are necessary when a user-facing interfaces are broken in a way that cannot be changed without changing the behavior of user's code.\nIn these situations it is ideal to be able to implement a switch between new better behavior and the old broken behavior.\nOn major version bumps, this switch will be deprecated and the new behavior will become the default.\n\nIn cases where behavioral switches are not easy to implement, breaking changes will attempt to be broadcasted to user by :class:`DeprecationWarning` when the to-be-changed behavior is invoked.\nBefore major releases, pending breaking changes will be incorporated.\n\nOne can create pull requests with breaking changes at any time, on the condition they will not be accepted until the next release is known to be a major version release.\n\n\nHow to Get Changes Merged\n=========================\n\nHave you fixed a bug in cocotb, or want to add new functionality to it?\ncocotb follows the typical `GitHub flow <https://guides.github.com/introduction/flow/>`__ and makes use of pull requests and reviews.\nFollow the steps below to get your changes merged, i.e. integrated into the main cocotb codebase.\n\n1. Create an issue ticket on `cocotb's GitHub issue tracker <https://github.com/cocotb/cocotb/issues>`__ describing the problem.\n   Issues are also a good place to discuss design options with others before writing code.\n2. `Fork <https://help.github.com/articles/fork-a-repo/>`__ the `cocotb GitHub repository <https://github.com/cocotb/cocotb>`__ into your personal namespace.\n3. Create a new branch off the ``master`` branch for your set of changes.\n   Use one branch per \"topic,\" i.e. per set of changes which belong together.\n4. Create one or multiple commits to address the issue.\n   Make sure to read and follow the `Patch Requirements <#patch-requirements>`__ when preparing your commits.\n5. Create new `pull request (PR) <https://github.com/cocotb/cocotb/pulls>`__.\n6. When you submit (or update) the pull request, a suite of regression tests will run.\n   If any of them turns \"red,\" i.e. reports a failure, you most likely need to fix your code before it can be merged.\n7. The pull request needs to be reviewed by at least one of the :ref:`maintainers`.\n   We aim to give feedback to all pull requests within a week, but as so often, life can get in the way.\n   If you receive no feedback from a maintainer within that time, please contact them directly (e.g. on `Gitter <https://gitter.im/cocotb/Lobby>`__ or email).\n   If a maintainer asks you to explain or modify code, try to do so.\n8. Once your code has at least one positive review from a maintainer and no maintainer strongly objects it your code is ready to be merged into the ``master`` branch.\n\nMaintainer Pre-approval\n-----------------------\n\nAfter making changes to cocotb, changes must be approved by at least one maintainer before being included.\nOut-of-scope and breaking changes **will not be accepted**.\nAlso a maintainer could object to a change due to implementation approach or code quality reasons.\nTo potentially save you frustration and time, it is a good idea to get maintainer pre-approval on the task before starting it.\n\nThe best way to get maintainer pre-approval is to make a `Github issue <https://github.com/cocotb/cocotb/issues>`__.\nThese issues can be a place for maintainers, as well as other users, to voice opinions on a proposed change before the task is worked.\nYou may also propose changes on the `Gitter channel <https://gitter.im/cocotb/Lobby>`__ or by directly contacting one of the :ref:`maintainers`.\n\nPatch Requirements\n------------------\n\nAll changes which should go into the main codebase of cocotb must follow this set of requirements.\n\n-  The code must be within the `scope of cocotb <#architecture-and-scope-of-cocotb>`__.\n-  All code must be licensed under the `Revised BSD License <https://github.com/cocotb/cocotb/blob/master/LICENSE>`__.\n   By contributing to this project you signal your agreement with these license terms.\n-  All code must follow the established coding standards:\n\n   -  For Python code, follow the `PEP 8 <https://www.python.org/dev/peps/pep-0008/>`__ style guide.\n   -  For C++ code, follow the `Google C++ Style Guide <https://google.github.io/styleguide/cppguide.html>`__ but with 4 space indentation.\n      You can run the following command to automatically format the modified file to match the standard:\n\n      .. code:: bash\n\n         clang-format -i <file>\n\n-  All code must pass existing tests.\n   New functionality must be accompanied by tests, and bug fixes should add tests to increase the test coverage and prevent regressions.\n-  If code changes or enhances documented behavior the documentation should be updated.\n-  If a change is user-visible, a newsfragment should be added to ``docs/source/newsfragments``.\n-  All pull requests must be accepted by at least one maintainer, with no maintainer strongly objecting.\n   Reviews must be performed by a person other than the primary author of the code.\n-  All commits should follow established best practices when creating a commit message:\n\n   -  The first line of the commit message is the short summary of what the code change does.\n      Keep this line below 50 characters.\n   -  Then have one blank line.\n   -  Now comes the long description of the commit.\n      Use this text to discuss things which are not obvious from the code, especially *why* changes were made.\n      Include the GitHub issue number (if one exists) in the form \"Fixes #nnn\" (`read more about that <https://help.github.com/articles/closing-issues-using-keywords/>`__).\n      Keep each description line below 72 characters.\n\n-  Use the following header for new non-example files:\n\n   .. code:: python\n\n      # Copyright cocotb contributors\n      # Licensed under the Revised BSD License, see LICENSE for details.\n      # SPDX-License-Identifier: BSD-3-Clause\n\n-  Use the following header for new example files:\n\n   .. code:: python\n\n      # This file is public domain, it can be freely copied without restrictions.\n      # SPDX-License-Identifier: CC0-1.0\n"
  },
  {
    "path": "docs/source/contributors.rst",
    "content": "************\nContributors\n************\n\n.. spelling:word-list::\n   McGregor\n   Grimwood\n   FOSSi\n   Solarflare\n\ncocotb is developed and maintained by an active community.\nOur GitHub repository contains a list of the `contributors <https://github.com/cocotb/cocotb/graphs/contributors>`_.\n\nSince mid-2018 cocotb is an independent project under the umbrella of the\n`FOSSi Foundation <https://www.fossi-foundation.org>`_.\nThe FOSSi Foundation provides the cocotb project with financial,\nlegal and administrative support, and holds cocotb assets.\n\n.. _maintainers:\n\nMaintainers\n===========\n\ncocotb uses a shared maintainer model.\nMost maintainers are experts in part of the cocotb codebase, and are primarily responsible for reviews in this area.\n\n- Kaleb Barrett (@ktbarrett)\n- Tomasz Hemperek (@themperek)\n- Marlon James (@marlonjames)\n- Colin Marquardt (@cmarqu)\n- Philipp Wagner (@imphil)\n- Eric Wieser (@eric-wieser)\n\ncocotb was originally developed by Stuart Hodgson and Chris Higgs of Potential Ventures\nwith the support of Solarflare Communications Ltd.\nand contributions from Gordon McGregor and Finn Grimwood.\n"
  },
  {
    "path": "docs/source/coroutines.rst",
    "content": ".. _coroutines:\n.. _async_functions:\n\n.. spelling:word-list::\n   Async\n\n\n******************************\nCoroutines, Tasks and Triggers\n******************************\n\ncocotb testbenches use Python's coroutines.\n:dfn:`Tasks` are cocotb objects that wrap coroutines\nand are used to schedule concurrent execution of the coroutines.\n\nWhile active tasks are executing, the simulation is paused.\nThe coroutine uses the :keyword:`await` keyword to\nblock on another coroutine's execution or pass control of execution back to the\nsimulator, allowing simulation time to advance.\n\nTypically coroutines :keyword:`!await` a :class:`~cocotb.triggers.Trigger` object which\npauses the task, and indicates to the simulator some event which will cause the task to resume execution.\nIn the following example, :class:`~cocotb.triggers.Timer` is such a trigger:\n\n.. code-block:: python\n\n    async def wait_10ns():\n        cocotb.log.info(\"About to wait for 10 ns\")\n        await Timer(10, unit=\"ns\")\n        cocotb.log.info(\"Simulation time has advanced by 10 ns\")\n\nCoroutines may also :keyword:`!await` on other coroutines:\n\n.. code-block:: python\n\n    async def wait_100ns():\n        for i in range(10):\n            await wait_10ns()\n\nCoroutines can :keyword:`return` a value, so that they can be used by other coroutines.\n\n.. code-block:: python\n\n    async def get_signal(clk, signal):\n        await RisingEdge(clk)\n        return signal.value\n\n    async def check_signal_changes(dut):\n        first = await get_signal(dut.clk, dut.signal)\n        second = await get_signal(dut.clk, dut.signal)\n        assert first != second, \"Signal did not change\"\n\n\nTriggers and Concurrency Utilities\n==================================\n\nBelow is a table of triggers and concurrency utilities that are useful for writing testbenches and models.\n\n..\n   Please keep this table aligned with the content in library_reference.rst\n\n+------------------------------------------------------+-------------------------------------------------------------------------------------------+\n| **Signal Edges**                                                                                                                                 |\n+------------------------------------------------------+-------------------------------------------------------------------------------------------+\n| | :class:`~cocotb.triggers.RisingEdge`               | | Resume after a *rising* edge on a single-bit signal                                     |\n| | :class:`~cocotb.triggers.FallingEdge`              | | Resume after a *falling* edge on a single-bit signal                                    |\n| | :class:`~cocotb.triggers.ValueChange`              | | Resume after *any* edge on a signal, but prefer using ``signal.value_change``           |\n| | :class:`~cocotb.triggers.ClockCycles`              | | Resume after the specified number of transitions of a signal                            |\n| | :class:`~cocotb.triggers.Edge`                     | | (deprecated, use ``signal.value_change`` instead)                                       |\n+------------------------------------------------------+-------------------------------------------------------------------------------------------+\n| **Timing**                                                                                                                                       |\n+------------------------------------------------------+-------------------------------------------------------------------------------------------+\n| | :class:`~cocotb.triggers.Timer`                    | | Resume after the specified time                                                         |\n| | :class:`~cocotb.triggers.ReadOnly`                 | | Resume when the simulation timestep moves to the *read-only* phase                      |\n| | :class:`~cocotb.triggers.ReadWrite`                | | Resume when the simulation timestep moves to the *read-write* phase                     |\n| | :class:`~cocotb.triggers.NextTimeStep`             | | Resume when the simulation timestep moves to the *next time step*                       |\n+------------------------------------------------------+-------------------------------------------------------------------------------------------+\n| **Concurrency**                                                                                                                                  |\n+------------------------------------------------------+-------------------------------------------------------------------------------------------+\n| | :func:`~cocotb.triggers.gather`                    | | Resume after *all* given Tasks or Triggers                                              |\n| | :func:`~cocotb.triggers.select`                    | | Resume after *any* given Tasks or Triggers                                              |\n| | :class:`~cocotb.triggers.Combine`                  | | Resume after *all* given Triggers                                                       |\n| | :class:`~cocotb.triggers.First`                    | | Resume after *any* given Triggers                                                       |\n| | :meth:`Task.complete <cocotb.task.Task.complete>`  | | Resume when a Task completes                                                            |\n| | :func:`~cocotb.triggers.wait` [#f1]_               | | Await on all given Tasks or Triggers concurrently and block until a condition is met    |\n| | :class:`~cocotb.triggers.NullTrigger` [#f1]_       | | Resume \"soon\"                                                                           |\n+------------------------------------------------------+-------------------------------------------------------------------------------------------+\n| **Synchronization**                                                                                                                              |\n+------------------------------------------------------+-------------------------------------------------------------------------------------------+\n| | :class:`~cocotb.triggers.Event`                    | | A way to signal an event across Tasks                                                   |\n| | :class:`~cocotb.triggers.Lock`                     | | A mutual exclusion lock                                                                 |\n| | :func:`~cocotb.triggers.with_timeout`              | | Resume latest at the specified timeout time                                             |\n+------------------------------------------------------+-------------------------------------------------------------------------------------------+\n\n.. rubric:: Footnotes\n\n.. [#f1] Uncommon.\n\nConcurrent Execution\n====================\n\nCoroutines can be scheduled for concurrent execution with :func:`~cocotb.start_soon`.\nThese concurrently running coroutines are called :class:`~cocotb.task.Task`\\ s.\n\n:func:`~cocotb.start_soon` schedules the coroutine for *future* execution,\nsome time after the current Task yields control.\n\n.. code-block:: python\n\n    @cocotb.test()\n    async def test_act_during_reset(dut):\n        \"\"\"While reset is active, toggle signals\"\"\"\n        tb = uart_tb(dut)\n        # \"Clock\" is a built in class for toggling a clock signal\n        Clock(dut.clk, 1, unit=\"ns\").start()\n        # reset_dut is a function -\n        # part of the user-generated \"uart_tb\" class\n        # run reset_dut immediately before continuing\n        await tb.reset_dut(dut.rstn, 20)\n\n        await Timer(10, unit=\"ns\")\n        print(\"Reset is still active: %d\" % dut.rstn)\n        await Timer(15, unit=\"ns\")\n        print(\"Reset has gone inactive: %d\" % dut.rstn)\n\nOther tasks can be used in an await statement to suspend the current task until the other task finishes.\n\n.. code-block:: python\n\n    @cocotb.test()\n    async def test_count_edge_cycles(dut, period_ns=1, clocks=6):\n        Clock(dut.clk, period_ns, unit=\"ns\").start()\n        await RisingEdge(dut.clk)\n\n        timer = Timer(period_ns + 10, \"ns\")\n        task = cocotb.start_soon(count_edges_cycles(dut.clk, clocks))\n        count = 0\n        expect = clocks - 1\n\n        while True:\n            result = await First(timer, task)\n            assert count <= expect, \"Task didn't complete in expected time\"\n            if result is timer:\n                cocotb.log.info(\"Count %d: Task still running\", count)\n                count += 1\n            else:\n                break\n\nTasks can be killed before they complete,\nforcing their completion before they would naturally end.\n\n.. code-block:: python\n\n    @cocotb.test()\n    async def test_different_clocks(dut):\n        clk_1mhz   = Clock(dut.clk, 1.0, unit=\"us\")\n        clk_250mhz = Clock(dut.clk, 4.0, unit=\"ns\")\n\n        clk_1mhz.start()\n        start_time_ns = get_sim_time(unit=\"ns\")\n        await Timer(1, unit=\"ns\")\n        await RisingEdge(dut.clk)\n        edge_time_ns = get_sim_time(unit=\"ns\")\n        assert isclose(edge_time_ns, start_time_ns + 1000.0), \"Expected a period of 1 us\"\n\n        clk_1mhz.stop()  # stop 1MHz clock here\n\n        clk_250mhz.start()\n        start_time_ns = get_sim_time(unit=\"ns\")\n        await Timer(1, unit=\"ns\")\n        await RisingEdge(dut.clk)\n        edge_time_ns = get_sim_time(unit=\"ns\")\n        assert isclose(edge_time_ns, start_time_ns + 4.0), \"Expected a period of 4 ns\"\n\n\n.. versionchanged:: 1.4\n    The ``cocotb.coroutine`` decorator is no longer necessary for :keyword:`async def` coroutines.\n    :keyword:`async def` coroutines can be used, without the ``@cocotb.coroutine`` decorator, wherever decorated coroutines are accepted,\n    including :keyword:`yield` statements and ``cocotb.fork`` (since replaced with :func:`~cocotb.start_soon`).\n\n.. versionchanged:: 1.6\n    Added :func:`cocotb.start` and :func:`cocotb.start_soon` scheduling functions.\n\n.. versionchanged:: 1.7\n    Deprecated ``cocotb.fork``.\n\n.. versionchanged:: 2.0\n    Removed ``cocotb.fork``.\n\n.. versionchanged:: 2.0\n    Removed ``cocotb.coroutine``.\n\n.. versionremoved:: 2.0\n    Removed references to the deprecated :func:`cocotb.start`.\n\n\nWaiting For Multiple Events Simultaneously\n==========================================\n\nOccasionally you'll need to wait for either one of many Tasks or Triggers to fire,\nor a collection of Tasks or Triggers to fire.\nThis is what :class:`~cocotb.triggers.First` and :class:`~cocotb.triggers.Combine` provide, respectively.\n\n\n.. _first-tutorial:\n\nWaiting For One Of Multiple Events\n----------------------------------\n\n:class:`~cocotb.triggers.First` is like awaiting multiple Triggers or Tasks at the same time,\nand resumes after one of the Triggers or Tasks fires.\nIt returns the result of awaiting the Task or Trigger that fired first.\nBelow we see it used to implement a timeout.\n\n.. code-block:: python\n\n    @cocotb.test\n    async def test_quiesce_or_timeout(dut):\n\n        # generate stimulus and drive it to the design\n        for trans in generate_transactions():\n            await drive(dut.intf, trans)\n\n        # wait for the design to quiesce or timeout\n        timeout = Timer(10, \"us\")\n        quiesce_task = cocotb.start_soon(quiesce())\n        result = await First(timeout, quiesce_task)\n        assert result is not timeout, \"Design has hung!\"\n\nFortunately for users timeouts are a common operation and cocotb provides :func:`~cocotb.triggers.with_timeout`.\nThe second section in the above code using it would be ``await with_timeout(quiesce(), 10, \"us\")``.\n\n.. note::\n\n    :class:`~cocotb.triggers.First` does *not* cancel Tasks that did not complete after it returns.\n    This means that Tasks passed to it are *still running*.\n    You may need to cancel those Tasks with :meth:`.Task.cancel`.\n\n\nDetermining Which Task Finishes First\n-------------------------------------\n\n:class:`~cocotb.triggers.First` can be used to determine which of multiple Tasks :meth:`complete <cocotb.task.Task.complete>` first using the following idiom.\n\n.. code-block:: python\n\n    @cocotb.test\n    async def test_which_finished_first(dut):\n\n        task_A = cocotb.start_soon(drive_A())\n        task_B = cocotb.start_soon(drive_B())\n\n        # Pass Task.complete rather than the Task directly.\n        result = await First(task_A.complete, task_B.complete)\n\n        # Compare the result against the Task's \"complete\" object.\n        if result is task_A.complete:\n            cocotb.log.info(\"Input A finished first\")\n        else:\n            cocotb.log.info(\"Input B finished first\")\n\n\n.. _combine-tutorial:\n\nWaiting For Multiple Events\n---------------------------\n\n:class:`~cocotb.triggers.Combine` is like awaiting multiple Triggers or Tasks at the same time,\nbut it resumes after *all* the listed Triggers or Tasks fire.\nUsing the example from the previous section, we can use it to wait until both the driving and quiesce are done.\n\n.. code-block:: python\n\n    @cocotb.test\n    async def test_wait_for_both(dut):\n\n        # generate stimulus and drive it to the design\n        async def drive_transactions():\n            for trans in generate_transactions():\n                await drive(dut.intf, trans)\n\n        # wait for both the driving and quiescing to complete before continuing\n        await Combine(\n            cocotb.start_soon(drive_transactions()),\n            cocotb.start_soon(quiesce())\n        )\n\nAnd of course, the sky is the limit when you compose the two.\n\n.. code-block:: python\n\n    @cocotb.test\n    async def test_wait_for_both_with_timeout(dut):\n\n        # wait for both the driving and quiescing to complete before continuing\n        # but timeout if *either* the driving or settling take too long\n        await Combine(\n            cocotb.start_soon(with_timeout(drive_transactions(), 1, \"us\")),\n            cocotb.start_soon(with_timeout(quiesce(), 10, \"us\")),\n        )\n\n\n.. note::\n\n    :class:`~cocotb.triggers.Combine` does *not* cancel Tasks that did not complete if it fails with an exception.\n    This means that Tasks passed to it are *still running*.\n    You may need to cancel those Tasks with :meth:`.Task.cancel`.\n\n.. _task_manager_tutorial:\n\n:class:`!TaskManager`\n=====================\n\nThe :class:`~cocotb.triggers.TaskManager` class is another way to run multiple async routines concurrently and wait for them all to complete.\nIt properly manages the lifetime of its \"children\" and handles exceptions and cancellations gracefully.\nUnlike :func:`~cocotb.triggers.gather` which takes all :term:`awaitable`\\ s and :term:`coroutine`\\ s at once,\n:class:`!TaskManager` allows adding new :term:`!awaitable`\\ s and :term:`!coroutine`\\ s dynamically,\nand provides options to control exception handling behavior on a per-Task basis,\nmaking it much more flexible.\n\nBasic Usage\n-----------\n\nTo use :class:`!TaskManager`, first construct it and use it as an :term:`asynchronous context manager` with the :keyword:`async with` statement.\nInside of the context block you can use the :deco:`fork <cocotb.triggers.TaskManager.fork>` decorator method to start :class:`!Task`\\ s concurrently.\nWhen control reaches the end of the context block\nthe :class:`!TaskManager` blocks the encompassing :class:`!Task` until all child :class:`!Task`\\ s complete.\n\n.. code-block:: python\n\n    from cocotb.triggers import TaskManager\n\n    # Drive two interfaces concurrently until both complete.\n\n    async with TaskManager() as tm:\n\n        @tm.fork\n        async def drive_interface1(): ...\n\n        @tm.fork\n        async def drive_interface2(): ...\n\n    # Control returns here when all drive Tasks have completed\n\nIn addition to the :deco:`!fork` method for starting :term:`coroutine function`\\ s concurrently,\n:meth:`~cocotb.triggers.TaskManager.start_soon` can be used for :keyword:`!await`\\ ing arbitrary :term:`awaitable`\\ s concurrently.\n\n.. code-block:: python\n\n    # Wait for operation to complete or timeout after 1 us\n\n    async with TaskManager() as tm:\n        tm.start_soon(RisingEdge(cocotb.top.operation_complete))\n\n        @tm.fork\n        async def watchdog():\n            await Timer(1, \"us\")\n            raise TimeoutError(\"Operation did not complete in time\")\n\nInspecting Child Task Results\n-----------------------------\n\nYou can inspect the result of child classes by storing the :class:`!Task` objects returned by the :meth:`!start_soon` method.\nWhen decoratoring a :term:`coroutine function` with :deco:`!fork`,\nthe name of the function will become the returned :class:`!Task` object.\n\n.. code-block:: python\n\n    async with TaskManager() as tm:\n        task1 = tm.start_soon(RisingEdge(cocotb.top.signal_a))\n\n        # task2 will become the Task object after wrapping the coroutine function with @fork\n        @tm.fork\n        async def task2():\n            return 42\n\n\n    assert task1.done()\n    assert task1.result() is RisingEdge(cocotb.top.signal_a)\n\n    assert task2.done()\n    assert task2.result() == 42\n\n.. note::\n    After exiting the context block and the :class:`!TaskManager` has begun finishing,\n    no further calls to :meth:`start_soon` or :deco:`!fork` are permitted.\n    Attempting to do so will raise a :exc:`RuntimeError`.\n\nHandling Exceptions and *continue_on_error*\n-------------------------------------------\n\n:class:`!TaskManager` gracefully handles exceptions raised in child :class:`!Task`\\ s or in the context block itself.\nIt ensures that no child :class:`!Task` is left running unintentionally by the time the context block exits.\n\nThe behavior of :class:`!TaskManager` when a child :class:`!Task` raises an exception is controlled by the *continue_on_error* parameter.\nThe constructor for :class:`!TaskManager` accepts an optional parameter *default_continue_on_error* which is used as the default for all children Tasks;\nit defaults to ``False``.\nThe :class:`!TaskManager`-wide default can be overridden on a per-Task basis using the *continue_on_error* parameter to the :deco:`!fork` or :meth:`!start_soon` methods.\n\n.. code-block:: python\n\n    async with TaskManager(default_continue_on_error=True) as tm:\n\n        @tm.fork(continue_on_error=False)\n        async def task1(): ...\n\n        tm.start_soon(some_coroutine(), continue_on_error=True)\n\nIf a child :class:`!Task` raises an exception,\none of two behaviors will occur depending on the value of *continue_on_error* for that Task.\nIf the *continue_on_error* parameter is ``False``, all other child :class:`!Task`\\ s are cancelled and the :class:`!TaskManager` will begin shutting down.\nIf the *continue_on_error* parameter is ``True``, the exception is captured and other child :class:`!Task`\\ s are allowed to continue running.\n\nAfter all child :class:`!Task`\\ s have finished,\nall exceptions, besides :exc:`~asyncio.CancelledError`, are gathered into an :exc:`ExceptionGroup`,\nor a :exc:`BaseExceptionGroup`, if at least one of the exceptions is a :exc:`BaseException`,\nand raised in the enclosing scope.\n\nYou can catch the :exc:`!ExceptionGroup` to handle errors from child :class:`!Task`\\ s\nby either catching the :exc:`!ExceptionGroup` as you would typically;\nor, if you are running Python 3.11 or later,\nusing the new `except* <https://docs.python.org/3/reference/compound_stmts.html#except-star>`_ syntax\nto catch specific exception types from the group.\nThis new syntax will run the except clause for each matching exception in the group.\n\n.. code-block:: python\n\n    try:\n        async with TaskManager(default_continue_on_error=True) as tm:\n\n            @tm.fork\n            async def task1():\n                ...\n                raise ValueError(\"An error occurred in task1\")\n\n            @tm.fork\n            async def task2():\n                ...\n                raise ValueError(\"An error occurred in task2\")\n\n    except* ValueError as e:\n        # This will print both ValueErrors from task1 and task2\n        cocotb.log.info(f\"Caught ValueError from TaskManager: {e}\")\n\n.. note::\n    After a :class:`!Task` fails and the :class:`!TaskManager` begins cancelling,\n    no further calls to :meth:`start_soon` or :deco:`!fork` are permitted.\n\nFailures Within the Context Block\n---------------------------------\n\nYou are permitted to add any :keyword:`await` statement to the body of the context block.\nThis means that it is possible for child tasks to start running, and then end with an exception, before the context block has finished.\nIn this case, a :exc:`~asyncio.CancelledError` will be raised from the current :keyword:`!await` expression in the context block,\nallowing the user to perform any necessary cleanup.\nThis :exc:`!CancelledError` will be squashed when the context block exits,\nand :class:`!TaskManager` continues shutting down as it normally would.\n\n.. code-block:: python\n\n    async with TaskManager() as tm:\n\n        @tm.fork\n        async def task1():\n            raise ValueError(\"An error occurred in task1\")\n\n        try:\n            await Timer(10)  # During this await, task1 will fail\n        except CancelledError:\n            cocotb.log.info(\n                \"The rest of the context block will be skipped due to task1 failing\"\n            )\n            raise  # DON'T FORGET THIS\n\n        ...  # This code will be skipped\n\n.. warning::\n    Just like with :class:`~cocotb.task.Task`, if a :class:`!TaskManager` context block is cancelled\n    and squashes the resulting :exc:`asyncio.CancelledError`, the test will be forcibly failed immediately.\n    Always remember to re-raise the :exc:`!asyncio.CancelledError` if you catch it.\n\nA context block can also fail with an exception like a child :class:`!Task` could.\nIn this case, if the *context_continue_on_error* parameter to the constructor is ``False``, all child :class:`!Task`\\ s are cancelled;\nif it is set to ``True``, other child :class:`!Task`\\ s are allowed to continue running.\nIn either case, after all child :class:`!Task`\\ s have finished,\nall exceptions, besides :exc:`~asyncio.CancelledError`, are gathered into an :exc:`ExceptionGroup`,\nor a :exc:`BaseExceptionGroup`, if at least one of the exceptions is a :exc:`BaseException`,\nand raised in the enclosing scope.\n\n.. code-block:: python\n\n    try:\n        async with TaskManager(context_continue_on_error=True) as tm:\n\n            @tm.fork\n            async def task1():\n                ...\n                return 42\n\n            raise ValueError(\"An error occurred in the context block\")\n\n    except* ValueError as e:\n        # This will print the ValueError from the context block\n        cocotb.log.info(f\"Caught ValueError from TaskManager: {e}\")\n\n    assert task1.result() == 42  # task1 was allowed to continue running until completion\n\nNesting :class:`!TaskManager`\n-----------------------------\n\n:class:`!TaskManager`\\ s can be arbitrarily nested.\nWhen any child :class:`!Task` fails, the entire tree of child :class:`!Task`\\ s will eventually be cancelled.\n\n.. code-block:: python\n\n    async with TaskManager() as tm_outer:\n\n        @tm_outer.fork\n        async def outer_task():\n            ...\n            raise RuntimeError(\"An error occurred in outer_task\")\n\n        async with TaskManager() as tm_inner:\n\n            # This inner task will be cancelled when outer_task fails\n            @tm_inner.fork\n            async def another_task(): ...\n\n    assert outer_task.exception() is RuntimeError\n    assert another_task.cancelled()\n\nAsync generators\n================\n\nStarting with Python 3.6, a :keyword:`yield` statement within an async function\nhas a new meaning which matches the typical meaning of yield within regular Python code.\nIt can be used to create a special type of generator function that can be iterated with :keyword:`async for`:\n\n.. code-block:: python\n\n    async def ten_samples_of(clk, signal):\n        for i in range(10):\n            await RisingEdge(clk)\n            yield signal.value  # this means \"send back to the for loop\"\n\n    @cocotb.test()\n    async def test_samples_are_even(dut):\n        async for sample in ten_samples_of(dut.clk, dut.signal):\n            assert sample % 2 == 0\n\nMore details on this type of generator can be found in :pep:`525`.\n\n\n.. _yield-syntax:\n\nGenerator-based coroutines\n==========================\n\n.. versionchanged:: 2.0\n    This style, which used the ``cocotb.coroutine`` decorator and the yield syntax, was removed.\n"
  },
  {
    "path": "docs/source/coverage.rst",
    "content": "********************\nPython Code Coverage\n********************\n\ncocotb provides support for collecting Python code coverage via the `coverage <https://coverage.readthedocs.io/>`_ package.\n\nThere are two main approaches to enabling coverage collection in cocotb regressions:\nusing the :envvar:`!COCOTB_USER_COVERAGE` environment variable, which is a temporary enablement,\nor by instrumenting your environment with :mod:`!coverage`'s :mod:`!sitecustomize` hook, which is a more permanent solution.\n\nThe first step in either approach is to install the :mod:`!coverage` package if you haven't already.\n\n.. code-block:: bash\n\n   pip install coverage\n\n\nUsing :envvar:`!COCOTB_USER_COVERAGE`\n=====================================\n\ncocotb provides the :envvar:`COCOTB_USER_COVERAGE` environment variable to enable coverage collection for the current regression.\nThis solution is ideal for users who only want to collect coverage occasionally or on a per-regression basis,\nor don't want to permanently modify their Python environment.\n\nTo enable coverage collection, set :envvar:`!COCOTB_USER_COVERAGE` to ``1`` before running your tests.\nThe :mod:`!coverage` module will use the :envvar:`COVERAGE_RCFILE` environment variable to find the configuration file to determine what to measure.\nIf :envvar:`!COVERAGE_RCFILE` is not set, cocotb provides a default configuration that collects line and branch coverage for all Python modules\nexcept those in the ``cocotb``, ``cocotb_tools``, and ``pygpi`` package directories.\n\n.. code-block:: bash\n\n   export COCOTB_USER_COVERAGE=1\n   # optional, only if you want to use a custom config file\n   export COVERAGE_RCFILE=path/to/your/.coveragerc\n\n   pytest\n   # or\n   make\n\nThis will create a file named ``.coverage`` in the directory where the test was run.\n\n\nInstrumenting your environment with :mod:`!coverage`'s :mod:`!sitecustomize` hook\n=================================================================================\n\nThis approach works well for users who regularly collect coverage across\nsubprocesses in their environment and want a single configuration that\napplies everywhere.\n\nThe :mod:`!coverage` module provides support for automatically collecting coverage for all packages in a Python environment\nregardless of how Python is invoked (e.g. via embedding a Python interpreter in a simulator) for a process and all its subprocesses.\nThis requires installing a :mod:`sitecustomize` hook that starts coverage measurement in any Python process.\n\nFollow the instructions in the `coverage documentation <https://coverage.readthedocs.io/en/latest/subprocess.html#manual-sub-process-coordination>`_ to add this hook.\n\nThen, to collect coverage for your cocotb tests, do the following:\n\n1. Create a ``.coveragerc`` configuration file specifying what to measure:\n\n   .. code-block:: ini\n\n      [run]\n      branch = True\n      source = my_package\n\n2. Set the ``COVERAGE_PROCESS_START`` environment variable and run your\n   tests. The exact command depends on how you run cocotb:\n\n   .. tab-set::\n\n      .. tab-item:: Makefile-based flow\n\n         .. code-block:: bash\n\n            export COVERAGE_PROCESS_START=.coveragerc\n            make\n\n      .. tab-item:: Python Runner\n\n         .. code-block:: bash\n\n            export COVERAGE_PROCESS_START=.coveragerc\n            python my_test_script.py\n\n      .. tab-item:: pytest\n\n         .. code-block:: bash\n\n            export COVERAGE_PROCESS_START=.coveragerc\n            coverage run --parallel-mode -m pytest\n\nThis will create a file named ``.coverage`` in the directory where the test was run.\n\n\nCombining coverage data from multiple runs\n==========================================\n\nIf you run your tests multiple times with coverage collection enabled from the same directory,\ncocotb will automatically load the configured coverage data from previous runs to append all coverage data together.\n\nHowever, if you are running tests in multiple directories, or running tests in parallel, you may end up with multiple ``.coverage`` files.\nYou can combine the resulting ``.coverage`` files into a single file using the `combine <https://coverage.readthedocs.io/en/latest/commands/cmd_combine.html#cmd-combine>`_ command.\n\n.. code-block:: bash\n\n   coverage combine path/to/.coverage path/to/other/.coverage\n\nThis will create a new ``.coverage`` file that combines the data from the specified files.\n\n\nViewing the coverage data\n=========================\n\nAfter running your tests with coverage collection enabled, you can use the `coverage command-line tool <https://coverage.readthedocs.io/en/latest/commands/index.html>`_ to view the results.\n\nThe simplest way to view the results is to use the `report <https://coverage.readthedocs.io/en/latest/commands/cmd_report.html#cmd-report>`_ command.\nThis will print a summary of the coverage including the number of statements that were hit and missed, the missed line numbers, and overall coverage percentage, to the terminal.\n\n.. code-block:: bash\n\n   coverage report\n\nFor a more detailed view, you can use the `html <https://coverage.readthedocs.io/en/latest/commands/cmd_html.html#cmd-html>`_ command to generate an HTML report.\n\n.. code-block:: bash\n\n   coverage html\n\nThis will create an ``htmlcov`` directory with an ``index.html`` file that you can open in a web browser which will allow you to navigate your testbench and the libraries it uses,\nand will show coverage details annotated on the source code.\n"
  },
  {
    "path": "docs/source/custom_flows.rst",
    "content": ".. _custom-flows:\n\n******************************\nExtending Existing Build Flows\n******************************\n\nIn order to extend an existing build flow for use with cocotb,\nthis chapter shows the minimum settings to be done.\n\n.. note::\n   These instructions are an unsupported alternative to using the Makefiles provided by cocotb.\n   The ``$(cocotb-config ...)`` syntax for executing ``cocotb-config`` works in the bash shell;\n   adapt for your scripting language as needed.\n\n\nFor all simulators, the following environment variables need to be set:\n\n* Define :envvar:`GPI_USERS` using ``$(cocotb-config --libpython);$(cocotb-config --pygpi-entry-point)``.\n* Define :envvar:`PYGPI_PYTHON_BIN` using ``$(cocotb-config --python-bin)``.\n* Define :envvar:`COCOTB_TEST_MODULES` with the name of the Python module(s) containing your testcases.\n\nSee the sections below for additional settings to be done, depending on the simulator.\n\n.. _custom-flows-icarus:\n\nIcarus Verilog\n==============\n\n* Call the ``vvp`` executable with the option ``-m $(cocotb-config --lib-name vpi icarus)``.\n\nVerilator\n=========\n\n* Extend the call to ``verilator`` with these options:\n\n   .. code-block::\n\n      --vpi --public-flat-rw --prefix Vtop \\\n      -LDFLAGS \"-Wl,-rpath,$(cocotb-config --lib-dir) \\\n          -L$(cocotb-config --lib-dir) \\\n          -lcocotbvpi_verilator\" \\\n      $(cocotb-config --share)/lib/verilator/verilator.cpp\n\n* Run Verilator's makefile as follows: ``CPPFLAGS=\"-std=c++11\" make -f Vtop.mk``\n\n.. _custom-flows-vcs:\n\nSynopsys VCS\n============\n\n* Create a file :file:`pli.tab` with the content ``acc+=rw,wn:*`` (or equivalent)\n  to allow cocotb to access values in the design.\n* Extend the ``vcs`` call with the options\n  ``+vpi -P pli.tab -load $(cocotb-config --lib-name-path vpi vcs)``.\n\n.. _custom-flows-aldec:\n.. _custom-flows-riviera:\n\nAldec Riviera-PRO\n=================\n\n* The ``asim`` call needs the ``+access +w_nets`` option set to allow cocotb to access values in the design.\n\n.. tab-set::\n\n   .. tab-item:: Design with a VHDL Toplevel\n\n      For a design with a VHDL toplevel, call ``asim`` with the option\n      ``-loadvhpi $(cocotb-config --lib-name-path vhpi riviera):vhpi_startup_routines_bootstrap``.\n\n      Set the :envvar:`GPI_EXTRA` environment variable to\n      ``$(cocotb-config --lib-name-path vpi riviera):cocotbvpi_entry_point``\n      if there are also (System)Verilog modules in the design.\n\n   .. tab-item:: Design with a (System)Verilog Toplevel\n\n      For a design with a (System)Verilog toplevel, call ``alog`` and ``asim`` with the option\n      ``-pli $(cocotb-config --lib-name-path vpi riviera)``.\n\n      Set the :envvar:`GPI_EXTRA` environment variable to\n      ``$(cocotb-config --lib-name-path vhpi riviera):cocotbvhpi_entry_point``\n      if there are also VHDL modules in the design.\n\n.. _custom-flows-activehdl:\n\nAldec Active-HDL\n================\n\n* The ``asim`` call needs the ``+access +w_nets`` option set to allow cocotb to access values in the design.\n\n.. tab-set::\n\n   .. tab-item:: Design with a VHDL Toplevel\n\n      For a design with a VHDL toplevel, call ``asim`` with the option\n      ``-loadvhpi $(cocotb-config --lib-name-path vhpi activehdl):vhpi_startup_routines_bootstrap``.\n\n      Set the :envvar:`GPI_EXTRA` environment variable to\n      ``$(cocotb-config --lib-name-path vpi activehdl):cocotbvpi_entry_point``\n      if there are also (System)Verilog modules in the design.\n\n   .. tab-item:: Design with a (System)Verilog Toplevel\n\n      For a design with a (System)Verilog toplevel, call ``alog`` and ``asim`` with the option\n      ``-pli $(cocotb-config --lib-name-path vpi activehdl)``.\n\n      Set the :envvar:`GPI_EXTRA` environment variable to\n      ``$(cocotb-config --lib-name-path vhpi activehdl):cocotbvhpi_entry_point``\n      if there are also VHDL modules in the design.\n\n.. _custom-flows-siemens:\n\nMentor/Siemens EDA Questa and Modelsim\n======================================\n\nQuesta supports two different flows: the traditional flow using ``vsim``, which is also used by ModelSim, and a modern alternative using ``qrun``.\n\n.. tab-set::\n\n   .. tab-item:: Design with a VHDL Toplevel\n\n      For a design with a VHDL toplevel, call the ``vsim`` or ``qrun`` executable with the option\n      ``-foreign \"cocotb_init $(cocotb-config --lib-name-path fli questa)\"``.\n\n      Set the :envvar:`GPI_EXTRA` environment variable to\n      ``$(cocotb-config --lib-name-path vpi questa):cocotbvpi_entry_point``\n      if there are also (System)Verilog modules in the design.\n\n   .. tab-item:: Design with a (System)Verilog Toplevel\n\n      For a design with a (System)Verilog toplevel, call the ``vsim`` or ``qrun`` executable with the option\n      ``-pli $(cocotb-config --lib-name-path vpi questa)``.\n\n      Set the :envvar:`GPI_EXTRA` environment variable to\n      ``$(cocotb-config --lib-name-path fli questa):cocotbfli_entry_point``\n      if there are also VHDL modules in the design.\n\n.. _custom-flows-cadence:\n\nCadence Incisive and Xcelium\n============================\n\n* The ``xrun`` call (or ``xmelab`` in multi-step mode) needs the ``-access +rwc``\n  (or equivalent, e.g. :samp:`-afile {afile}`) option set to allow cocotb to access values in the design.\n\n* The ``xrun`` call (or ``xmsim`` in multi-step mode) needs the VPI library and entry point via the option\n  ``-loadvpisim $(cocotb-config --lib-name-path vpi xcelium):vlog_startup_routines_bootstrap``.\n  Alternatively, it is possible to specify the same during elaboration in multi-step mode with\n  ``-loadvpi $(cocotb-config --lib-name-path vpi xcelium):.vlog_startup_routines_bootstrap``.\n  The syntax is ``-loadvpi library:elab_functions[.sim_functions]``, taking two comma separated lists of\n  methods. The first list is invoked during elaboration and then simulation, while the second only applies\n  to simulation and it is the one to use to register callbacks. Specifying the entry point in ``elab_functions``\n  works but has the downside of initializing cocotb during elaboration, not only simulation.\n\n* If the design contains any VHDL modules, set the :envvar:`GPI_EXTRA` environment variable to\n  ``$(cocotb-config --lib-name-path vhpi xcelium):cocotbvhpi_entry_point``.\n  This is because directly loading the VHPI library causes an error in Xcelium,\n  so always load the VPI library and supply VHPI via ``GPI_EXTRA``.\n\n.. note::\n  For a design with a VHDL toplevel, call the ``xrun`` or ``xmelab`` executable with the option\n  ``-NEW_VHPI_PROPAGATE_DELAY``.\n\n.. _custom-flows-ghdl:\n\nGHDL\n====\n\n* Extend the ``ghdl -r`` call with the option\n  ``--vpi=$(cocotb-config --lib-name-path vpi ghdl)``.\n\n.. _custom-flows-nvc:\n\nNVC\n===\n\n* Extend the ``nvc -r`` call with the option\n  ``--load=$(cocotb-config --lib-name-path vhpi nvc)``.\n\n.. note::\n   It is recommended to add ``--preserve-case`` to build arguments.\n   This is standards-compliant behavior and may become default behavior in NVC.\n\n.. _custom-flows-cvc:\n\nTachyon DA CVC\n==============\n\n* Extend the ``cvc64`` call with the option\n  ``+interp +acc+2 +loadvpi=$(cocotb-config --lib-name-path vpi cvc):vlog_startup_routines_bootstrap``.\n\n.. _custom-flows-dsim:\n\nSiemens DSim\n============\n\n* Extend the ``dsim`` call with the option\n  ``-pli_lib $(cocotb-config --lib-name-path vpi dsim) +acc+rwcbfsWF``.\n"
  },
  {
    "path": "docs/source/developing.rst",
    "content": "*****************\nDeveloping cocotb\n*****************\n\nSetting Up a Development Environment\n====================================\n\n:ref:`Install prerequisites to build the development version of cocotb <install-devel>` and standard development tools (editor, shell, git, etc.).\n\n.. note:: Documentation generation requires Python 3.11+.\n\nFirst, you should `fork and clone <https://guides.github.com/activities/forking/>`__ the cocotb repo to your machine.\nThis will allow you to make changes to the cocotb source code, create pull requests, and run regressions and build documentation locally.\n\nYou will need `doxygen <https://www.doxygen.nl/index.html>`__, for building documentation.\nWe recommend if you are using a Linux distribution to use your system package manager to install doxygen.\nLikewise, doxygen can be installed using the homebrew package manager on Mac OS.\nWindows contributors should download a binary distribution installer from the main website.\n\nNext install `uv <https://docs.astral.sh/uv/getting-started/installation/>`__,\nwhich is a tool for managing Python virtual environments and dependencies.\n\nAfter ``uv`` is installed, run the following command in the project root to build a virtual environment for development.\n\n.. code:: bash\n\n   uv venv\n\nThis will create a virtual environment and print instructions on how to activate it.\nAfter you activate the virtual environment, you can install the development dependencies with the following command:\n\n.. code:: bash\n\n   uv sync --dev\n\n.. note::\n   We recommend using `direnv <https://direnv.net/>`__ to automatically activate the virtual environment when you navigate into the project directory.\n\nTo enable pre-commit checks, run the following command at the root of the cloned project to install the git hooks.\n\n.. code:: bash\n\n   prek install\n\nWhen committing, prek's git commit hooks will run, checking your changes for formatting, code smells, etc.\nYou will see the lists of checks printed and whether they passed, were skipped, or failed.\nIf any of the checks fail, it is recommended to fix them before opening a pull request,\notherwise the pull request checks will fail as well.\n\nNow you are ready to contribute!\n\nRunning Tests Locally\n=====================\n\nFirst, `set up your development environment <#setting-up-a-development-environment>`__.\n\nOur tests are managed by ``nox``, which runs both ``pytest`` tests and our system of makefiles.\nThe regression does not end on the first failure, but continues until all tests in the ``/tests`` and ``/examples`` directories have been run.\n\nTo run the tests locally with ``nox``, issue the following command.\n\n.. code:: bash\n\n   nox -s dev_test\n\nAt the end of the regression, if there were any test failures, the tests that failed will be printed.\nIf the tests succeed you will see the message ``Session tests was successful`` printed in green.\n\nBy default the ``dev_test`` nox session runs all simulator-agnostic tests, as well as all tests which require a simulator and can be run against Icarus Verilog.\nIcarus Verilog must be installed.\n\nThe simulator and the toplevel language can be changed by setting the environment variables :make:var:`SIM` and :make:var:`TOPLEVEL_LANG`.\nAlternatively, the simulator-specific nox sessions can be used, as described below.\n\nSelecting a Language and Simulator for Regression\n=================================================\n\ncocotb can be used with multiple simulators, and can run tests against all of them.\nNox provides a session for each valid simulator/language/GPI interface combination, from which one or multiple sessions can be selected.\n\nThe following examples are good starting points;\nrefer to the `nox command-line usage documentation <https://nox.thea.codes/en/stable/usage.html>`__ for more information.\n\n.. code:: bash\n\n   # List all available sessions.\n   nox -l\n\n   # Run all simulator-agnostic tests.\n   nox -s dev_test_nosim\n\n   # Run the simulator-specific tests against Xcelium, using a VHDL toplevel and\n   # the VHPI interface.\n   nox -s \"dev_test_sim(sim='xcelium', toplevel_lang='vhdl', gpi_interface='vhpi')\"\n\n   # Run all simulator-specific tests against Icarus Verilog and GHDL.\n   # Both simulators must be installed locally.\n   nox -k \"dev_test_sim and (icarus or ghdl)\"\n\nRunning Individual Tests Locally\n================================\n\nEach test under ``/tests/test_cases/*/`` and ``/examples/*/tests/`` can be run individually.\nThis is particularly useful if you want to run a particular test that fails the regression.\n\nFirst you must install cocotb from source by navigating to the project root directory and issuing the following command:\n\n.. code:: bash\n\n   python -m pip install .\n\nOn Windows, you must instead install cocotb from source like so:\n\n.. code:: bash\n\n   python -m pip install --global-option build_ext --global-option --compiler=mingw32 .\n\nOnce that has been done, you can navigate to the directory containing the test you wish to run.\nThen you may issue an :ref:`make <building>` command.\nFor example, if you want to test with Icarus using Verilog sources:\n\n.. code:: bash\n\n   make SIM=icarus TOPLEVEL_LANG=verilog\n\nBuilding Documentation Locally\n==============================\n\nFirst, `set up your development environment <#setting-up-a-development-environment>`__.\n\nDocumentation is built locally using ``nox``.\nThe last message in the output will contain a URL to the documentation you just built.\nSimply copy and paste the link into your browser to view it.\nThe documentation will be built in the same location on your hard drive on every run, so you only have to refresh the page to see new changes.\n\nTo build the documentation locally on Linux or Mac, issue the following command:\n\n.. code:: bash\n\n   nox -e docs\n\nBuilding the documentation is not currently supported on Windows.\n"
  },
  {
    "path": "docs/source/diagrams/README.md",
    "content": "The sources for the vector diagrams (in `xml/`) can be edited with\n[diagrams.net](https://app.diagrams.net/) - formerly called \"draw.io\".\n\nThe SVG files in `svg/` are exported versions of those.\n\nNote that diagrams.net allows you to directly save and export the files\nto your cocotb fork/branch on GitHub, producing git commits.\n"
  },
  {
    "path": "docs/source/examples.rst",
    "content": "*************\nMore Examples\n*************\n\nApart from the examples covered with full tutorials in the previous sections,\nthe directory :file:`examples/` contains some more smaller modules you may want to take a look at.\n\n\nAdder\n=====\n\nThe directory :file:`examples/adder/` contains an ``adder`` :term:`RTL` in both Verilog and VHDL,\nan ``adder_model`` implemented in Python,\nand the cocotb testbench with two defined tests — a simple :func:`adder_basic_test` and\na slightly more advanced :func:`adder_randomised_test`.\n\n\n.. _matrix_multiplier:\n\nMatrix Multiplier\n=================\n\nThe directory :file:`examples/matrix_multiplier`\ncontains a module for multiplying two matrices together,\nimplemented in both **VHDL** and **SystemVerilog**.\n\nThe module takes two matrices ``a_i`` and ``b_i`` as inputs\nand provides the resulting matrix ``c_o`` as an output.\nOn each rising clock edge,\n``c_o`` is calculated and output.\nWhen input ``valid_i`` is high\nand ``c_o`` is calculated,\n``valid_o`` goes high to signal a valid output value.\n\nA reusable ``DataValidMonitor`` class is defined.\nIt monitors a streaming data/valid bus,\nsamples the bus when a transaction occurs,\nand places those transactions into an asynchronous :class:`~cocotb.queue.Queue`.\nThe queue allows another coroutine to consume monitored transactions at its own pace.\n\nA reusable ``MatrixMultiplierTester`` is also defined.\nIt instantiates two of the ``DataValidMonitor``\\ s:\none to monitor the matrix multiplier input,\nand another to monitor the output.\nThe ``MatrixMultiplierTester`` starts a task which consumes transactions from the input monitor,\nfeeds them into a model to compute an expected output,\nand finally compares the module output to the expected for correctness.\n\nThe main test coroutine stimulates the matrix multiplier DUT with the test data.\nOnce all the test inputs have been applied it decides when the test is done.\n\nThe testbench makes use of random data generators to test many sets of matrices.\n\nThe number of data bits for each entry in the matrices,\nas well as the row and column counts for each matrix,\nare configurable in the Makefile.\n\n.. note::\n    The example module uses one-dimensional arrays in the port definition to represent the matrices.\n\n\nMixed Language\n==============\n\nThe directory :file:`examples/mixed_language/` contains two toplevel :term:`HDL` files,\none in VHDL, one in SystemVerilog, that each instantiate an ``endian_swapper`` entity in\nSystemVerilog and VHDL in parallel and chains them together so that the endianness is swapped twice.\n\nThus, we end up with SystemVerilog+VHDL instantiated in VHDL and\nSystemVerilog+VHDL instantiated in SystemVerilog.\n\nThe cocotb testbench pulls the reset on both instances and checks that they behave the same.\n\n.. todo::\n\n   This example is not complete.\n\n.. spelling:word-list::\n   Todo\n\n\n.. _mixed_signal:\n\nMixed-signal (analog/digital)\n=============================\n\nThis example with two different designs shows\nhow cocotb can be used in an analog-mixed signal (AMS) simulation,\nprovided your simulator supports this.\nSuch an AMS setup involves a digital and an analog simulation kernel,\nand also provides means to transfer data between the digital and the analog domain.\n\nThe \"-AMS\" variants of the common digital HDLs (VHDL-AMS, Verilog-AMS and SystemVerilog-AMS)\nand languages like Spice can be used to express the analog behavior of your circuit.\n\nDue to limitations of the underlying simulator interfaces (VPI, VHPI, FLI),\ncocotb cannot directly access the analog domain but has to resort to e.g. HDL helper code.\nThus, unlike the other examples,\npart of this testbench is implemented with cocotb and the helper part with HDL.\n\n.. toctree::\n   rescap\n   regulator\n\n\n.. _system_modeling:\n\nSystem Modeling\n===============\n\n.. toctree::\n   analog_model\n"
  },
  {
    "path": "docs/source/extensions.rst",
    "content": "*************************\nWriting cocotb Extensions\n*************************\n\nThis guide explains how to write cocotb extensions, with a focus on the conventions that should be followed.\n\ncocotb gives its users a framework to build Python testbenches for hardware designs.\nBut sometimes the functionality provided by cocotb is too low-level.\nOne common example are bus drivers and monitors:\ninstead of creating a bus adapter from scratch for each new project, wouldn't it be nice to share this component, and build on top it?\nIn the verification world, such extensions are often called \"verification IP\" (VIP).\n\nIn cocotb, such functionality can be packaged and distributed as extensions.\nTechnically, cocotb extensions are normal Python packages, and all standard Python packaging and distribution techniques can be used.\nAdditionally, the cocotb community has agreed on a set of conventions to make extensions easier to use and to discover.\n\n.. _extensions-naming-conventions:\n\nNaming conventions\n==================\n\ncocotb extensions are normal Python modules which follow these naming conventions.\n\nAssuming an extension named ``EXTNAME`` (all lower-case),\n\n- the package is in the ``cocotbext.EXTNAME`` namespace, and\n- the distribution (package) name is prefixed with ``cocotbext-EXTNAME``.\n\nFor example, a SPI bus extension might be packaged as ``cocotbext-spi``, and its functionality would live in the ``cocotbext.spi`` namespace.\nThe module can then be installed with ``pip3 install cocotbext-spi``, and used with ``import cocotbext.spi``.\n\nLicensing\n=========\n\ncocotb is licensed under the `3-clause BSD license <https://spdx.org/licenses/BSD-3-Clause.html>`_.\nThis license is a permissive open source license that allows redistribution of both source and binary forms, with or without modification, so long as the original copyright is included.\nThis means any open source or closed source, commercial or non-commercial project can use cocotb.\nIt is also compatible with a large number of other licenses.\nFor all these reasons, we recommend that cocotb extensions be released under the 3-clause BSD license.\n\nThat being said, you are free to license your cocotb extension under whatever license you prefer,\nso long as it is compatible with the cocotb license.\n\n\nPackaging extensions\n====================\n\nTo package a cocotb extension as Python package follow the :ref:`extensions-naming-conventions`, and the `normal Python packaging rules <https://packaging.python.org/tutorials/packaging-projects/>`_.\nExtensions namespaced packages, implemented using the `native namespacing <https://packaging.python.org/guides/packaging-namespace-packages/#native-namespace-packages>`_ approach discussed in :pep:`420`.\nThe module file hierarchy should be as follows (replace ``EXTNAME`` with the name of the extension, e.g. ``spi``).\n\n.. code-block::\n\n  # file structure of the cocotbext-EXTNAME repository\n  ├── cocotbext/\n  │   │   # No __init__.py here.\n  │   └── EXTNAME/\n  │       └── __init__.py\n  ├── README.md\n  └── setup.py\n\nThe Python source code should go into the :file:`EXTNAME` directory, next to the :file:`__init__.py` file.\nAll packaging metadata goes into :file:`setup.py`.\n\n.. code-block:: python\n\n  # Minimal setup.py. Extend as needed.\n  from setuptools import setup, find_namespace_packages\n\n  setup(name = 'cocotbext-EXTNAME',\n        version = '0.1',\n        packages = find_namespace_packages(include=['cocotbext.*']),\n        install_requires = ['cocotb'],\n        python_requires = '>=3.9',\n        classifiers = [\n          \"Programming Language :: Python :: 3\",\n          \"Operating System :: OS Independent\",\n          \"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)\",\n          \"Framework :: cocotb\"])\n\nWith this file structure in place the cocotb extension can be installed through ``pip`` in development mode ::\n\n  $ python3 -m pip install -e .\n\nOnce the extension has been `uploaded to PyPi <https://packaging.python.org/tutorials/packaging-projects/#uploading-the-distribution-archives>`_, it can be installed by name.\n\n.. code-block: command\n\n  $ python3 -m pip install cocotbext-EXTNAME\n\nTo use the functionality in the extension module, import it into your testbench.\n\n.. code-block:: python\n\n  # Examples for importing (parts of) the extension\n  import cocotbext.EXTNAME\n  from cocotbext import EXTNAME\n  from cocotbext.EXTNAME import MyVerificationClass\n\nCode hosting\n============\n\nThe source code of cocotb extensions can be hosted anywhere.\nIf authors wish to do so, extensions can also be hosted on GitHub in the `cocotb GitHub organization <https://github.com/cocotb>`_ (e.g. ``github.com/cocotb/cocotbext-EXTNAME``).\nPlease file a `GitHub issue in the cocotb repository <https://github.com/cocotb/cocotb/issues>`_ if you'd like to discuss that.\n\nNote that hosting extensions within the cocotb organization is decided on a case-by-case basis by the cocotb maintainers.\nAt least, a cocotb-hosted extension needs to fulfill the following requirements:\n\n* It needs tests that can be run in order to see that the extension works\n  and continues to work as cocotb itself changes, especially when a new release is upcoming.\n* It needs documentation (preferably in Sphinx) so that users know how to use the extension.\n* We must have access to the PyPi project so that we can continue to upload new releases\n  in case the extension maintainer (\"Owner\") becomes unresponsive.\n"
  },
  {
    "path": "docs/source/further_resources.rst",
    "content": "*****************\nFurther Resources\n*****************\n\nWe have a list of talks and papers, libraries and examples at our Wiki page\n`Further Resources <https://github.com/cocotb/cocotb/wiki/Further-Resources>`_.\nFeel free to add links to cocotb-related content that we are still missing!\n"
  },
  {
    "path": "docs/source/genindex.rst",
    "content": "..\n   This file is a placeholder and will be replaced by Sphinx\n   See https://stackoverflow.com/a/42310803\n\n*****\nIndex\n*****\n"
  },
  {
    "path": "docs/source/glossary.rst",
    "content": ".. _glossary:\n\nGlossary\n========\n\n.. glossary::\n   :sorted:\n\n   BFM\n      Bus Functional Model\n\n   blocking function\n      A function that blocks the caller until the function finishes.\n      This is typically a regular function,\n      but sometimes involves calls to threaded code which blocks execution for an indeterminate amount of time.\n      See also the :term:`Python glossary <python:function>`.\n\n   coroutine function\n      The definition of a function that, when called, returns a coroutine object.\n      Implemented using :keyword:`async` functions.\n      See also the :term:`Python glossary <python:coroutine function>`.\n\n   coroutine\n      The result of calling a :term:`coroutine function`.\n      Coroutines are not run immediately, you must either\n      :keyword:`await` on them which blocks the awaiting coroutine until it is finished;\n      or turn them into a :term:`task`, which can be run concurrently.\n      See also the :term:`Python glossary <python:coroutine>`.\n\n   task\n      A :term:`coroutine` that can be run concurrently to other tasks.\n\n   trigger\n      An :term:`awaitable` object which when :keyword:`awaited <await>` will block the current :term:`task` until its condition is met.\n      For example, a :class:`RisingEdge(dut.clk) <cocotb.triggers.RisingEdge>` trigger will block until the next rising edge of the ``dut.clk`` signal.\n\n   DUT\n      Design under Test\n\n   DUV\n      Design under Verification\n\n   FLI\n      Foreign Language Interface. Mentor Graphics' equivalent to :term:`VHPI`.\n\n   GPI\n      Generic Procedural Interface, cocotb's abstraction over :term:`VPI`, :term:`VHPI`, and :term:`FLI`.\n\n   HAL\n      Hardware Abstraction Layer\n\n   HDL\n      Hardware Description Language\n\n   MDV\n      Metric-driven Verification\n\n   RTL\n      Register Transfer Level\n\n   UVM\n      Universal Verification Methodology\n\n   VHPI\n      The VHDL Procedural Interface, an application-programming interface to VHDL tools.\n\n   VIP\n      Verification IP\n\n   VPI\n      The Verilog Procedural Interface, an application-programming interface to (System)Verilog tools.\n      Its original name was \"PLI 2.0\".\n\n   time step\n      A single point in simulated time, comprised of a series of one or more :term:`evaluation cycles <evaluation cycle>`.\n\n   evaluation cycle\n      One iteration of the evaluation loop in a :term:`time step`.\n      Occurs when HDL or cocotb code is executed in reaction to events, such as simulated time advancing or signal or variable values changing.\n      The executed code tends to create more events, leading to the next evaluation cycle.\n\n   inertial deposit\n      :term:`Depositing <deposit>` a value on a signal or variable at the end of the current delta cycle.\n\n   no-delay deposit\n      :term:`Depositing <deposit>` a value on a signal or variable immediately.\n\n   driving\n      Continuously :term:`depositing <deposit>` a value to a signal. cocotb cannot drive signals, only deposit or force values.\n\n   deposit\n      Setting the value of a signal or variable once. May be :term:`inertial <inertial deposit>` or :term:`no-delay <no-delay deposit>`.\n\n   force\n      Setting the value to a signal or variable once immediately, then locking it so the value can't change.\n\n   release\n      Setting the value to a signal or variable once immediately, then unlocking it from a previous :term:`force`.\n\n   simulator object\n      An addressable object from the :term:`DUT`. Corresponds to a signal, variable, or hierarchical element in the :term:`HDL` code.\n"
  },
  {
    "path": "docs/source/index.rst",
    "content": "#################\nWelcome to cocotb\n#################\n\n..\n   This documentation tries to follow https://diataxis.fr/\n   Other media about the same topic:\n   - https://ep2018.europython.eu/media/conference/slides/get-your-documentation-right.pdf\n   - https://www.youtube.com/watch?v=t4vKPhjcMZg\n   - A good example: http://docs.django-cms.org/en/latest/contributing/documentation.html#contributing-documentation\n\n   See also https://github.com/cocotb/cocotb/wiki/Howto:-Writing-Documentation\n\n***************\nWhat is cocotb?\n***************\n\ncocotb enables users to test and verify their chip designs in `Python <https://www.python.org>`_ as opposed to VHDL, (System)Verilog, or other EDA-specific languages.\n\n\n***********\nWhy cocotb?\n***********\n\ncocotb was specifically designed to lower the overhead of creating a testbench.\nBut it is still capable of -- and encourages -- reuse and randomized testing for building larger, more complex testbenches.\n\nPython offers many advantages over languages traditionally used for test and verification, such as VHDL or (System)Verilog.\n\n* Writing Python is **fast** - it's a very productive language.\n* It's **easy** to interface to other languages from Python.\n* Python has a huge library of existing code to **reuse**.\n* Python is **interpreted** - tests can be edited and re-run without having to recompile the design or the testbench.\n* Python is **popular** - far more engineers know Python than SystemVerilog or VHDL.\n\ncocotb supports :ref:`most popular simulators <simulator-support>` on :ref:`most relevant platforms <platform-support>`.\n\nWhen writing cocotb testbenches, users will typically not have to write any :term:`HDL`.\n\ncocotb has built-in support for integrating with continuous integration systems,\nsuch as Jenkins, GitLab, etc. through standardized, machine-readable test reporting formats.\n\ncocotb is provided free of charge under the `BSD License <https://en.wikipedia.org/wiki/BSD_licenses#3-clause_license_(%22BSD_License_2.0%22,_%22Revised_BSD_License%22,_%22New_BSD_License%22,_or_%22Modified_BSD_License%22)>`_\nand is hosted publicly on `GitHub <https://github.com/cocotb/cocotb>`_.\n\n\n*********************\nHow does cocotb work?\n*********************\n\ncocotb is a **co**\\ routine-based **co**\\ simulation **t**\\ est\\ **b**\\ ench environment.\n\nThis means that when the design is simulated, cocotb runs as a cosimulation using one of the procedural interfaces (:term:`VPI`, :term:`VHPI`, or :term:`FLI`).\nA Python interpreter is embedded into the running simulator process to provide a Python execution environment.\nA :doc:`Python library <library_reference>`\nand `coroutine <https://en.wikipedia.org/wiki/Coroutine>`_\\ -based concurrency system are built on top of the procedural interfaces to interact with the simulated design in a Pythonic way.\n\n.. image:: diagrams/svg/cocotb_overview.svg\n\n\n**************\nWho is cocotb?\n**************\n\ncocotb is a Free and Open Source project and is developed collaboratively by its `contributors <https://github.com/cocotb/cocotb/graphs/contributors>`_ and :ref:`maintainers`.\ncocotb has many serious commercial users and sponsors.\nSee `cocotb.org <https://cocotb.org>`_ for more details.\n\n..\n   Tutorials - lessons that take the reader by the hand through a series of steps to complete a project\n   (Example: kid cooking; learning-oriented)\n\n   - learning by doing\n   - getting started\n   - inspiring confidence\n   - repeatability\n   - immediate sense of achievement\n   - concreteness, not abstraction\n   - minimum necessary explanation\n   - no distractions\n\n.. toctree::\n   :maxdepth: 1\n   :caption: Tutorials\n   :name: tutorials\n   :hidden:\n\n   install\n   quickstart\n   writing_testbenches\n   runner\n   coroutines\n   triggers\n   pytest\n   examples\n\n\n..\n   How-To Guides - guides that take the reader through the steps required to solve a common problem\n   (Example: recipe; problem-oriented)\n\n   - a series of steps\n   - a focus on the goal\n   - addressing a specific question\n   - no unnecessary explanation\n   - a little flexibility\n   - practical usability\n   - good naming\n\n.. toctree::\n   :maxdepth: 1\n   :caption: How-to Guides\n   :name: howto_guides\n   :hidden:\n\n   install_devel\n   custom_flows\n   extensions\n   upgrade-2.0\n   update_indexing\n   rotating_logger\n   profiling\n   coverage\n\n\n.. todo::\n   - Add IPython section\n   - How to deal with existing Verification IP?\n   - Point to https://github.com/cocotb/cocotb/wiki/Code-Examples\n\n\n..\n   Explanation (Background, Discussions) - discussions that clarify and illuminate a particular topic\n   (Example: history of cooking; understanding-oriented)\n\n   - giving context\n   - explaining why\n   - multiple examples, alternative approaches\n   - making connections\n   - no instruction or technical description\n\n.. toctree::\n   :maxdepth: 1\n   :caption: Key topics\n   :name: key_topics\n   :hidden:\n\n   troubleshooting\n   timing_model\n\n.. todo::\n   - Move section \"How does cocotb work?\" from Introduction to here\n   - Add some info from :doc:`coroutines`\n   - Add GPI section\n\n\n..\n   Reference - technical descriptions of the machinery and its operation\n   (Example: Wikipedia pages of ingredients; information-oriented)\n\n   - structure\n   - consistency\n   - description\n   - accuracy\n\n.. toctree::\n   :maxdepth: 1\n   :caption: Reference\n   :name: reference\n   :hidden:\n\n   building\n   Python Code Library Reference <library_reference>\n   GPI Library Reference <library_reference_c>\n   simulator_support\n   platform_support\n   refcard\n\n.. toctree::\n   :maxdepth: 1\n   :caption: Development & Community\n   :name: development_community\n   :hidden:\n\n   support\n   contributing\n   developing\n   maintaining\n   contributors\n   roadmap\n   release_notes\n   further_resources\n\n.. todo::\n   - merge `further_resources` into Contributing\n\n.. toctree::\n   :maxdepth: 1\n   :caption: Index\n   :name: index\n   :hidden:\n\n   Classes, Methods, Variables etc. <genindex>\n   Python Modules <py-modindex>\n   glossary\n"
  },
  {
    "path": "docs/source/install.rst",
    "content": ".. _install:\n\n************\nInstallation\n************\n\n.. note::\n   If you want to install the **development version** of cocotb,\n   `instructions are here <https://docs.cocotb.org/en/development/install_devel.html>`_.\n\n:command:`pip` is the officially supported and recommended package manager for installing cocotb.\ncocotb is also packaged by third parties to support installation via alternative package managers; see :ref:`install-package-manager` for details.\nFor more installation options, please visit `our Wiki <https://github.com/cocotb/cocotb/wiki/Tier-2-Setup-Instructions>`_.\n\n\nInstall with ``pip``\n====================\n\n\n.. _install-prerequisites:\n\nInstall Prerequisites\n---------------------\n\nThe current stable version of cocotb requires:\n\n* Python 3.9+\n* libpython 3.9+ which matches the Python version\n\nThe installation instructions vary depending on your operating system:\n\n.. tab-set::\n\n   .. tab-item:: Windows - Conda\n\n      We recommend users who are more comfortable with native Windows development to use `Conda <https://conda.io/>`_.\n      Conda is an open-source package and environment management system available on Windows.\n\n      Download and install `Miniconda <https://docs.conda.io/en/latest/miniconda.html>`_ from https://conda.io/.\n      From an Anaconda Prompt, use the following line to install a compiler (GCC or Clang) and GNU Make:\n\n      .. code-block:: bash\n\n          conda install -c msys2 m2-base m2-make\n\n   .. tab-item:: Windows - WSL\n\n      We recommend users who are running Windows and who are more comfortable with a Unix shell,\n      or who have legacy Makefile-based projects,\n      to use Windows Subsystem for Linux (WSL).\n\n      Follow the `Microsoft WSL installation guide <https://docs.microsoft.com/en-us/windows/wsl/install>`_ to install WSL\n      with a :ref:`supported Linux distribution <supported-linux-distributions>`.\n      Then follow the appropriate Linux installation instructions for cocotb.\n\n   .. tab-item:: Linux - Debian\n\n      In a terminal, run\n\n      .. code-block:: bash\n\n          sudo apt-get install make python3 python3-pip libpython3-dev\n\n   .. tab-item:: Linux - Red Hat\n\n      In a terminal, run\n\n      .. code-block:: bash\n\n          sudo yum install make python3 python3-pip python3-libs\n\n   .. tab-item:: macOS\n\n      We recommend using the `Homebrew <https://brew.sh/>`_ package manager.\n      After installing it, run the following line in a terminal:\n\n      .. code-block:: bash\n\n           brew install python\n\n\n.. _install-cocotb:\n.. _installation-via-pip:\n\nInstall cocotb\n--------------\n\n.. only:: is_release_build\n\n    You are reading the documentation for cocotb |version|.\n    To install this version, or any later compatible version, run\n\n    .. parsed-literal::\n\n        pip install \"cocotb~=\\ |version|\\ \"\n\n.. only:: not is_release_build\n\n    The latest **stable version** of cocotb can be installed by running\n\n    .. code-block:: bash\n\n        pip install cocotb\n\n.. note::\n\n    If your user does not have permissions to install cocotb using the instructions above,\n    try adding the ``--user`` option to :command:`pip`\n    (see `the pip documentation <https://pip.pypa.io/en/stable/user_guide/#user-installs>`_).\n\n.. warning::\n\n    :command:`pip` may belong to a different Python installation to what you expect.\n    Use ``pip -V`` to check.\n    If this prints \"(python 2.7)\", use :command:`pip3` or ``python3 -m pip`` in place of :command:`pip` in the command shown.\n\n\nVerify Installation\n-------------------\n\nAfter installation, you should be able to execute the following command:\n\n.. code-block:: bash\n\n    cocotb-config --version\n\nIf the command is not found, you need to append its location to the ``PATH`` environment variable.\n\nVerify the version printed matches the version you intended to install.\n\n\n.. _install-package-manager:\n\nInstallation via Alternative Package Managers\n=============================================\n\n.. tab-set::\n\n   .. tab-item:: Guix\n\n      In a terminal, run\n\n        .. code-block:: bash\n\n\t        guix install python-cocotb\n"
  },
  {
    "path": "docs/source/install_devel.rst",
    "content": ".. _install-devel:\n\n**********************************\nInstalling the Development Version\n**********************************\n\n.. note::\n\n   If you want to follow the instructions on this page,\n   make sure you are reading the\n   `development version <https://docs.cocotb.org/en/development/install_devel.html>`_.\n\n   Once you install the development version,\n   you should keep reading the\n   `matching documentation <https://docs.cocotb.org/en/development/>`_.\n\n:command:`pip` is the officially supported and recommended package manager for installing the development version of cocotb.\nCurrently there are no alternative package managers that provide the development version of cocotb.\nBelow are the instructions for installing the development version of cocotb using :command:`pip`.\n\n\nInstall with ``pip``\n====================\n\n\nInstall Prerequisites\n---------------------\n\nThe development version of cocotb requires building C++ extensions.\nThis requires Python development headers, a C++ compiler, and C++ development libraries.\n\n* Python 3.9+\n* libpython 3.9+ to match the executable Python version\n* Python development packages\n* GCC 4.8.1+, Clang 3.3+ or Microsoft Visual C++ 14.21+ and associated development packages\n* On Linux: A static build of the C++ standard library ``libstdc++``.\n  Some distributions include the static library in their default packages (e.g. Debian/Ubuntu),\n  others (e.g. Red Hat) require the installation of a package typically named ``libstdc++-static``.\n\nThe installation instructions vary depending on your operating system:\n\n.. tab-set::\n\n   .. tab-item:: Windows - Conda\n\n      We recommend users who are more comfortable with native Windows development to use `Conda <https://conda.io/>`_.\n      Conda is an open-source package and environment management system available on Windows.\n\n      Download and install `Miniconda <https://docs.conda.io/en/latest/miniconda.html>`_ from https://conda.io/.\n      From an Anaconda Prompt, use the following line to install a compiler (GCC or Clang) and GNU Make:\n\n      .. code-block:: bash\n\n          conda install -c msys2 m2-base m2-make\n\n   .. tab-item:: Windows - WSL\n\n      We recommend users who are running Windows and who are more comfortable with a Unix shell,\n      or who have legacy Makefile-based projects,\n      to use Windows Subsystem for Linux (WSL).\n\n      Follow the `Microsoft WSL installation guide <https://docs.microsoft.com/en-us/windows/wsl/install>`_ to install WSL\n      with a :ref:`supported Linux distribution <supported-linux-distributions>`.\n      Then follow the appropriate Linux installation instructions for cocotb.\n\n   .. tab-item:: Linux - Debian/Ubuntu\n\n      In a terminal, run\n\n      .. code-block:: bash\n\n          sudo apt-get install make gcc g++ python3 python3-dev python3-pip\n\n   .. tab-item:: Linux - Red Hat\n\n      If you are using RHEL9, it might be necessary to add the CodeReady Linux Builder repository\n      to be able to install ``libstdc++-static``.\n      To add this repo, run in a terminal\n\n      .. code-block:: bash\n\n          sudo subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms\n\n      Then, run\n\n      .. code-block:: bash\n\n          sudo yum install make gcc gcc-c++ libstdc++-devel libstdc++-static python3 python3-devel python3-pip\n\n   .. tab-item:: macOS\n\n      .. code-block:: bash\n\n           brew install python\n\n\nInstall cocotb\n--------------\n\nThe development version of cocotb can be installed by running the following command:\n\n.. code-block:: bash\n\n    pip install git+https://github.com/cocotb/cocotb@master\n\nAlternatively, if you have cloned the cocotb repository locally, you can install it by running:\n\n.. code-block:: bash\n\n    pip install ./path/to/cocotb\n\nFor testing Python changes without reinstalling, you can use the editable install option.\nThis requires that you have cloned the cocotb repository locally.\n\n.. code-block:: bash\n\n    pip install -e ./path/to/cocotb\n\n.. note::\n\n    If your user does not have permissions to install cocotb using the instructions above,\n    try adding the ``--user`` option to ``pip``\n    (see `the pip documentation <https://pip.pypa.io/en/stable/user_guide/#user-installs>`_).\n\n.. warning::\n\n    ``pip`` may belong to a different Python installation to what you expect.\n    Use ``pip -V`` to check.\n    If this prints \"(python 2.7)\", use ``pip3`` or ``python3 -m pip`` in place of ``pip`` in the command shown.\n\n\nPassing Flags to C++ Library Builds\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nYou may want to pass additional flags when building cocotb's C++ libraries.\nThese libraries are built during the ``pip install`` call when installing from a source distribution,\ne.g. a local clone, from Github directly, or from an sdist tarball.\n\nYou can pass additional options to the library build process using the\n`conventional variables <https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html>`_\nfor C and C++ compilation and linking: ``CFLAGS``, ``CPPFLAGS``, and ``LDFLAGS`` when building with GCC or Clang,\nand `CL <https://learn.microsoft.com/en-us/cpp/build/reference/cl-environment-variables>`_ when building with MSVC.\n\n.. code-block:: shell\n\n    $ CFLAGS=\"-O2 -g\" LDFLAGS=\"-O2 -g\" pip install git+https://github.com/cocotb/cocotb@master\n\n.. note::\n\n    ``CXXFLAGS``, ``LDLIBS`` are not supported by the distutils/pip build system.\n\n\nVerify Installation\n-------------------\n\nAfter installation, you should be able to execute the following command:\n\n.. code-block:: bash\n\n    cocotb-config --version\n\nIf the command is not found, you need to append its location to the ``PATH`` environment variable.\n\nVerify the version printed matches the version you intended to install.\n"
  },
  {
    "path": "docs/source/library_reference.rst",
    "content": "*****************\nLibrary Reference\n*****************\n\n.. spelling:word-list::\n   AXIProtocolError\n   BusDriver\n   De\n   Re\n   ReadOnly\n   args\n   cbNextSimTime\n   ing\n   sim\n   stdout\n   un\n\n.. module:: cocotb\n\n.. _api-pytest-plugin:\n\nPytest Plugin\n=============\n\n\n.. _api-pytest-plugin-fixtures:\n\nFixtures\n--------\n\n.. module:: cocotb_tools.pytest.plugin\n\n.. autofixture:: dut\n\n.. autofixture:: hdl_session\n\n.. autofixture:: hdl\n\n\n.. _api-pytest-plugin-markers:\n\nMarkers\n-------\n\n.. module:: cocotb_tools.pytest.mark\n\n.. autodecorator:: cocotb_runner\n\n.. autodecorator:: cocotb_test\n\n.. autodecorator:: cocotb_timeout\n\n.. autodecorator:: cocotb_library\n\n.. autodecorator:: cocotb_sources\n\n.. autodecorator:: cocotb_defines\n\n.. autodecorator:: cocotb_includes\n\n.. autodecorator:: cocotb_parameters\n\n.. autodecorator:: cocotb_plusargs\n\n.. autodecorator:: cocotb_env\n\n.. autodecorator:: cocotb_seed\n\n.. autodecorator:: cocotb_timescale\n\n.. autodecorator:: cocotb_always\n\n.. autodecorator:: cocotb_clean\n\n.. autodecorator:: cocotb_waves\n\n.. autodecorator:: cocotb_build_args\n\n.. autodecorator:: cocotb_elab_args\n\n.. autodecorator:: cocotb_test_args\n\n.. autodecorator:: cocotb_pre_cmd\n\n.. _api-pytest-plugin-hdl:\n\n\nHDL Fixture Request\n-------------------\n\n.. module:: cocotb_tools.pytest.hdl\n\n.. autoclass:: HDL\n    :members:\n\n\n.. _api-pytest-plugin-hook-specs:\n\nHook Specifications\n-------------------\n\n.. module:: cocotb_tools.pytest.hookspecs\n\n.. autofunction:: pytest_cocotb_make_hdl\n\n.. autofunction:: pytest_cocotb_make_runner\n\n\n.. _api-runner:\n\nPython Test Runner\n==================\n\n.. warning::\n    Python runners and associated APIs are an experimental feature and subject to change.\n\n.. module:: cocotb_tools.runner\n    :synopsis: Build HDL and run cocotb tests.\n\n.. autofunction:: get_runner\n\n.. autodata:: SUPPORTED_RUNNERS\n   :no-value:\n\n.. autoclass:: Runner\n    :members:\n\n.. autoclass:: VHDL\n\n.. autoclass:: Verilog\n\n.. autoclass:: VerilatorControlFile\n\n.. autodata:: MAX_PARALLEL_BUILD_JOBS\n\n.. envvar:: GUI\n\n    Type: :ref:`env-boolean`\n\n    Default: :data:`False`\n\n    Enable the GUI mode in the simulator (if supported).\n\n.. envvar:: WAVES\n\n    Type: :ref:`env-boolean`\n\n    Default: :data:`False`\n\n    Enable wave traces dump for the Aldec Riviera-PRO, Mentor Graphics Questa, and Icarus Verilog simulators.\n    To get wave traces in Verilator see :ref:`sim-verilator-waveforms`.\n\n.. envvar:: COCOTB_WAVEFORM_VIEWER\n\n    Type: :ref:`env-string`\n\n    The name of the waveform viewer executable to use (like ``surfer``) when GUI mode is enabled\n    for simulators that do not have a built-in waveform viewer (like Verilator).\n    The executable name will be called with the name of the waveform file as the argument.\n\n.. envvar:: LIBPYTHON_LOC\n\n    Type: :ref:`env-string`\n\n    The absolute path to the Python library associated with the current Python installation;\n    i.e. ``libpython.so`` or ``python.dll`` on Windows.\n    This is determined with ``cocotb-config --libpython`` during build.\n\n    This is only used if :envvar:`GPI_USERS` is not already defined by the user.\n\n.. envvar:: SIM_CMD_PREFIX\n\n    Prefix for simulation command invocations.\n\n    This can be used to add environment variables or other commands before the invocations of simulation commands.\n    For example, ``export SIM_CMD_PREFIX='LD_PRELOAD=\"foo.so bar.so\"'`` can be used to force a particular library to load.\n    Or, ``export SIM_CMD_PREFIX='gdb --args'`` to run the simulation with the GDB debugger.\n\n    .. versionadded:: 1.6\n\n    .. versionadded:: 2.1\n        Support for this variable was added to Python Runners.\n\n.. envvar:: SIM_CMD_SUFFIX\n\n    Suffix for simulation command invocations.\n    Typically used to redirect simulator ``stdout`` and ``stderr``:\n\n    .. code-block:: bash\n\n        # Prints simulator stdout and stderr to the terminal\n        # as well as capture it all in a log file \"sim.log\".\n        export SIM_CMD_SUFFIX=\"2>&1 | tee sim.log\"\n\n    .. versionadded:: 2.0\n\n    .. versionadded:: 2.1\n        Support for this variable was added to Python Runners.\n\n\n.. _api-runner-sim:\n\nSimulator Runners\n-----------------\n\n.. autoclass:: Icarus\n\n.. autoclass:: Verilator\n\n.. autoclass:: Riviera\n\n.. autoclass:: Questa\n\n.. autoclass:: Xcelium\n\n.. autoclass:: Ghdl\n\n.. autoclass:: Nvc\n\n.. autoclass:: Vcs\n\n.. autoclass:: Dsim\n\nResults\n-------\n\n.. autofunction:: get_results\n\nFile Utilities\n--------------\n\n.. autofunction:: get_abs_path\n\n.. autofunction:: outdated\n\n\n.. _writing-tests:\n\nMarking and Generating Tests\n============================\n\n.. currentmodule:: None\n\n.. autofunction:: cocotb.test\n\n.. autofunction:: cocotb.parametrize\n\n.. autofunction:: cocotb.skipif\n\n.. autofunction:: cocotb.xfail\n\n.. autoclass:: cocotb.regression.TestFactory\n    :members:\n    :member-order: bysource\n\n.. autoclass:: cocotb.regression.SimFailure\n\n\nDiscovering Tests\n=================\n\n.. envvar:: COCOTB_MAX_FAILURES\n\n    Type: :ref:`_env-int`\n\n    Limits the number of test failures allowed during a regression run.\n\n    If set then if the number of failed tests reaches this value, the regression\n    is terminated early and no further tests are executed.\n\n    If not set, all tests are executed regardless of failures.\n\n    .. versionadded:: 2.1\n\n.. envvar:: COCOTB_TEST_MODULES\n\n    Type: :ref:`env-list`\n\n    The name of the Python module(s) to search for test functions -\n    if your tests are in a file called ``test_mydesign.py``, ``COCOTB_TEST_MODULES`` would be set to ``test_mydesign``.\n    Multiple modules can be specified using a comma-separated string.\n    For example: ``COCOTB_TEST_MODULES=\"directed_tests,random_tests,error_injection_tests\"``.\n    All tests will be run from each specified module in order of the module's appearance in this list.\n\n    This is the only environment variable that is **required** for cocotb, all others are optional.\n\n    .. versionchanged:: 2.0\n\n        :envvar:`MODULE` is renamed to :envvar:`COCOTB_TEST_MODULES`.\n\n    .. deprecated:: 2.0\n\n        :envvar:`MODULE` is a deprecated alias and will be removed.\n\n.. _testcase:\n\n.. envvar:: COCOTB_TESTCASE\n\n    Type: :ref:`env-list`\n\n    A comma-separated list of tests to run.\n    Does an exact match on the test name.\n\n    .. versionchanged:: 2.0\n\n        :envvar:`TESTCASE` is renamed to :envvar:`COCOTB_TESTCASE`.\n\n    .. deprecated:: 2.0\n\n        :envvar:`TESTCASE` is a deprecated alias and will be removed.\n\n    .. deprecated:: 2.0\n\n        Use :envvar:`COCOTB_TEST_FILTER` instead.\n\n        If matching only the exact test name is desired, use the regular expression anchor character ``$``.\n        For example, ``my_test$`` will match ``my_test``, but not ``my_test_2``.\n\n        To run multiple tests, use regular expression alternations.\n        For example, ``my_test|my_other_test``.\n\n    .. versionchanged:: 2.0\n\n        Previously, if more than one test matched a test name in the :envvar:`TESTCASE` list,\n        only the first test that matched that test name in the :envvar:`COCOTB_TEST_MODULES` list was run.\n        Now, all tests that match the test name across all :envvar:`COCOTB_TEST_MODULES`\\ s are run.\n\n    .. warning::\n\n        Only one of :envvar:`COCOTB_TESTCASE` or :envvar:`COCOTB_TEST_FILTER` should be used.\n\n\n.. envvar:: COCOTB_TEST_FILTER\n\n    Type: :ref:`env-string`\n\n    A regular expression matching names of test function(s) to run.\n    If this variable is not defined cocotb discovers and executes all functions decorated with the :class:`cocotb.test` decorator in the supplied :envvar:`COCOTB_TEST_MODULES` list.\n\n    .. versionadded:: 2.0\n\n    .. warning::\n\n        Only one of :envvar:`COCOTB_TESTCASE` or :envvar:`COCOTB_TEST_FILTER` should be used.\n\n.. envvar:: COCOTB_LIST_TESTS\n\n    Type: :ref:`env-boolean`\n\n    If defined, list the tests that would be run, in the order they would be run, without running them.\n\n    .. versionadded:: 2.1\n\n.. envvar:: COCOTB_RESULTS_FILE\n\n    Type: :ref:`env-string`\n\n    Default: :file:`results.xml`\n\n    Name of the file in which xUnit XML test results are to be stored.\n\n    .. versionadded:: 1.3\n\n.. envvar:: COCOTB_REWRITE_ASSERTION_FILES\n\n    Type: :ref:`env-string`\n\n    Default: ``*.py``\n\n    Select the Python files to apply ``pytest``'s assertion rewriting to.\n    This is useful to get more informative assertion error messages in cocotb tests.\n    Specify using a space-separated list of file globs, e.g. ``test_*.py testbench_common/**/*.py``.\n    Set to the empty string to disable assertion rewriting.\n    Defaults to ``*.py`` (all Python files, even third-party modules like ``scipy``).\n\n    .. versionadded:: 2.0\n\nTest Management\n===============\n\n.. currentmodule:: None\n\n.. autofunction:: cocotb.end_test\n\n.. autofunction:: cocotb.pass_test\n\n.. _task-management:\n\nTask Management\n===============\n\n.. currentmodule:: None\n\n.. autofunction:: cocotb.start_soon\n\n.. autofunction:: cocotb.start\n\n.. autofunction:: cocotb.create_task\n\n.. module:: cocotb.task\n    :synopsis: Tools for concurrency.\n\n.. autoclass:: ResultType\n\n.. autoclass:: Task\n    :members:\n\n.. autofunction:: current_task\n\nBridging through non-`async` code\n---------------------------------\n\n.. autofunction:: bridge\n\n.. autofunction:: resume\n\n\nHDL Datatypes\n=============\n\nThese are a set of datatypes that model the behavior of common HDL datatypes.\n\n.. versionadded:: 1.6\n\n.. module:: cocotb.types\n    :synopsis: Types for dealing with digital signal values.\n\n.. autoclass:: Logic\n    :members:\n\n.. autoclass:: Bit\n    :members:\n\n.. autoclass:: Range\n    :members:\n    :exclude-members: count, index\n\n.. autoclass:: AbstractArray\n    :members:\n\n.. autoclass:: AbstractMutableArray\n    :members:\n    :show-inheritance:\n\n.. autoclass:: Array\n    :members:\n    :inherited-members:\n\n.. autoclass:: LogicArray\n    :members:\n    :inherited-members:\n\n.. envvar:: COCOTB_RESOLVE_X\n\n    Type: :ref:`env-string`\n\n    Defines how to resolve bits with a value of ``X``, ``Z``, ``U``, ``W``, or ``-`` when being converted to integer.\n    Valid settings are:\n\n    ``error``\n        Resolves nothing.\n    ``weak``\n        Resolves ``L`` to ``0`` and ``H`` to ``1``.\n    ``zeros``\n        Like ``weak``, but resolves all other non-\\ ``0``\\ /\\ ``1`` values to ``0``.\n    ``ones``\n        Like ``weak``, but resolves all other non-\\ ``0``\\ /\\ ``1`` values to ``1``.\n    ``random``\n        Like ``weak``, but resolves all other non-\\ ``0``\\ /\\ ``1`` values randomly to either ``0`` or ``1``.\n\n    There is also a slight difference in behavior of ``bool(logic)`` when this environment variable is set.\n    When this variable is set, ``bool(logic)`` treats all non-\\ ``0``\\ /\\ ``1`` values as equivalent to ``0``.\n    When this variable is *not* set, ``bool(logic)`` will fail on non-\\ ``0``\\ /\\ ``1`` values.\n\n    .. warning::\n        Using this feature is *not* recommended.\n\n    .. deprecated:: 2.0\n        The previously accepted values ``VALUE_ERROR``, ``ZEROS``, ``ONES``, and ``RANDOM`` are deprecated.\n\n.. _triggers:\n\nTriggers\n========\n\n.. module:: cocotb.triggers\n\n.. autofunction:: current_gpi_trigger\n\n.. _edge-triggers:\n\nEdge Triggers\n-------------\n\n.. autoclass:: RisingEdge\n    :members:\n\n.. autoclass:: FallingEdge\n    :members:\n\n.. autoclass:: ClockCycles\n    :members:\n\n.. autoclass:: ValueChange\n    :members:\n\n.. autoclass:: Edge\n    :members:\n\n\nTiming Triggers\n---------------\n\n.. autoclass:: Timer\n    :members:\n\n    .. autoattribute:: round_mode\n\n.. autoclass:: ReadOnly\n    :members:\n\n.. autoclass:: ReadWrite\n    :members:\n\n.. autoclass:: NextTimeStep\n    :members:\n\n\nConcurrency Triggers\n--------------------\n\nTriggers dealing with Tasks or running multiple Tasks concurrently.\n\n.. currentmodule:: None\n\n.. autoclass:: cocotb.task.Join\n    :members:\n\n.. autoclass:: cocotb.task.TaskComplete\n    :members:\n\n.. currentmodule:: cocotb.triggers\n\n.. autoclass:: NullTrigger\n    :members:\n\n.. autoclass:: Combine\n    :members:\n\n.. autoclass:: First\n    :members:\n\n.. autofunction:: wait\n\n.. autofunction:: gather\n\n.. autofunction:: select\n\n.. autoclass:: TaskManager\n    :members:\n\n\nSynchronization Triggers\n------------------------\n\nThe following objects are not :class:`Trigger`\\ s themselves, but contain methods that can be used as triggers.\nThey are used to synchronize coroutines with each other.\n\n.. autoclass:: Event\n    :members:\n    :member-order: bysource\n\n.. autoclass:: Lock\n    :members:\n    :member-order: bysource\n\n.. autoclass:: SimTimeoutError\n\n.. autofunction:: with_timeout\n\n\nAbstract Triggers\n-----------------\n\nThe following are internal classes used within ``cocotb``.\n\n.. autoclass:: Trigger\n    :members:\n    :member-order: bysource\n\n.. autoclass:: GPITrigger\n    :members:\n    :member-order: bysource\n\n.. autoclass:: Waitable\n    :members:\n    :member-order: bysource\n    :private-members:\n\n\nTest Utilities\n==============\n\nClock Driver\n------------\n\n.. automodule:: cocotb.clock\n    :members:\n    :member-order: bysource\n    :synopsis: A single-ended clock driver.\n\nAsynchronous Queues\n-------------------\n\n.. automodule:: cocotb.queue\n    :members:\n    :inherited-members:\n    :member-order: bysource\n    :synopsis: Collection of asynchronous queues.\n\n\nSimulation Time Utilities\n=========================\n\n.. automodule:: cocotb.simtime\n    :members:\n    :member-order: bysource\n    :synopsis: Tools for dealing with simulated time.\n\n.. automodule:: cocotb.utils\n    :members:\n    :member-order: bysource\n    :synopsis: Tools for dealing with simulated time.\n    :ignore-module-all:\n\n.. _logging-reference-section:\n\nLogging\n=======\n\n.. autodata:: cocotb.log\n\n.. module:: cocotb.logging\n    :synopsis: Classes for logging messages from cocotb during simulation.\n\n.. autofunction:: SimLog\n\n.. autofunction:: default_config\n\n.. envvar:: COCOTB_LOG_LEVEL\n\n    Type: :ref:`env-string`\n\n    The default log level of all ``\"cocotb\"`` Python loggers.\n    Valid values are ``TRACE``, ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``, ``CRITICAL``.\n    The default is unset, which means that the log level is inherited from the root logger.\n    This behaves similarly to ``INFO``.\n\n    .. versionchanged:: 2.0\n        The root ``\"gpi\"`` logger level is no longer set when this environment variable is used.\n        Use :envvar:`GPI_LOG_LEVEL` instead.\n\n.. envvar:: GPI_LOG_LEVEL\n\n    Type: :ref:`env-string`\n\n    The default log level of all ``\"gpi\"`` (the low-level simulator interface) loggers,\n    including both Python and the native GPI logger.\n    Valid values are ``TRACE``, ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``, ``CRITICAL``.\n    The default is unset, which means that the log level is inherited from the root logger.\n    This behaves similarly to ``INFO``.\n\n    .. versionadded:: 2.0\n\n.. envvar:: GPI_DEBUG\n\n    Enable additional debug functionality in the GPI.\n    Includes verbose log messages tracing the code execution path through the GPI.\n    The messages are logged at GPI log level ``TRACE``,\n    so :envvar:`GPI_LOG_LEVEL` must be set to ``TRACE`` in order to see\n    tracing messages during early GPI startup.\n\n    .. versionadded:: 2.1\n\nAdding Simulation Time to Logs\n------------------------------\n\n.. autoclass:: SimTimeContextFilter\n    :show-inheritance:\n    :no-members:\n\n.. currentmodule:: None\n\n.. attribute:: logging.LogRecord.created_sim_time\n\n    The result of :func:`~cocotb.simtime.get_sim_time` at the point the log was created (in simulation time).\n    The formatter is responsible for converting this to something like nanoseconds via :func:`~cocotb.simtime.convert`.\n\n    This is added by :class:`~cocotb.logging.SimTimeContextFilter`.\n\n.. currentmodule:: cocotb.logging\n\nLog Formatting\n--------------\n\n.. autoclass:: SimLogFormatter\n    :show-inheritance:\n    :no-members:\n\n.. autoclass:: SimColourLogFormatter\n    :show-inheritance:\n    :no-members:\n\n.. envvar:: COCOTB_REDUCED_LOG_FMT\n\n    Type: :ref:`env-boolean`\n\n    Default: :data:`True`\n\n    Logs will include simulation time, message type (``INFO``, ``WARNING``, ``ERROR``, ...), logger name, and the log message itself.\n    If disabled, the filename and line number where a log function was called will be added between the logger name and the log message.\n\n.. envvar:: COCOTB_LOG_PREFIX\n\n    Type: :ref:`env-string`\n\n    Customize the log message prefix.\n    The value of this variable should be in Python f-string syntax.\n    It has access to the following variables:\n\n    - ``record``: The :class:`~logging.LogRecord` being formatted. This includes the attribute ``created_sim_time``, which is the simulation time in steps.\n    - ``time``: The Python :mod:`time` module.\n    - ``simtime``: The cocotb :mod:`cocotb.simtime` module.\n    - ``simtime_fmt``: Function which, given a ``LogRecord`` and ``TimeUnit``, returns the simulation time in the requested units as a string with the default formatting.\n    - ``ANSI``: The cocotb :class:`cocotb.logging.ANSI` enum, which contains ANSI escape codes for coloring the output.\n    - ``level_color_start``: The ANSI escape code to start highlighting according to the log level.\n    - ``level_color_end``: The ANSI escape code to end highlighting according to the log level.\n    - ``ljust``: A helper function ``ljust(s,c)``, equivalent to ``s.ljust(c)`` after shortening ``s`` from the left to a length at most ``c`` and prepending ``..`` if anything was cut.\n    - ``rjust``: A helper function ``rjust(s,c)``, equivalent to ``s.rjust(c)`` after shortening in the same way as ``ljust``.\n\n    The following example is a color-less version of the default log prefix.\n\n    .. code-block:: shell\n\n        COCOTB_LOG_PREFIX=\"{simtime.convert(record.created_sim_time, 'step', to='ns'):>9}ns {record.levelname:<8} {ljust(record.name, 34)} \"\n\n    .. note::\n        If this variable is set, :envvar:`COCOTB_REDUCED_LOG_FMT` has no effect.\n\n    .. versionadded:: 2.0\n\nLog Coloring\n------------\n\n.. autodata:: strip_ansi\n\n.. autodata:: ANSI\n\n.. envvar:: COCOTB_ANSI_OUTPUT\n\n    Type: :ref:`env-boolean`\n\n    Use this to override the default behavior of annotating cocotb output with\n    ANSI color codes if the output is a terminal (``isatty()``).\n\n    ``COCOTB_ANSI_OUTPUT=1``\n       Forces output to be ANSI-colored regardless of the type of ``stdout`` or the presence of :envvar:`NO_COLOR`.\n    ``COCOTB_ANSI_OUTPUT=0``\n       Suppresses the ANSI color output in the log messages.\n\n.. envvar:: NO_COLOR\n\n    From http://no-color.org,\n\n        Command-line software which adds ANSI color to its output by default should check for a ``NO_COLOR`` environment variable that,\n        when present and not an empty string (regardless of its value), prevents the addition of ANSI color.\n\n\nSimulator Objects\n=================\n\n.. note::\n    \"Handle\" is a legacy term which refers to the fact these objects are implemented using opaque \"handles\" to simulator objects.\n    A better term is :term:`simulator object`.\n\n.. module:: cocotb.handle\n    :synopsis: Tools for discovering and manipulating :term:`simulator objects <simulator object>`.\n\n.. autoclass:: SimHandleBase\n    :members:\n    :member-order: bysource\n\n.. autoenum:: GPIDiscovery\n\n.. autoclass:: HierarchyObject\n    :members:\n    :member-order: bysource\n    :special-members: __len__, __iter__\n    :inherited-members: SimHandleBase\n\n.. autoclass:: HierarchyArrayObject\n    :members:\n    :member-order: bysource\n    :special-members: __len__, __iter__\n    :inherited-members: SimHandleBase\n\n.. autoclass:: ValueObjectBase\n    :members:\n    :member-order: bysource\n    :inherited-members: SimHandleBase\n\n.. autoclass:: ArrayObject\n    :members:\n    :member-order: bysource\n    :special-members: __len__, __iter__\n    :inherited-members: SimHandleBase, ValueObjectBase\n\n.. autoclass:: LogicObject\n    :members:\n    :member-order: bysource\n    :inherited-members: SimHandleBase, ValueObjectBase\n\n.. autoclass:: LogicArrayObject\n    :members:\n    :member-order: bysource\n    :special-members: __len__\n    :inherited-members: SimHandleBase, ValueObjectBase\n\n.. autoclass:: StringObject\n    :members:\n    :member-order: bysource\n    :special-members: __len__\n    :inherited-members: SimHandleBase, ValueObjectBase\n\n.. autoclass:: IntegerObject\n    :members:\n    :member-order: bysource\n    :inherited-members: SimHandleBase, ValueObjectBase\n\n.. autoclass:: RealObject\n    :members:\n    :member-order: bysource\n    :inherited-members: SimHandleBase, ValueObjectBase\n\n.. autoclass:: EnumObject\n    :members:\n    :member-order: bysource\n    :inherited-members: SimHandleBase, ValueObjectBase\n\n.. envvar:: COCOTB_TRUST_INERTIAL_WRITES\n\n    Type: :ref:`env-boolean`\n\n    Defining this variable enables a mode which allows cocotb to trust that VPI/VHPI/FLI inertial writes are applied properly according to the respective standards.\n    This mode can lead to noticeable performance improvements,\n    and also includes some behavioral difference that are considered by the cocotb maintainers to be \"better\".\n    Not all simulators handle inertial writes properly, so use with caution.\n\n    This is achieved by *not* scheduling writes to occur at the beginning of the ``ReadWrite`` mode,\n    but instead trusting that the simulator's inertial write mechanism is correct.\n    This allows cocotb to avoid a VPI callback into Python to apply writes.\n\n    .. note::\n        This flag is enabled by default for the GHDL, NVC and Verilator simulators.\n        More simulators may enable this flag by default in the future as they are gradually updated to properly apply inertial writes according to the respective standard.\n\n    .. note::\n        To test if your simulator behaves correctly with your simulator and version,\n        first clone the cocotb github repo and run:\n\n        .. code-block::\n\n            cd tests/test_cases/test_inertial_writes\n            make simulator_test SIM=<your simulator here> TOPLEVEL_LANG=<vhdl or verilog>\n\n        If the tests pass, your simulator and version apply inertial writes as expected and you can turn on :envvar:`COCOTB_TRUST_INERTIAL_WRITES`.\n\n.. _assignment-methods:\n\nAssignment Methods\n------------------\n\n.. autoclass:: Deposit\n\n.. autoclass:: Immediate\n\n.. autoclass:: Force\n\n.. autoclass:: Freeze\n\n.. autoclass:: Release\n\nMiscellaneous\n=============\n\nOther Runtime Information\n-------------------------\n\n.. currentmodule:: None\n\n.. autodata:: cocotb.__version__\n\n.. autodata:: cocotb.argv\n\n.. autodata:: cocotb.plusargs\n\n.. envvar:: COCOTB_PLUSARGS\n\n    Type: :ref:`env-string`\n\n      \"Plusargs\" are options that are starting with a plus (``+``) sign.\n      They are passed to the simulator and are also available within cocotb as :data:`cocotb.plusargs`.\n      In the simulator, they can be read by the Verilog/SystemVerilog system functions\n      ``$test$plusargs`` and ``$value$plusargs``.\n\n    .. versionchanged:: 2.0\n\n        :envvar:`PLUSARGS` is renamed to :envvar:`COCOTB_PLUSARGS`.\n\n    .. deprecated:: 2.0\n\n        :envvar:`PLUSARGS` is a deprecated alias and will be removed.\n\n.. autodata:: cocotb.top\n\n.. envvar:: COCOTB_TOPLEVEL\n\n    Type: :ref:`env-string`\n\n    Use this to indicate the instance in the hierarchy to use as the :term:`DUT`.\n    If this isn't defined then the first root instance is used.\n    Leading and trailing whitespace are automatically discarded.\n\n    The DUT is available in cocotb tests as a Python object at :data:`cocotb.top`;\n    and is also passed to all cocotb tests as the :ref:`first and only parameter <quickstart_creating_a_test>`.\n\n    .. versionchanged:: 1.6 Strip leading and trailing whitespace\n\n    .. versionchanged:: 2.0\n\n        :envvar:`TOPLEVEL` is renamed to :envvar:`COCOTB_TOPLEVEL`.\n\n    .. deprecated:: 2.0\n\n        :envvar:`TOPLEVEL` is a deprecated alias and will be removed.\n\n.. autodata:: cocotb.packages\n\n.. autodata:: cocotb.SIM_NAME\n\n.. autodata:: cocotb.SIM_VERSION\n\n.. autodata:: cocotb.RANDOM_SEED\n\n.. envvar:: COCOTB_RANDOM_SEED\n\n    Type: :ref:`env-integer`\n\n    Seed the Python random module to recreate a previous test stimulus.\n    At the beginning of every test a message is displayed with the seed used for that execution:\n\n    .. code-block:: bash\n\n             0.00ns INFO     cocotb                             Seeding Python random module with 1756566114\n\n\n    To recreate the same stimuli use the following:\n\n    .. code-block:: bash\n\n       make COCOTB_RANDOM_SEED=1377424946\n\n    The special :data:`cocotb.plusargs` ``+ntb_random_seed`` and ``+seed``, if present,\n    are evaluated to set the random seed value if :envvar:`!COCOTB_RANDOM_SEED` is not set.\n    ``+ntb_random_seed`` takes precedence over ``+seed``.\n\n    .. versionchanged:: 2.0\n\n        :envvar:`RANDOM_SEED` is renamed to :envvar:`COCOTB_RANDOM_SEED`.\n\n    .. deprecated:: 2.0\n\n        :envvar:`RANDOM_SEED` is a deprecated alias and will be removed.\n\n    .. deprecated:: 2.0\n\n        The setting of :envvar:`!COCOTB_RANDOM_SEED` using ``+ntb_random_seed`` and ``+seed`` :data:`!cocotb.plusargs`.\n\n\n.. autodata:: cocotb.is_simulation\n\n.. envvar:: COCOTB_RANDOM_TEST_ORDER\n\n    Type :ref:`env-boolean`\n\n    Default: :data:`False`\n\n    Enable randomizing the order of tests within each stage. To recreate the\n    same test order, the random seed must be set.\n\n    If not set, all tests are ran in the order in which they were discovered.\n\n    .. versionadded:: 2.1\n\nDebugging\n---------\n\n.. automodule:: cocotb.debug\n    :members:\n    :member-order: bysource\n    :synopsis: Features for debugging cocotb's concurrency system.\n\n.. envvar:: COCOTB_SCHEDULER_DEBUG\n\n    Type: :ref:`env-boolean`\n\n    Default: :data:`False`\n\n    Enable additional log output of the coroutine scheduler.\n\n    This will default the value of :data:`~cocotb.debug.debug`,\n    which can later be modified.\n\n.. envvar:: COCOTB_PDB_ON_EXCEPTION\n\n    Type: :ref:`env-boolean`\n\n    Default: :data:`False`\n\n    If defined, cocotb will drop into the Python debugger (:mod:`pdb`) if a test fails with an exception.\n    See also the :ref:`troubleshooting-attaching-debugger-python` subsection of :ref:`troubleshooting-attaching-debugger`.\n\n    .. note::\n        Prior to Python 3.14 running the ``(q)uit`` command in the debugger would not exit the simulator process,\n        but continue running the rest of the test suite. From Python 3.14 onwards, ``(q)uit`` will exit the simulator process immediately.\n        To mimic this behavior call :func:`os._exit` from the pdb command line.\n\n        .. code-block::\n\n            (Pdb) import os; os._exit(0)\n\n.. envvar:: COCOTB_ATTACH\n\n    Type: :ref:`env-integer`\n\n    In order to give yourself time to attach a debugger to the simulator process before it starts to run,\n    you can set the environment variable :envvar:`COCOTB_ATTACH` to a pause time value in seconds.\n    If set, cocotb will print the process ID (PID) to attach to and wait the specified time before\n    actually letting the simulator run.\n\n.. envvar:: COCOTB_ENABLE_PROFILING\n\n    Type: :ref:`env-boolean`\n\n    Default: :data:`False`\n\n    Enable performance analysis of the Python portion of cocotb. When set, a file :file:`test_profile.pstat`\n    will be written which contains statistics about the cumulative time spent in the functions.\n\n    From this, a callgraph diagram can be generated with `gprof2dot <https://github.com/jrfonseca/gprof2dot>`_ and ``graphviz``.\n\n.. envvar:: COCOTB_USER_COVERAGE\n\n    Type: :ref:`env-boolean`\n\n    Default: :data:`False`\n\n    Enable to collect Python coverage data for user code.\n    If :envvar:`COVERAGE_RCFILE` is not set,\n    line and branch coverage is collected and files in the ``cocotb``, ``cocotb_tools``, and ``pygpi`` package directories are excluded.\n\n    This requires the :mod:`coverage` Python module to be installed.\n\n    .. versionchanged:: 2.0\n\n        :envvar:`COVERAGE` is renamed to :envvar:`COCOTB_USER_COVERAGE`.\n\n    .. deprecated:: 2.0\n\n        :envvar:`COVERAGE` is a deprecated alias and will be removed.\n\n.. envvar:: COVERAGE_RCFILE\n\n    Type: :ref:`env-string`\n\n    Location of a configuration file for coverage collection of Python user code\n    using the the :mod:`coverage` module.\n    See https://coverage.readthedocs.io/en/latest/config.html for documentation of this file.\n\n    If this environment variable is set,\n    cocotb will *not* apply its own default coverage collection settings,\n    like enabling branch coverage and excluding files in the cocotb package directory.\n\n    .. versionadded:: 1.7\n\n.. _combine-results:\n\nThe ``combine_results`` script\n------------------------------\n\nUse ``python -m cocotb_tools.combine_results`` to call the script.\n\n.. sphinx_argparse_cli::\n    :module: cocotb_tools.combine_results\n    :func: _get_parser\n    :prog: combine_results\n\n.. _cocotb-config:\n\n\nThe ``cocotb-config`` script\n----------------------------\n\nUse ``cocotb-config`` or ``python -m cocotb_tools.config`` to call the script.\n\n.. sphinx_argparse_cli::\n    :module: cocotb_tools.config\n    :func: _get_parser\n    :prog: cocotb-config\n\n\nImplementation Details\n======================\n\n.. note::\n    In general, nothing in this section should be interacted with directly -\n    these components work mostly behind the scenes.\n\nThe Regression Manager\n----------------------\n\n.. module:: cocotb.regression\n    :synopsis: Regression test suite manager.\n\n.. autodata:: _manager_inst\n\n.. autoclass:: Test\n\n.. autoenum:: RegressionMode\n\n.. autoclass:: RegressionManager\n    :members:\n    :member-order: bysource\n\n\n.. _pygpi:\n\nPyGPI and the ``cocotb.simulator`` module\n-----------------------------------------\n\nThe PyGPI is a Python wrapper around the :term:`GPI` (Generic Procedural Interface).\n\n.. envvar:: PYGPI_PYTHON_BIN\n\n    Type: :ref:`env-string`\n\n    The Python binary in the Python environment to use with cocotb.\n    This is set to the result of ``cocotb-config --python-bin`` in the Makefiles and :ref:`Python Runner <howto-python-runner>`.\n    You will likely only need to set this variable manually if\n    you are using a Python environment other than the currently activated environment,\n    or if you are using a :ref:`custom flow <custom-flows>`.\n\n.. envvar:: PYGPI_USERS\n\n    Type: :ref:`env-list`\n\n    The Python module and callable that starts up the Python cosimulation environment.\n    User overloads can be used to enter alternative Python frameworks or to hook existing cocotb functionality.\n    The variable is formatted as ``path.to.entry.module:entry_point.function,other_module:other_func``.\n    The string before the colon is the Python module to import\n    and the string following the colon is the object to call as the entry function.\n    Multiple entry points can be specified by separating them with a comma.\n\n    The entry function must be a callable matching this form:\n\n    * ``entry_function() -> None``\n\n    .. versionchanged:: 1.8\n        ``level`` argument to ``_sim_event`` is no longer passed, it is assumed to be ``SIM_FAIL`` (2).\n\n    .. versionchanged:: 2.0\n        The entry-module-level functions ``_sim_event``, ``_log_from_c``, and ``_filter_from_c`` are no longer required.\n\n    .. versionchanged:: 2.0\n        Multiple entry points can be specified by separating them with a comma.\n\n    .. versionchanged:: 2.0\n        Renamed from ``PYGPI_ENTRY_POINT``.\n\n    .. versionchanged:: 2.1\n\n        The entry function is no longer passed the ``argv`` object.\n        If you need access to command-line arguments, use :func:`cocotb.simulator.get_simulator_args`.\n\n.. envvar:: PYGPI_DEBUG\n\n    Type: :ref:`env-boolean`\n\n    Default: :data:`False`\n\n    Enable additional debug functionality in the PyGPI.\n    Includes verbose log messages tracing the code execution path through the PyGPI.\n    The messages are logged at GPI log level ``TRACE``,\n    so :envvar:`GPI_LOG_LEVEL` must be set to ``TRACE`` in order to see\n    tracing messages during early PyGPI startup.\n\n    .. versionadded:: 2.1\n\nThe ``cocotb.simulator`` module is the Python :keyword:`import`-able interface to the PyGPI.\nIt should not be considered public API, but is documented here for developers of cocotb.\n\n.. automodule:: cocotb.simulator\n    :members:\n    :undoc-members:\n    :member-order: bysource\n    :synopsis: Interface to simulator.\n\n\n.. _env:\n\nEnvironment Variables\n=====================\n\n.. _env-types:\n\nTypes\n-----\n\n.. _env-boolean:\n\nBoolean\n^^^^^^^\n\nEnable or disable an option by setting the corresponding environment variable to one of the supported values (case-insensitive):\n\n* ``1``, ``yes``, ``y``, ``on``, ``true`` or ``enable`` to enable it.\n* ``0``, ``no``, ``n``, ``off``, ``false`` or ``disable`` to disable it.\n* If the environment variable is unset or empty, it will use the listed default value, or be disabled if no default is specified.\n\n.. note::\n\n    Environment variables of boolean type are case-insensitive. For example: ``YES``, ``Yes`` or ``yes`` are equal.\n\n.. _env-list:\n\nList\n^^^^\n\nComma (``,``) separated list of values. Each element will have leading and trailing whitespace characters stripped.\nEmpty elements will be discarded.\n\n.. _env-string:\n\nString\n^^^^^^\n\nPassed value will have leading and trailing whitespace characters stripped.\nIf environment variable is unset or empty, it will use default value.\nIf no default is specified by the documentation, the feature will be disabled.\n\n.. _env-integer:\n\nInteger\n^^^^^^^\n\nAn integer environment variable is formatted similarly to a Python integer literal.\nOnly decimal literal syntax is supported (i.e. ``0x1234`` is *not* supported) unless specified.\nThere is no limit on the size of the integer.\nValues cannot be prefixed with ``-``; negative values are not currently supported.\nValues cannot contain a decimal point, fractional value (even if ``0``) or exponent.\nAny leading or trailing whitespace is stripped.\n"
  },
  {
    "path": "docs/source/library_reference_c.rst",
    "content": "*********************\nGPI Library Reference\n*********************\n\ncocotb contains a native library called :term:`GPI` (Generic Procedural Interface)\nthat is an abstraction layer for the VPI, VHPI, and FLI simulator interfaces.\n\n.. image:: diagrams/svg/cocotb_overview.svg\n\nThe interaction between cocotb's Python and GPI is via a Python extension module called the :ref:`PyGPI <pygpi>`.\n\nEnvironment Variables\n=====================\n\n.. envvar:: GPI_USERS\n\n    A list of native libraries to load, and optionally functions in those libraries to call,\n    once the GPI is initialized.\n\n    This list is ``;``-separated.\n    Each element of the list contains a path to a library to load.\n    These paths can be full paths (e.g. ``/usr/local/lib/libstuff.so``), in which case the exact library will be loaded,\n    or the basename (e.g. ``libstuff.so``), in which case your operating system's dynamic library lookup will be used.\n\n    Optionally, after the path in each element, a function in that library to call can be specified by name\n    by suffixing the path with a ``,`` character followed by the function name.\n\n    For example:\n\n    * ``GPI_USERS=/usr/local/lib/libstuff.so;libotherstuff.so,entry_func``\n\n    .. attention::\n        This means that paths which contain the characters ``;`` and ``,`` cannot be used in this variable.\n        Instead of using a full path, use the basename, and use environment variables like ``PATH`` or ``LD_LIBRARY_PATH``\n        to modify your operating system's library search path.\n\n    When using the :ref:`building` or :ref:`api-runner` this defaults to load ``libpython`` and then the PyGPI entry point.\n    You can get the default PyGPI entry point at other times by calling ``cocotb-config --pygpi-entry-point`` from the shell\n    or :func:`cocotb_tools.config.pygpi_entry_point` from Python.\n\n.. envvar:: GPI_EXTRA\n\n    A comma-separated list of extra libraries that are dynamically loaded at runtime.\n    A function from each of these libraries will be called as an entry point prior to elaboration,\n    allowing these libraries to register system functions and callbacks.\n    Note that :term:`HDL` objects cannot be accessed at this time.\n    An entry point function must be named following a ``:`` separator,\n    which follows an existing simulator convention.\n\n    For example:\n\n    * ``GPI_EXTRA=libnameA.so:entryA,libnameB.so:entryB`` will first load ``libnameA.so`` with entry point ``entryA`` , then load ``libnameB.so`` with entry point ``entryB``.\n\n    .. versionchanged:: 1.4\n        Support for the custom entry point via ``:`` was added.\n        Previously ``:`` was used as a separator between libraries instead of ``,``.\n\n    .. versionchanged:: 1.5\n        Library name must be fully specified.\n        This allows using relative or absolute paths in library names,\n        and loading from libraries that `aren't` prefixed with \"lib\".\n        Paths `should not` contain commas.\n\nC API\n=====\n\n.. doxygenfile:: gpi.h\n   :sections: brief detaileddescription\n\nUser Handles\n------------\nThese types and functions are about handles the GPI provides to users\nfor interacting with GPI-managed objects.\n\n.. doxygentypedef:: gpi_sim_hdl\n.. doxygentypedef:: gpi_iterator_hdl\n.. doxygentypedef:: gpi_cb_hdl\n\nGPI Functionality\n-----------------\n\nSimulator Control and Interrogation\n+++++++++++++++++++++++++++++++++++\n.. doxygengroup:: SimIntf\n\nSimulation Object Query\n+++++++++++++++++++++++\n.. doxygengroup:: ObjQuery\n\nGeneral Object Properties\n+++++++++++++++++++++++++\n.. doxygengroup:: ObjProps\n\nSignal Object Properties\n++++++++++++++++++++++++\n.. doxygengroup:: SigProps\n\nSimulation Object Iteration\n+++++++++++++++++++++++++++\n.. doxygengroup:: HandleIteration\n\nSimulation Callbacks\n++++++++++++++++++++\n.. doxygengroup:: SimCallbacks\n\nLogging Dependency Injection\n++++++++++++++++++++++++++++\n.. doxygengroup:: Logging\n"
  },
  {
    "path": "docs/source/maintaining.rst",
    "content": "******************\nMaintaining cocotb\n******************\n\nThis section describes how to maintain cocotb, i.e., the more or less frequent tasks performed by the :ref:`cocotb maintainers <maintainers>`.\n\nManaging of Issues and Pull Requests\n====================================\n\nThe cocotb project makes use of GitHub labels attached to issues and pull requests to structure the development process.\nEach issue and pull request can have multiple labels assigned.\n\nThe ``type`` labels define the type of issue or PR:\n\n-  ``type:bug``: a bug in existing functionality\n-  ``type:feature``: new functionality\n-  ``type:cleanup``: cleanup or refactoring on code, documentation, or other areas\n-  ``type:deprecation``: API that should warn and eventually be removed\n-  ``type:change``: an API breaking change that isn't a deprecation or removal\n-  ``type:backport``: a backport of another PR from master onto a stable branch\n-  ``type:task``: a generic label for anything that doesn't fall into the above\n\nThe ``status`` labels give a quick impression of the current status of the issue or PR:\n\n-  ``status:worksforme``: the issue it not reproducible, or intended behavior (i.e. not a bug)\n-  ``status:blocked``: further progress is blocked by a dependency, e.g. other code which must be committed first.\n-  ``status:needs-info``: feedback from someone is required. The issue/PR text gives more details.\n-  ``status:duplicate``: the same issue is already being handled in another issue/PR.\n-  ``status:close?``: issues which can probably be closed, but need a second pair of eyes\n-  ``status:needs-proprietary-testing``: Help needed testing on a proprietary tool\n-  ``status:out-of-scope``: An issue or PR that was closed because the feature or bug was deemed to be out of scope\n\nFor the use in pull requests the following additional status labels are defined:\n\n-  ``status:needs-review``: this PR needs at least one review\n-  ``status:ready-for-merge``: this PR is ready (according to the `Patch Requirements <#patch-requirements>`__) to be merged\n-  ``status:needs-rebase``: needs a git rebase\n-  ``status:needs-newsfragment``: Needs a towncrier newsfragment for the changelog\n-  ``status:needs-test``: needs tests written\n-  ``status:needs-proprietary-testing``: needs testing the change in a simulator we don't have access to\n\nWe occasionally find bugs in upstream projects, such as simulators, Python dependencies, CI tools, etc.\nThe following labels are used for those issues.\n\n-  ``upstream``: marks the issue as being a issue with an upstream project\n-  ``status:needs-upstream-report``: the issue has been diagnosed as an upstream issue, but no upstream report has been filed\n-  ``status:upstream-report-filed``: the issue has been reported upstream\n\nThe ``category`` labels help maintainers to filter issues which are relevant to their area of expertise:\n\n-  ``category:OS:MacOS``: Mac OS/OS X specific issues\n-  ``category:OS:Linux``: Linux specific issues\n-  ``category:OS:Windows``: Microsoft Windows-specific issues\n-  ``category:simulators``: simulator support, including VPI/GPI/etc.\n-  ``category:simulators:activehdl``: Aldec Active-HDL\n-  ``category:simulators:cvc``: Tachyon CVC\n-  ``category:simulators:ghdl``: GHDL\n-  ``category:simulators:icarus``: Icarus Verilog (iverilog)\n-  ``category:simulators:ius``: Cadence Incisive (IUS)\n-  ``category:simulators:modelsim``: Mentor Modelsim\n-  ``category:simulators:nvc``: NVC\n-  ``category:simulators:questa``: Mentor Questa\n-  ``category:simulators:riviera``: Aldec Riviera-PRO\n-  ``category:simulators:vcs``: Synopsys VCS\n-  ``category:simulators:verilator``: Verilator\n-  ``category:simulators:xcelium``: Cadence Xcelium\n-  ``category:codebase:gpi``: relating to the GPI or one of the implementation\n-  ``category:codebase:pygpi``: relating to the Python wrapper around the GPI (embed library and simulator module)\n-  ``category:codebase:scheduler``: relating to the coroutine scheduler\n-  ``category:codebase:triggers``: related to triggers\n-  ``category:codebase:tasks``: related to tasks or coroutines\n-  ``category:codebase:tests``: relating to code for automating test runs (regression manager)\n-  ``category:codebase:handle``: relating to handles\n-  ``category:codebase:types``: relating to modelling types\n-  ``category:codebase:project-automation``: relating to included project automation (makefiles, Python runner)\n-  ``category:building``: relating to build C/C++ libraries and extension modules\n-  ``category:packaging``: issues related to (PyPi) packaging, etc.\n-  ``category:docs``: documentation issues and fixes\n-  ``category:hardware-in-the-loop``: relating to real-life hardware (HIL)\n-  ``category:performance``: performance topics\n-  ``category:ci-free``: continuous integration and unit tests\n-  ``category:meta``: cocotb repo, maintainers, or community\n-  ``category:extensions``: cocotb extension modules\n-  ``category:debugging``: debugging features\n\nTo help new contributors find a good issue to work on one more label is used (following `GitHub standard practices <#https://help.github.com/articles/helping-new-contributors-find-your-project-with-labels/>`__):\n\n-  ``good first issue``: this issue is a good starting point for new contributors.\n   The issue should give an actionable description of what to do to complete this task, along with contact information of a mentor for this task.\n\ncocotb explicitly uses no priority labels, as experience indicates that they provide little value.\n\nIssues and pull requests which are invalid, or where feedback is lacking for four weeks, should be closed.\n\n\ncocotb Releases\n===============\n\ncocotb aims to keep the ``master`` branch always in a releasable state.\nAt least four times a year an official release should be created.\nIt is the job of the maintainers to find a suitable time for a release, to communicate it to the community, and to coordinate it.\n\n\nBackport Changes\n================\n\nAll changes should generally be merged into the ``master`` branch first.\nIf those changes are also needed in a different branch, e.g., a stable branch, they need to be backported.\nPRs can be backported fully automated through GitHub, or semi-automated with the ability to resolve merge conflicts.\nStart with the automated backport process, and fall back to the manual one if necessary.\n\nAutomated PR Backports\n----------------------\n\nThe backporting process starts from an open or already merged PR, typically targeting the ``master`` branch.\nThis PR can then be ported over to any of the ``stable/*`` branches.\n\n1. Open the *source PR* you'd like to backport on GitHub.\n2. Add the label ``backport-to:STABLE_BRANCH_NAME``, e.g. ``backport-to:1.9`` to backport a change to the branch ``stable/1.9``.\n3. If not done yet: Merge the source PR.\n\nOnce the source PR is merged, backport automation (in GitHub Actions) will kick in.\n\n* If the backport can be performed automatically (i.e., there are no merge conflicts), a new PR is opened against the stable branch.\n* Otherwise, a comment is left in the source PR with instructions how to perform a manual backport. Follow the instructions below to continue.\n\nManual PR Backport\n------------------\n\nThe most convenient way to backport a PR is using the `Backport CLI Tool <https://github.com/sorenlouv/backport/>`_, which also powers the automated backport process.\n\n1. Install `npx` on your machine.\n2. Configure authentication for Backport, as described at `in their documentation <https://github.com/sorenlouv/backport/blob/main/docs/config-file-options.md#global-config-backportconfigjson>`_.\n3. In the *master* branch of the cocotb source tree run ``npx backport --pr MY_SOURCE_PR``.\n\nAnswer questions as necessary.\nIn case of a merge conflict, Backport will ask for a manual conflict resolution.\nThis resolution needs to happen in the separate backport repository, typically located at ``~/.backport/repositories/cocotb/cocotb``.\n\nBackport will create a branch in your fork of the cocotb repository, and create a pull request to merge this branch into the selected stable branch, just like in the automated process.\n"
  },
  {
    "path": "docs/source/newsfragments/4519.feature.rst",
    "content": "Support null-ranged arrays (including ``std_logic_vector`` and ``string``) in VHDL.\n"
  },
  {
    "path": "docs/source/newsfragments/4717.change.rst",
    "content": "Reimplemented the scheduler. Exact scheduling order may have changed.\n"
  },
  {
    "path": "docs/source/newsfragments/4986.removal.1.rst",
    "content": "Removed Windows and Linux 32-bit release builds.\n"
  },
  {
    "path": "docs/source/newsfragments/4986.removal.rst",
    "content": "Dropped support for MacOS 13 (Ventura).\n"
  },
  {
    "path": "docs/source/newsfragments/4987.removal.rst",
    "content": "Support for Python 3.6, 3.7, and 3.8 was removed.\n"
  },
  {
    "path": "docs/source/newsfragments/5007.feature.1.rst",
    "content": "Added :deco:`cocotb.skipif` to mark a test as conditionally skipped, with an optional reason string.\n"
  },
  {
    "path": "docs/source/newsfragments/5007.feature.2.rst",
    "content": "Added :deco:`cocotb.xfail` to mark a test as expected to fail with an optional reason and expected exception type.\n"
  },
  {
    "path": "docs/source/newsfragments/5007.feature.rst",
    "content": "Made :deco:`cocotb.test` and :deco:`cocotb.parametrize` stackable. Applying the decorator multiple times to the same test will combine the values of each decoration into a single test generation.\n"
  },
  {
    "path": "docs/source/newsfragments/5041.bugfix.rst",
    "content": "Improve VsimSA simulator support (adds Active-HDL support and updates Riviera-Pro support).\n"
  },
  {
    "path": "docs/source/newsfragments/5057.feature.rst",
    "content": "Add support for Python 3.14.\n"
  },
  {
    "path": "docs/source/newsfragments/5076.feature.rst",
    "content": "Added ``cwd`` argument to :meth:`Runner.build() <cocotb_tools.runner.Runner.build>`.\n"
  },
  {
    "path": "docs/source/newsfragments/5090.feature.rst",
    "content": "Added the :ref:`Pytest Plugin <pytest-support>` that enables using pytest as the regression manager for running cocotb tests.\n"
  },
  {
    "path": "docs/source/newsfragments/5106.feature.rst",
    "content": "Added :envvar:`COCOTB_RANDOM_TEST_ORDER` environment variables to enable randomized ordering of cocotb tests within each stage.\n"
  },
  {
    "path": "docs/source/newsfragments/5114.feature.rst",
    "content": "Added support for SAIF tracing when using Verilator>=5.042 as the simulator.  This is enabled by adding ``--trace-saif`` to :make:var:`EXTRA_ARGS` (when using Makefiles) or to ``build_args`` (when using the runner).\n"
  },
  {
    "path": "docs/source/newsfragments/5131.feature.rst",
    "content": "Added :envvar:`GPI_DEBUG` and :envvar:`PYGPI_DEBUG` environment variables to enable additional debug features, including TRACE log messages.\n"
  },
  {
    "path": "docs/source/newsfragments/5162.change.rst",
    "content": "Changed :meth:`Task.cancel() <cocotb.task.Task.cancel>` to throw :exc:`RuntimeError` if attempting to cancel the currently running task.\n"
  },
  {
    "path": "docs/source/newsfragments/5163.feature.rst",
    "content": "Added :class:`cocotb.triggers.TaskManager` for managing multiple concurrent tasks with automatic cleanup on completion or error.\n"
  },
  {
    "path": "docs/source/newsfragments/5165.feature.1.rst",
    "content": "Added :func:`cocotb.triggers.gather` to wait for multiple awaitables concurrently and collect all results.\n"
  },
  {
    "path": "docs/source/newsfragments/5165.feature.2.rst",
    "content": "Added :func:`cocotb.triggers.select` to wait for multiple awaitables concurrently and return the first one to complete.\n"
  },
  {
    "path": "docs/source/newsfragments/5165.feature.rst",
    "content": "Added :func:`cocotb.triggers.wait` for waiting on multiple awaitables concurrently with a configurable return condition.\n"
  },
  {
    "path": "docs/source/newsfragments/5179.change.rst",
    "content": "Verilog packed vectors, structs, and unions no longer map to :class:`~cocotb.handle.LogicArrayObject`, but :class:`~cocotb.handle.PackedObject`.\n"
  },
  {
    "path": "docs/source/newsfragments/5179.feature.1.rst",
    "content": "Added the :class:`~cocotb.handle.PackedObject` type for Verilog packed vectors, structs, and unions.\n"
  },
  {
    "path": "docs/source/newsfragments/5179.feature.rst",
    "content": ":class:`~cocotb.handle.LogicArrayObject` (VHDL arrays of ``logic`` and ``bit``) now support indexing single elements.\n"
  },
  {
    "path": "docs/source/newsfragments/5181.feature.rst",
    "content": "Add support for ``pre_cmd`` argument to :meth:`Runner.test() <cocotb_tools.runner.Runner.test>` for Aldec Riviera-Pro.\n"
  },
  {
    "path": "docs/source/newsfragments/5182.feature.rst",
    "content": "Add support for ``gui`` argument to :meth:`Runner.test() <cocotb_tools.runner.Runner.test>` for Aldec Riviera-Pro.\n"
  },
  {
    "path": "docs/source/newsfragments/5205.feature.rst",
    "content": ":func:`~cocotb.triggers.with_timeout` now supports being passed any :term:`awaitable`.\n"
  },
  {
    "path": "docs/source/newsfragments/5206.removal.rst",
    "content": "Deprecated passing :class:`~cocotb.task.Task`\\ s to :class:`~cocotb.triggers.First` and :class:`~cocotb.triggers.Combine` in favor of passing coroutines directly to :func:`~cocotb.triggers.select` and :func:`~cocotb.triggers.gather`, respectively.\n"
  },
  {
    "path": "docs/source/newsfragments/5207.change.rst",
    "content": "The ``LIBPYTHON_LOC`` environment variable was removed from the GPI. Instead, ``libpython`` should be included in :envvar:`GPI_USERS`. Support remains in Makefiles (:make:var:`LIBPYTHON_LOC`) and Python Runner (:envvar:`LIBPYTHON_LOC`) for backwards-compatibility. In this case the value of :envvar:`!LIBPYTHON_LOC` is included in the generated :envvar:`!GPI_USERS` if and only if :envvar:`!GPI_USERS` is not already defined.\n"
  },
  {
    "path": "docs/source/newsfragments/5220.feature.1.rst",
    "content": "Added support for using underscores (``_``) as visual separators in :class:`str` values used to set the value of :class:`~cocotb.handle.LogicArrayObject` to enhance readability of long bitstrings, e.g. ``dut.signal.value = \"1010_1101\"``.\n"
  },
  {
    "path": "docs/source/newsfragments/5220.feature.rst",
    "content": "Added visual separator support to :class:`~cocotb.types.LogicArray` string construction. This allows underscores (``_``) to be used to improve readability of long bitstrings, e.g. ``\"1010_1101\"``.\n"
  },
  {
    "path": "docs/source/newsfragments/5222.feature.rst",
    "content": "Added the *on_overflow* parameter to :meth:`LogicArray.from_unsigned() <cocotb.types.LogicArray.from_unsigned>` and :meth:`LogicArray.from_signed() <cocotb.types.LogicArray.from_signed>` to allow the user to decide how to handle values which are too large to fit in *range*.\n"
  },
  {
    "path": "docs/source/newsfragments/5232.change.rst",
    "content": "Added :ref:`environment variable type <env-types>` information to all documented environment variables.\n"
  },
  {
    "path": "docs/source/newsfragments/5248.bugfix.rst",
    "content": ":func:`cocotb.logging.default_config` no longer overwrites root handlers, but configures formatting on whatever handlers are already registered.\n"
  },
  {
    "path": "docs/source/newsfragments/5258.change.rst",
    "content": "Entry points listed in :envvar:`PYGPI_USERS` are no longer passed the ``argv`` object. If you need access to command-line arguments, use :func:`cocotb.simulator.get_simulator_args` instead.\n"
  },
  {
    "path": "docs/source/newsfragments/5263.change.rst",
    "content": "Changed input value checking on :class:`~cocotb.handle.IntegerObject` and :class:`~cocotb.handle.EnumObject` to reflect the size and signedness of the underlying HDL type. Previously, both classes would accept negative values even if the underlying type was unsigned, and had a hardcoded and incorrect limit on the size of the value size that didn't reflect the size of the underlying HDL type.\n"
  },
  {
    "path": "docs/source/newsfragments/5293.feature.1.rst",
    "content": "Added support for comparing :class:`~cocotb.types.LogicArray` with negative integers. This assumes two's complement representation.\n"
  },
  {
    "path": "docs/source/newsfragments/5293.feature.rst",
    "content": "Added support for constructing :class:`~cocotb.types.LogicArray` from a negative integer. This assumes two's complement representation.\n"
  },
  {
    "path": "docs/source/newsfragments/5306.bugfix.rst",
    "content": "Fixed bug where :envvar:`COCOTB_RESOLVE_X` when set ``\"random\"`` would resolve all non-``0``/``1`` values in a vector to the same value.\n"
  },
  {
    "path": "docs/source/newsfragments/5306.change.rst",
    "content": "Split the random number generator (RNG) for the :envvar:`COCOTB_RESOLVE_X` ``\"random\"`` mode from the global Python RNG, so that switching from one :envvar:`!COCOTB_RESOLVE_X` mode to another would not affect the random number sequence of the rest of the testbench.\n"
  },
  {
    "path": "docs/source/newsfragments/5309.feature.rst",
    "content": "Added support for terminating a regression early when the number of test failures reaches :envvar:`COCOTB_MAX_FAILURES`.\n"
  },
  {
    "path": "docs/source/newsfragments/5357.feature.rst",
    "content": "Added support for :class:`pytest.RaisesExc` and :class:`pytest.RaisesGroup` as ``raises`` argument to :func:`cocotb.xfail`.\n"
  },
  {
    "path": "docs/source/newsfragments/5363.change.rst",
    "content": ":mod:`pytest` is no longer an optional dependency, but is required.\n"
  },
  {
    "path": "docs/source/newsfragments/5366.feature.rst",
    "content": "Added :envvar:`COCOTB_LIST_TESTS` environment variable to list tests without running them.\n"
  },
  {
    "path": "docs/source/newsfragments/5380.feature.rst",
    "content": "Added support for :func:`pytest.skip` and :func:`pytest.xfail` for ending the test early.\n"
  },
  {
    "path": "docs/source/newsfragments/5382.change.rst",
    "content": "The :ref:`Makefile <building>` target ``sim`` no longer recursively calls ``make``. This makes it possible to use ``+=`` with Make variables without the right hand side being added twice.\n"
  },
  {
    "path": "docs/source/newsfragments/5392.feature.rst",
    "content": "Added :func:`cocotb.end_test` to end the test immediately from any :class:`!Task` without forcing a pass.\n"
  },
  {
    "path": "docs/source/newsfragments/5395.removal.rst",
    "content": "Deprecated :func:`cocotb.pass_test`. Instead, use :func:`cocotb.skip` to skip a test or use :func:`cocotb.end_test` to end a test while respecting expected failures.\n"
  },
  {
    "path": "docs/source/newsfragments/5415.feature.rst",
    "content": "Added public variable :data:`cocotb_tools.runner.SUPPORTED_RUNNERS`, allowing external libraries to register additional simulators for the ``get_runner()`` function.\n"
  },
  {
    "path": "docs/source/newsfragments/5439.bugfix.rst",
    "content": "Fixed use-after-free in ``VpiSignalObjHdl::register_value_change_callback`` error handling code which caused VCS to segfault.\n"
  },
  {
    "path": "docs/source/newsfragments/5440.bugfix.rst",
    "content": "Fixed a segmentation fault on Icarus Verilog when VPI callbacks fired after the Python interpreter was finalized during simulator shutdown.\n"
  },
  {
    "path": "docs/source/newsfragments/5450.feature.rst",
    "content": "Add ability to specify a particular architecture for a toplevel entity when using NVC.\n"
  },
  {
    "path": "docs/source/newsfragments/5483.feature.rst",
    "content": "Added support for :class:`~cocotb.triggers.RisingEdge` and :class:`~cocotb.triggers.FallingEdge` for instances of :class:`~cocotb.handle.LogicArrayObject` with only one bit.\n"
  },
  {
    "path": "docs/source/newsfragments/5506.feature.rst",
    "content": "Add support for :envvar:`SIM_CMD_PREFIX` and :envvar:`SIM_CMD_SUFFIX` environment variables to the :ref:`Python Runners <howto-python-runner>`.\n"
  },
  {
    "path": "docs/source/newsfragments/5516.change.rst",
    "content": "Changed the extension on the Icarus GPI implementation library from ``.vpl`` to the normal extension for shared libraries on the platform (e.g. ``.so`` or ``.dll``).\n"
  },
  {
    "path": "docs/source/newsfragments/5516.removal.1.rst",
    "content": "Removed the :func:`!cocotb_tools.config.lib_name` function.\n"
  },
  {
    "path": "docs/source/newsfragments/5516.removal.rst",
    "content": "Removed the ``--lib-name`` option from the :ref:`cocotb-config <cocotb-config>` script.\n"
  },
  {
    "path": "docs/source/newsfragments/README.rst",
    "content": ":orphan:\n\n*********************\nWriting Release Notes\n*********************\n\nWe are using `towncrier <https://pypi.org/project/towncrier/>`_ to handle\nour release notes, and this directory contains the input for it -\n\"news fragments\" which are short files that contain a small\n**ReST**-formatted text that will be added to the next version's\nRelease Notes page.\n\nWriting Newsfragments\n---------------------\n\nEach file should be named like ``<ISSUE_OR_PR>.<TYPE>.rst``,\nwhere ``<ISSUE_OR_PR>`` is an issue or a pull request number -\nwhatever is most useful to link to,\nand ``<TYPE>`` is one of:\n\n* ``feature``: New user-facing feature.\n* ``bugfix``: A bug fix.\n* ``doc``: Documentation improvement.\n* ``removal``: Deprecation or removal of public API or behavior.\n* ``change``: A change in public API or behavior.\n\nIn that file, make sure to use full sentences with correct case and punctuation.\nUse \"action\" statements as much as possible.\nIf deprecating or removing something and there is an alternative, mention the alternative.\nIf changing behavior list both the new and old behavior;\nand if there is a way to emulate the old behavior, mention it.\nAvoid mentioning rationale or needless details and avoid talking to the reader.\nUse Sphinx references (see https://sphinx-tutorial.readthedocs.io/cheatsheet/)\nif you refer to added classes, methods etc.\nIn cases where there is more than one piece of news for a pull request,\nsplit the news into multiple fragments (see below for details on how to do that).\n\nDo not use a bullet point at the beginning of the file;\nthose are added automatically.\nEach fragment file must be a single piece of news on a single line;\nmulti-line files will not render correctly.\n\nExamples:\n\n.. parsed-literal::\n\n    Added :class:`TaskManager`.\n\n.. parsed-literal::\n\n    Deprecated passing ``name`` to the :class:`~cocotb.triggers.Event` constructor. If you need to associate a name with an :class:`!Event`, subclass :class:`!Event` and add a ``name`` attribute.\n\nAllowed Syntax\n--------------\n\nAfter we have a release, the release notes are updated so references to objects eternally point to the particular version of the object from that release using intersphinx.\nBecause of that there are certain limitations on the syntax allowed in newsfragments.\n\nDo not use `.object` to refer to a non-qualified object, these only work on internal references and will not work in the release notes after the release.\nUse the full path to the object instead with the `~` prefix to shorten the display name.\n\n.. parsed-literal::\n\n    :class:`~cocotb.triggers.Event`\n\nThat works for everything but ``attr``\\ s and ``meth``\\ s, where you typically want to refer to the type in addition to the method or attribute name.\nIn those cases, use manual formatting.\nMethods should have ``()`` after the name, and attributes should not.\n\n.. parsed-literal::\n\n    :meth:`Runner.test() <cocotb.runner.Runner.test>`\n    :attr:`Event.data <cocotb.triggers.Event.data>`\n\n\nMultiple Newsfragments per PR\n-----------------------------\n\nMultiple newsfragments of different ``<TYPE>`` can be added for a single ``<ISSUE_OR_PR>``.\nAdditional newsfragments of the same ``<TYPE>`` for a single ``<ISSUE_OR_PR>`` are\nsupported using the name format ``<ISSUE_OR_PR>.<TYPE>.<#>.rst``.\n\nExample:\n\n* ``<ISSUE_OR_PR>.bugfix.rst``\n* ``<ISSUE_OR_PR>.bugfix.1.rst``\n* ``<ISSUE_OR_PR>.removal.rst``\n\n\nHow Towncrier Works\n-------------------\n\nTowncrier automatically assembles a list of unreleased changes when building Sphinx (see :file:`docs/conf.py`),\nmeaning your notes will be visible in the documentation immediately after merging.\n\nWhen performing a release, ``towncrier`` should be run independently (in cocotb's root directory),\nwhich will delete all the merged newsfragments.\nMake sure to commit the changes.\n\n:file:`pyproject.toml` contains the configuration for towncrier.\n"
  },
  {
    "path": "docs/source/platform_support.rst",
    "content": ".. _platform-support:\n\n****************\nPlatform Support\n****************\n\ncocotb supports Windows, Linux, and macOS, with a wide range of Python versions.\nThis page describes which platform combinations we test and support.\n\nThe :ref:`platform-support-policy` discusses the underlying policy.\n\n.. note::\n\n  In many cases cocotb will work on platforms not listed on this page, and we aim to fix compatibility issues as we become aware of them.\n  However, we encourage less experienced users to stick with one of the supported options for a good user experience.\n\n  Please reach out to the cocotb team if you would like to see support for a different platform, and are willing to contribute to maintaining it.\n\nSupported Python Versions\n=========================\n\nThe following versions of Python, and all associated patch releases (except where noted) are supported by cocotb.\ncocotb depends on CPython APIs;\nalternative Python implementations like PyPy or Jython are not supported.\n\n* CPython 3.9\n* CPython 3.10\n* CPython 3.11\n* CPython 3.12\n* CPython 3.13\n* CPython 3.14\n\n.. _supported-linux-distributions:\n\nSupported Linux Distributions and Versions\n==========================================\n\nLinux users are in the privileged position of being able to choose from huge variety of distributions.\nWhile most of them are compatible with each other, some subtle differences exist.\nEven though cocotb aims to be agnostic to the distribution, and generally works well on most of them, we are explicitly supporting and testing on a limited subset of distributions which are common in EDA environments.\n\nWe encourage especially users less experienced with Linux to use one of the supported and tested distributions listed below to ensure a smooth cocotb experience.\n\nLinux distributions typically ship a default version of Python called \"system Python\".\nThis version of Python can be used with cocotb unless noted otherwise.\n\n* **Red Hat Enterprise Linux (RHEL) 8 amd64**,\n  shipping with Python 3.6 (newer versions of Python are available), pip 9, and glibc 2.28.\n  `Upstream support until May 2029 <https://access.redhat.com/support/policy/updates/errata#Life_Cycle_Dates>`_.\n* **Red Hat Enterprise Linux (RHEL) 9 amd64**,\n  shipping with Python 3.9 (newer versions of Python are available), pip 21, and glibc 2.34.\n  `Upstream support until May 2032 <https://access.redhat.com/support/policy/updates/errata#Life_Cycle_Dates>`_.\n* **Red Hat Enterprise Linux (RHEL) 10 amd64**,\n  shipping with Python 3.12, pip 23.3, and glibc 2.39.\n  `Upstream support until May 2035 <https://access.redhat.com/support/policy/updates/errata#Life_Cycle_Dates>`_.\n* **Ubuntu 22.04 LTS amd64**, shipping with Python 3.10, pip 22, glibc 2.35.\n  `Upstream support until April 2027 <https://wiki.ubuntu.com/Releases>`_.\n* **Ubuntu 24.04 LTS amd64**, shipping with Python 3.12, pip 24, glibc 2.39.\n  `Upstream support until June 2029 <https://wiki.ubuntu.com/Releases>`_.\n\n.. note::\n\n  * Binary-compatible RHEL-clones, such as CentOS, AlmaLinux or Rocky Linux, are equally supported.\n  * For RHEL only Red Hat-supported minor versions are supported by cocotb.\n  * Compatible Ubuntu derivatives, such as Kubuntu, Xubuntu, etc., are equally supported.\n\nSupported Windows Versions\n==========================\n\n* **Windows 10 x86_64**\n* **Windows 11 x86_64**\n\nSupported macOS Versions\n========================\n\n* **macOS 14 (Sonoma) x86_64**\n* **macOS 15 (Sequoia) x86_64**\n* **macOS 14 (Sonoma) ARM64**\n* **macOS 15 (Sequoia) ARM64**\n\n.. _platform-support-policy:\n\ncocotb Platform Support Policy\n==============================\n\ncocotb's platform support policy is driven by two main considerations.\n\n1. Support cocotb on the platforms our users are using.\n2. Allow our users to use the latest cocotb release.\n\nThe first item is obvious, but comes with interesting implications:\nfor hardware projects it is common to use \"mature\" platforms such as the previous version of RHEL, and stay on that for the duration of a chip project, which might last multiple years.\nFor cocotb, this means supporting rather old Python and operating system versions.\n\nThe second item is less obvious.\nOne might argue that users of older Python or operating system versions should simply use an old version of cocotb.\nThere are two reasons against applying this rule too aggressively.\nFirst of all, we want to give users the benefit of using the latest and greatest version of cocotb on the platform they are on (and are typically unable to change).\nBut even more importantly, every user who is on the latest release is beneficial for the cocotb project.\nSupporting multiple older cocotb releases comes a cost: users report bugs which have been fixed in later releases, patch releases need to be supplied (e.g. for security problems), and integrating improvements our users made becomes harder.\n\nWhen determining the list of supported operating systems and Python versions we are trying to balance those two main considerations.\nThe guidance below adds a bit more color to the policy we apply for choosing supported Python and operating system versions.\n\nPython Support\n--------------\n\ncocotb aims to support a wide range of Python versions as long as they are supported either by the upstream Python project, or by another entity.\n\nIn general, cocotb aims to support all versions of Python `supported by the Python upstream community <https://devguide.python.org/#status-of-python-branches>`_ at the time a cocotb release was made.\nAdditionally, the Python version a supported Linux distribution ships with (system Python) is typically supported as well,\nas long as it receives updates by the operating system vendor (e.g. Red Hat, Debian, or Canonical).\n\nOnly the standard CPython implementation is supported, the alternatives are not supported.\nOnly 64-bit versions of Python are supported.\n\nOperating System Support\n------------------------\n\ncocotb aims to support all operating systems commonly used by our users.\nAs such, we try to match the support matrix of major EDA tools to enable a seamless interaction between simulators and cocotb.\nAdditionally, cocotb should work on the latest version of Windows, Linux, and macOS to ensure users can update their operating system freely without being blocked by cocotb.\n\nOnly 64-bit operating systems are supported.\n\nSimulator Support\n-----------------\n\ncocotb aims to support all major simulators on all operating systems where that simulator is supported.\nOur official support is limited to what we can test in our CI system.\ncocotb's build systems (:ref:`Makefiles <building>` or :ref:`Python runners <api-runner>`) support more simulators,\nand cocotb can theoretically work with any simulator that supports the :term:`VPI` or :term:`VHPI`;\nhowever, such simulators are not officially supported.\n\nOnly 64-bit simulators are supported.\n"
  },
  {
    "path": "docs/source/profiling.rst",
    "content": "************************\nProfiling Testbench Code\n************************\n\ncocotb provides two ways to profile your testbench code (and cocotb itself).\nOne is by using the `built-in tracing profilers in Python <https://docs.python.org/3/library/profile.html>`_,\nand the other is by using a sampling profiler such as `py-spy <https://github.com/benfred/py-spy>`_.\n\n``cProfile`` tracing profiler\n=============================\n\nThe built-in `cProfile` profiler is a tracing profiler that records every function call and its duration.\nThis is capable of a very high degree of accuracy, but it can also introduce significant execution overhead.\nAdditionally, it is only capable of profiling Python code, so it will not capture time spent in cocotb's C++ code.\n\nTo profile a test run, set the :envvar:`COCOTB_ENABLE_PROFILING` to ``1`` before running your tests.\nThis will create a file named ``cocotb.prof`` in the directory where the test was run.\n\n.. code-block:: bash\n\n   export COCOTB_ENABLE_PROFILING=1\n\n   pytest\n   # or\n   make\n\nThere are many ways to view the resulting profile data, but one of the most common is to use the `snakeviz <https://jiffyclub.github.io/snakeviz/>`_ tool to visualize the data in a web browser.\n\n.. code-block:: bash\n\n   pip install snakeviz\n   snakeviz cocotb.prof\n\n\n``py-spy`` sampling profiler\n============================\n\nA sampling profiler such as ``py-spy`` is not as accurate as a tracing profiler,\nbut, in general, it has less execution overhead than a tracing profiler, which may be preferable for long-running simulations.\nAdditionally, some profilers such as ``py-spy`` are able to capture time spent in C++ code, which can be useful for profiling extension modules.\n\nTo profile with py-spy, prefix the simulation command with py-spy using :envvar:`SIM_CMD_PREFIX`.\n\n.. code-block:: bash\n\n    export SIM_CMD_PREFIX=\"py-spy record --format speedscope -o profile.ss --\"\n\n    pytest\n    # or\n    make\n\nIt's recommended to use the ``speedscope`` output format which provides a more interactive visualization of the profile data.\nYou can open the output file in the `speedscope <https://www.speedscope.app/>`_ website, or you can view it locally by installing speedscope.\nThis requires you `install Node.js and npm <https://docs.npmjs.com/downloading-and-installing-node-js-and-npm>`_ first.\n\n.. code-block:: bash\n\n    npm install -g speedscope\n    speedscope profile.ss\n"
  },
  {
    "path": "docs/source/py-modindex.rst",
    "content": "..\n   This file is a placeholder and will be replaced by Sphinx\n   This is a hack to put the module index in the toctree\n   See https://stackoverflow.com/a/42310803\n\n*****\nIndex\n*****\n"
  },
  {
    "path": "docs/source/pytest.rst",
    "content": ".. _pytest-support:\n\n**************\nPytest Support\n**************\n\n:py:mod:`cocotb_tools.pytest.plugin` provides full `pytest`_ integration with cocotb. Including:\n\n* `fixtures`_ to cleanly set up and tear down cocotb tests and designs under test.\n* `plugins`_ that can extend cocotb testing capabilities.\n* `configuration`_ facilities to configure the cocotb testing environment using\n  :ref:`command line arguments <pytest-plugin-options>` ``--cocotb-*``,\n  configuration files like `pyproject.toml`_ or `fixture`_ arguments for fine control per test, class, module or session.\n* listing all available cocotb tests and their relationship with :py:mod:`cocotb_tools.runner`.\n* `marks`_ to easily set metadata on cocotb test functions.\n* filtering cocotb tests with `pytest`_ ``-k '<expression>'`` and ``-m '<markers>'`` options.\n* reporting all executed cocotb tests.\n* parallel execution of cocotb runners by using the `pytest-xdist`_ plugin\n\nEnabling the Plugin\n===================\n\n:py:mod:`cocotb_tools.pytest.plugin` can be enabled in various ways.\n\nIn a Python project\n-------------------\n\nWhen using the `pyproject.toml`_ file (recommended way):\n\n.. code:: toml\n\n    [project.entry-points.pytest11]\n    cocotb = \"cocotb_tools.pytest.plugin\"\n\nWhen using the ``pytest.ini`` file:\n\n.. code:: ini\n\n    [pytest]\n    addopts = -p cocotb_tools.pytest.plugin\n\nWhen using the ``setup.cfg`` file:\n\n.. code:: ini\n\n    [options.entry_points]\n    pytest11 =\n      cocotb = cocotb_tools.pytest.plugin\n\nWhen using the ``setup.py`` file:\n\n.. code:: python\n\n    from setuptools import setup\n\n    setup(\n        # ...,\n        entry_points={\n            \"pytest11\": [\n                \"cocotb = cocotb_tools.pytest.plugin\",\n            ],\n        },\n    )\n\nIn a non-Python project\n-----------------------\n\nBy defining the global variable ``pytest_plugins`` when using a ``conftest.py`` file\n(which must be located in the root of the project):\n\n.. code:: python\n\n    pytest_plugins = (\"cocotb_tools.pytest.plugin\",)\n\nBy defining the ``PYTEST_PLUGINS`` environment variable:\n\n.. code:: shell\n\n    export PYTEST_PLUGINS=\"cocotb_tools.pytest.plugin\"\n\nBy using the ``-p <plugin>`` option when invoking the `pytest`_ command line interface:\n\n.. code:: shell\n\n    pytest -p cocotb_tools.pytest.plugin ...\n\n\n.. _pytest-plugin-build-and-test:\n\nBuilding and Testing\n====================\n\n:py:class:`cocotb_tools.pytest.hdl.HDL` interfaces with the :ref:`Python runners <howto-python-runner>` to build designs and run simulations.\nThe :py:class:`~cocotb_tools.runner.Runner` is fully configurable by using ``--cocotb-*`` command line arguments,\nconfiguration files like `pyproject.toml`_ or `fixture`_ arguments.\n\n\n.. _pytest-plugin-fixtures:\n\nFixtures\n--------\n\n:py:fixture:`cocotb_tools.pytest.plugin.hdl`\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe plugin provides an :fixture:`~cocotb_tools.pytest.plugin.hdl` fixture that will create a new instance of\n:py:class:`~cocotb_tools.pytest.hdl.HDL` that can be customized and then used in tests.\n\nAn example is provided below, located in a project ``conftest.py`` file:\n\n.. code:: python\n\n    import pytest\n    from cocotb_tools.pytest.hdl import HDL\n\n\n    @pytest.fixture(name=\"sample_module\")\n    def sample_module_fixture(hdl: HDL) -> HDL:\n        \"\"\"Define HDL design by adding HDL source files to it.\n\n        Args:\n            hdl: Fixture created by the cocotb pytest plugin, representing a HDL design.\n\n        Returns:\n            Representation of HDL design with added HDL source files.\n        \"\"\"\n        hdl.sources = (\n            # List HDL source files,\n            \"sample_module.sv\",\n        )\n\n        # Build HDL design\n        hdl.build()\n\n        return hdl\n\n\n.. _pytest-plugin-markers:\n\nMarkers\n-------\n\n:py:deco:`!pytest.mark.cocotb_runner`\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe plugin provides the marker :py:deco:`!pytest.mark.cocotb_runner` that will mark test function as cocotb runner.\n\n.. code:: python\n\n    import pytest\n    from cocotb_tools.pytest.hdl import HDL\n\n\n    @pytest.fixture(name=\"sample_module\")\n    def sample_module_fixture(hdl: HDL) -> HDL:\n        \"\"\"Define new HDL design by adding HDL source files to it.\"\"\"\n        hdl.toplevel = \"sample_module\"\n        hdl.sources = (DESIGNS / \"sample_module.sv\",)\n        hdl.build()\n\n        return hdl\n\n\n    # Request for defined HDL design by using fixture\n    @pytest.mark.cocotb_runner  # needed to mark this test function as cocotb runner\n    def hdl_runner_1(sample_module: HDL) -> None:\n        \"\"\"Run HDL simulator that will execute cocotb tests.\"\"\"\n        sample_module.test()\n\n\n    @pytest.mark.cocotb_runner\n    @pytest.mark.cocotb_timescale(unit=\"1ns\", precision=\"1ps\")\n    def test_dut_using_different_timescale(sample_module: HDL) -> None:\n        \"\"\"Test DUT using different timescale.\"\"\"\n        sample_module.test()\n\n\nIf no positional arguments were provided to :py:deco:`!pytest.mark.cocotb_runner`,\nplugin will load current Python module where :py:deco:`!pytest.mark.cocotb_runner` was used as cocotb testbench\n(Python file with cocotb tests).\n\n.. code:: python\n\n    @pytest.mark.cocotb_runner\n    def test_dut_using_default_testbench(sample_module: HDL) -> None:\n        \"\"\"Test DUT with cocotb tests defined in the same Python file as this test function.\"\"\"\n        sample_module.test()\n\n\n    async def test_dut_feature_1(dut) -> None:\n        \"\"\"Test DUT feature 1.\"\"\"\n        ...\n\n\n    async def test_dut_feature_2(dut) -> None:\n        \"\"\"Test DUT feature 2.\"\"\"\n        ...\n\n\nAdditionally, positional arguments of :py:deco:`!pytest.mark.cocotb_runner` marker are equivalent to\n``test_module`` argument from :py:meth:`.Runner.test`.\n\n.. code:: python\n\n    @pytest.mark.cocotb_runner(\"test_dut_tb_1\")\n    def test_dut_using_different_testbench(sample_module: HDL) -> None:\n        \"\"\"Load ``test_dut_tb_1`` Python module and run cocotb tests from there to test DUT.\"\"\"\n        sample_module.test()\n\n\n    @pytest.mark.cocotb_runner(\"test_dut_tb_2\", \"test_dut_tb_3\")\n    def test_dut_using_different_testbenches(sample_module: HDL) -> None:\n        \"\"\"Load ``test_dut_tb_2`` and ``test_dut_tb_3`` Python modules and run cocotb tests from there to test DUT.\"\"\"\n        sample_module.test()\n\n\nIf ``toplevel`` argument is empty/non-set, plugin will use name of first test module but without\n``test_*`` prefix or ``*_test`` suffix. For example, if test module was ``test_design`` then\nname of HDL top level design will be ``design``.\n\n.. code:: python\n\n    # test_design.py\n\n    @pytest.mark.cocotb_runner\n    def test_dut_using_default_toplevel(sample_module: HDL) -> None:\n        \"\"\"Test DUT with default top level associated with name of test file as this test function.\"\"\"\n        assert hdl.toplevel == \"design\"\n        sample_module.test()\n\n\n:py:deco:`!pytest.mark.cocotb_test`\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe plugin provides the marker :py:deco:`!pytest.mark.cocotb_test` which allows\nto mark any coroutine test function as cocotb test.\n\n.. code:: python\n\n    @pytest.mark.cocotb_test\n    async def my_test_function(dut) -> None:\n        \"\"\"Function to test DUT feature.\"\"\"\n        ...\n\n\nUsing the :py:deco:`!pytest.mark.cocotb_test` marker is optional for test functions if they meet the following criteria:\n\n* start with ``test_``\n* is a coroutine function (``async def``)\n* has a positional argument ``dut`` to use the :fixture:`~cocotb_tools.pytest.plugin.dut` fixture\n\n.. code:: python\n\n    async def test_dut_feature(dut) -> None:\n        \"\"\"Function to test DUT feature.\"\"\"\n        ...\n\n\nNon-``async`` functions marked with :py:deco:`!pytest.mark.cocotb_test` are control functions run by pytest.\nThey can run simulations by invoking :py:func:`cocotb_tools.pytest.hdl.HDL.test`\nor :py:func:`cocotb_tools.runner.Runner.test`.\n\n.. code:: python\n\n    import pytest\n    from cocotb_tools.pytest.hdl import HDL\n\n\n    # First, define new HDL design, add HDL source files to it and build it\n    @pytest.fixture(name=\"sample_module\")\n    def sample_module_fixture(hdl: HDL) -> HDL:\n        \"\"\"Define new HDL design by adding HDL source files to it.\"\"\"\n        hdl.toplevel = \"sample_module\"\n        hdl.sources = (DESIGNS / \"sample_module.sv\",)\n        hdl.build()\n\n        return hdl\n\n\n    # Request for defined HDL design by using fixture\n    @pytest.mark.cocotb_runner  # needed to mark this test function as cocotb runner\n    def hdl_runner(sample_module: HDL) -> None:\n        \"\"\"Run HDL simulator that will execute cocotb tests.\"\"\"\n        hdl.test()\n\n\n    async def test_something(dut) -> None:\n        \"\"\"Function that is picked up by pytest discovery does not need a decorator.\"\"\"\n\n\n    @pytest.mark.cocotb_test\n    async def name_without_test_prefix(dut) -> None:\n        \"\"\"Function that is not picked up by pytest discovery needs a decorator to count as a test.\"\"\"\n\n\n:py:deco:`!pytest.mark.cocotb_timeout`\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe plugin provides the marker :py:deco:`!pytest.mark.cocotb_timeout` which allows to mark coroutine function\nwith simulation time duration before the test is forced to fail.\n\n.. code:: python\n\n    @pytest.mark.cocotb_timeout(duration=200, unit=\"ns\")\n    async def test_dut_feature(dut) -> None:\n        \"\"\"Test DUT feature that must finish before 200 nanoseconds.\"\"\"\n        ...\n\n\n.. _pytest-plugin-test-discovery:\n\nTest Discovery\n==============\n\nMarkers can also help the plugin identify and bind cocotb tests to cocotb runners.\nThis is done based on positional arguments supplied to the :py:deco:`!pytest.mark.cocotb_runner` decorator.\nUsers can filter tests when invoking `pytest`_  with ``-k '<expression>'`` or ``-m '<markers>'`` options.\n\nList tree hierarchy of cocotb tests related to cocotb runners and cocotb testbenches:\n\n.. code:: shell\n\n   pytest --collect-only\n\nExample output::\n\n    <Dir tests>\n      <Module test_sample_module.py>\n        <Function test_sample_module>\n        <Runner test_sample_module>\n          <Testbench test_sample_module>\n            <Function test_dut_feature_1>\n            <Function test_dut_feature_2>\n\n.. note::\n\n   Functions which build HDL designs and run tests using the cocotb Runner are treated by the plugin as test functions.\n   Unfortunately, pytest ``<Function>`` items cannot have other sub-items like cocotb test functions or cocotb test modules.\n   So the plugin uses the ``<Runner>`` node to visualize relationship between the cocotb Runner (``<Function>``),\n   cocotb test modules (``<Testbench>``) and cocotb tests (``<Function>``).\n\nRun specific test(s) based on output from ``pytest --collect-only``:\n\n.. code:: shell\n\n   pytest -k 'test_sample_module and test_dut_feature_2'\n\nUser Fixtures\n=============\n\n``pytest`` fixtures can provide useful test functionality, and can use the fixtures provided by the cocotb plugin.\n\nSome examples include:\n\n* Automatically generate a clock.\n* Automatically set up (reset, configure) and tear down DUT per each test\n\nExample clock generation for all tests using the ``conftest.py`` file:\n\n.. code:: python\n\n    from collections.abc import AsyncGenerator\n\n    import pytest\n    from cocotb.clock import Clock\n\n\n    @pytest.fixture(scope=\"session\", autouse=True)\n    async def clock_generation(dut) -> AsyncGenerator[None, None]:\n        \"\"\"Generate clock for all tests using session scope.\"\"\"\n        # Test setup (executed before test), create and start clock generation\n        dut.clk.value = 0\n\n        Clock(dut.clk, 10, unit=\"ns\").start(start_high=False)\n\n        yield  # Calling test, yield is needed to keep clock generation alive\n\n        # Test teardown (executed after test), clock generation will be finished here\n\n\nExample set up and tear down fixture:\n\n.. code:: python\n\n    from collections.abc import AsyncGenerator\n\n    import pytest\n    from cocotb.triggers import FallingEdge\n\n\n    @pytest.fixture(autouse=True)\n    async def setup_sample_module(dut) -> AsyncGenerator[None, None]:\n        \"\"\"Set up and tear down sample module.\"\"\"\n        # Test setup (executed before test)\n        dut.rst.value = 1\n        dut.stream_in_valid.value = 0\n        dut.stream_in_data.value = 0\n        dut.stream_out_ready.value = 0\n\n        for _ in range(2):\n            await FallingEdge(dut.clk)\n\n        dut.rst.value = 0\n\n        yield  # Calling test\n\n        # Test teardown (executed after test)\n        dut.stream_in_valid.value = 0\n        dut.stream_in_data.value = 0\n        dut.stream_out_ready.value = 0\n\n        await FallingEdge(dut.clk)\n\n\n    async def test_dut_feature_1(dut) -> None:\n        \"\"\"Test DUT feature 1. DUT will be always correctly reset and configured.\"\"\"\n\n\n    async def test_dut_feature_2(dut) -> None:\n        \"\"\"Test DUT feature 2. DUT will be always correctly reset and configured.\"\"\"\n\n\n.. _pytest-plugin-integration:\n\nIntegration\n===========\n\nFirst, you should follow the chapter about :ref:`custom-flows` to learn how to integrate cocotb into your existing build flow.\n\n\nDirect Usage\n------------\n\nThe most straightforward usage with the plugin is to directly invoke build system from a test function.\nExample with a custom ``Makefile`` that is defining the ``sample_module`` make recipe:\n\n.. code:: python\n\n    import pytest\n    import subprocess\n\n    @pytest.mark.cocotb_runner\n    def test_sample_module() -> None:\n        \"\"\"Build and run HDL design.\"\"\"\n        subprocess.run([\"make\", \"sample_module\"], check=True)\n\n\nYou may also consider to use command line arguments from pytest to configure build system:\n\n.. code:: python\n\n    import pytest\n    import subprocess\n\n    @pytest.mark.cocotb_runner\n    def test_sample_module(request: pytest.FixtureRequest) -> None:\n        args: list[str] = [\"make\", \"sample_module\"]\n\n        # Add additional arguments based on request.config.option.cocotb_* options or\n        # from fixtures request.node.iter_markers() like \"cocotb\" marker\n        if request.config.option.cocotb_verbose:\n            args.append(\"VERBOSE=1\")\n\n        subprocess.run(args, check=True)\n\n\nAs Fixture\n----------\n\nAnd make it reusable for other projects/teams by packaging is as a new plugin for pytest:\n\n.. code:: python\n\n    import pytest\n    import subprocess\n\n    class MyBuildSystem:\n        def __init__(self, request: pytest.FixtureRequest) -> None:\n            # Handle request.config.option.cocotb_* options and fixtures request.node.iter_markers() like \"cocotb\" marker\n            self.args: list[str] = [\"make\"]\n\n        def build_and_run(self) -> None:\n            # Compile HDL design and run simulator\n            subprocess.run(args, check=True)\n\n\n    @pytest.fixture\n    def my_build_system(request: pytest.FixtureRequest) -> MyBuildSystem:\n        return MyBuildSystem(request)\n\n\nSo others can use it in their projects:\n\n.. code:: python\n\n    import pytest\n    from pytest_cocotb_my_build_system import MyBuildSystem\n\n    @pytest.mark.cocotb_runner\n    def test_sample_module(my_build_system: MyBuildSystem) -> None:\n        my_build_system.build_and_run()\n\n\nBy Hooks\n--------\n\nThe most recommended way to integrate custom build flow with :py:mod:`~cocotb_tools.pytest.plugin`\nis to implement cocotb pytest hooks defined in :py:mod:`cocotb_tools.pytest.hookspecs`.\n\n\n.. code:: python\n\n    from pathlib import Path\n    from cocotb_tools.pytest.hdl import HDL\n    from cocotb_tools.runner import Runner\n    from pytest import FixtureRequest, hookimpl\n\n\n    class MyHDL(HDL):\n        def __init__(self, request: FixtureRequest) -> None:\n            # Add new attributes, load HDL source files from build system, ...\n            ...\n\n\n    class MyRunner(Runner):\n        def build(self, *args, **kwargs) -> None:\n            # Build HDL design by invoking existing build system\n            ...\n\n        def test(self, *args, **kwargs) -> Path:\n            # Run HDL simulator by invoking existing build system\n            ...\n\n\n    @hookimpl(tryfirst=True)\n    def pytest_cocotb_make_hdl(request: FixtureRequest) -> HDL:\n        return MyHDL(request)\n\n\n    @hookimpl(tryfirst=True)\n    def pytest_cocotb_make_runner(simulator_name: str) -> Runner:\n        return MyRunner()\n\n\nImplemented hooks can be distributed as new Python package published to PyPI registry.\n\nConsider to name published Python package with the ``pytest-cocotb-`` prefix.\nThis will allow to automatically list your integration in the list of available pytest `plugins`_.\n\n\nConfiguration\n=============\n\nThanks to :py:mod:`cocotb_tools.pytest.plugin`, cocotb can be configured in many ways.\n\nPrecedence order of configuring cocotb from the highest to the lowest priority:\n\n1. :py:func:`cocotb_tools.pytest.hdl.HDL` attributes set at fixture or test function level\n2. :py:deco:`!pytest.mark.cocotb_runner` marker used with test functions.\n3. ``--cocotb-*`` command line arguments when invoking them with `pytest`_ command line interface.\n4. ``COCOTB_*`` environment variables.\n5. ``cocotb_*`` entries defined in various configuration files like `pyproject.toml`_ file.\n6. Default values.\n\nAll available command line arguments, configuration entries and environment variables that can be\nused to configure cocotb testing environment, can be listed by invoking `pytest`_ help:\n\n.. code:: shell\n\n    pytest --help\n\n\n.. _pytest-plugin-under-the-hood:\n\nUnder the Hood\n==============\n\n.. image:: diagrams/svg/pytest_plugin_overview.svg\n\n\nThe :py:mod:`cocotb_tools.pytest.plugin` is split into two independent parts that complement each other.\n\nThe first part is performed when invoking the ``pytest`` from command line.\nThis is the main process that is running in non-simulation environment. It will:\n\n* Identify and mark test function as cocotb runner or cocotb test.\n* Collect all tests, including cocotb runners and cocotb tests, when invoking ``pytest`` **with** the ``--collect-only`` option.\n  This will allow to properly visualize relationship between cocotb runner, test module (testbench) and cocotb test in\n  the ``pytest`` summary report about collected tests (items).\n* Collect all non-cocotb tests, including cocotb runners, when invoking ``pytest`` **without** the ``--collect-only`` option.\n  This will allow to execute cocotb runners as test functions that will build HDL design and run simulation with cocotb tests.\n* Collect serialized test reports sent by cocotb tests via IPC (Inter-Process Communication) from running simulation process.\n\n.. note::\n\n   Cocotb runners are treated by the plugin as test functions and they will be reported in pytest collect and test summary info.\n   This will allow to report compilation/elaboration of HDL design and simulation runtimes.\n\nThe second part of the :py:mod:`cocotb_tools.pytest.plugin` is performed within the simulator process. It will:\n\n* Identify and mark test function as cocotb test.\n* Collect **only** cocotb tests.\n* Handle coroutines (asynchronous functions) for requested fixtures, test setup, test call and test teardown.\n* Serialize test reports and send them via IPC to the main process (non-simulation environment).\n\n\n.. _pytest-plugin-options:\n\nOptions\n=======\n\n.. argparse::\n   :module: cocotb_tools.pytest.plugin\n   :func: _options_for_documentation\n   :prog: pytest\n\n.. _pytest: https://docs.pytest.org/en/stable/contents.html\n.. _fixture: https://docs.pytest.org/en/stable/explanation/fixtures.html#about-fixtures\n.. _fixtures: https://docs.pytest.org/en/stable/explanation/fixtures.html#about-fixtures\n.. _plugins: https://docs.pytest.org/en/stable/reference/plugin_list.html#plugin-list\n.. _configuration: https://docs.pytest.org/en/stable/reference/customize.html\n.. _pyproject.toml: https://packaging.python.org/en/latest/specifications/pyproject-toml/\n.. _marks: https://docs.pytest.org/en/stable/how-to/mark.html\n.. _request: https://docs.pytest.org/en/stable/reference/reference.html#request\n.. _pytest-xdist: https://github.com/pytest-dev/pytest-xdist\n"
  },
  {
    "path": "docs/source/quickstart.rst",
    "content": ".. _quickstart:\n\n****************\nQuickstart Guide\n****************\nThis guide describe some minimal cocotb testcase examples, with instructions for running simulations, and steps to view the generated waveforms. For a thorough explanation about the cocotb testbench concepts used in this quickstart guide, refer to the :ref:`writing_tbs` page.\n\nPrerequisites\n=============\nBefore starting, install the :ref:`prerequisites<install-prerequisites>` and\ncocotb itself: ``pip install cocotb``\n\nVerify installation and version with the ``cocotb-config --version`` command.\n\nExamples use `Icarus Verilog <https://steveicarus.github.io/iverilog/>`_ for simulation,\nbut any supported Verilog simulator can be used.\nSee :ref:`simulator-support` for a comprehensive list of the supported simulators.\n\nThe code for the following example is available in the cocotb sources:\n:reposrc:`examples/doc_examples/quickstart <examples/doc_examples/quickstart>`.\n\nThe files can be downloaded directly here:\n\n   * :download:`simple_module.sv <../../examples/doc_examples/quickstart/simple_counter.sv>`\n   * :download:`cocotb_test_simple_module.py <../../examples/doc_examples/quickstart/simple_counter_testcases.py>`\n   * :download:`test_runner.py <../../examples/doc_examples/quickstart/test_runner.py>`\n   * :download:`Makefile <../../examples/doc_examples/quickstart/Makefile>`\n\n.. _quickstart_creating_a_test:\n\nCreating a Test\n===============\nA typical cocotb testbench requires no additional :term:`HDL` code.\nThe :term:`DUT` is instantiated as the toplevel in the simulator without any HDL wrapper code.\nThe input stimulus and output checking is done with Python.\n\nCreate a cocotb testcase by decorating an :keyword:`async` Python function with :deco:`cocotb.test`.\nThe function must accept at least the ``dut`` argument,\nwhich gives access to the HDL toplevel.\n\nThe ``dut`` argument gives access to all internals of the HDL toplevel, that is, any port, signal, parameter/generic, as well as submodules.\nIt is possible to \"dot\" your way through the entire hierarchy of the toplevel and access every signal inside every submodule.\n\n.. code-block:: python3\n\n   @cocotb.test()\n   async def testcase(dut):\n      do_something()\n\nAll examples described in this section can be found in the :file:`simple_counter_testcases.py` file.\nThe filename does not really matter as long as it is consistent with the value of :envvar:`COCOTB_TEST_MODULES` in the Makefile and the ``test_module`` argument to :meth:`~cocotb_tools.runner.Runner.test`.\n\n.. _quickstart-example1:\n\nExample 1 - Sequential\n----------------------\nThis example demonstrates a single sequential test routine:\n\n- Set default values for the signals ``ena`` and ``rst``.\n- Start a Clock for stimulus\n- Wait and deactivate ``rst``\n- Hold ``ena`` active for 10 clock cycles then verify ``counter`` equals 10\n- Deactivate ``ena``, wait, and verify ``counter`` does not increment\n\n.. literalinclude:: ../../examples/doc_examples/quickstart/simple_counter_testcases.py\n   :language: python\n   :start-at: # Imports for all Quickstart examples\n   :end-before: # QUICKSTART 1\n\n.. literalinclude:: ../../examples/doc_examples/quickstart/simple_counter_testcases.py\n   :language: python\n   :start-at: # QUICKSTART 1\n   :end-before: # END QUICKSTART 1\n\nThings to note:\n   * ``dut.`` to access anything in the HDL toplevel.\n   * ``dut.<signal>`` to get a *reference* to a signal in the HDL toplevel.\n   * ``dut.<signal>.value`` to get the signal *value*.\n   * ``dut.<signal>.value = some_value`` to set the signal *value*.\n   * :keyword:`!await` to wait for any :ref:`trigger <triggers>` (:class:`~cocotb.trigger.Timer`, :class:`~cocotb.trigger.RisingEdge`, etc.).\n   * :keyword:`!assert` to verify that a value or condition is as expected.\n\nExample 2 - Coroutines\n----------------------\nOften it is useful to have several routines running in parallel.\nThis can be done with :keyword:`async` functions.\nWith cocotb an :keyword:`!async` function should always be started with :func:`cocotb.start_soon`,\nand can be :keyword:`await`-ed if desired. See :ref:`coroutines` for more information.\n\nAs long as the coroutines are not decorated with :deco:`cocotb.test` they are not automatically called\nand can be used as helper functions in the actual testcase decorated with :deco:`!cocotb.test`.\n\nThe following example is similar to :ref:`quickstart-example1`,\nbut does continuous checking of the counter value by starting a coroutine that is always running.\nStimulus is done by starting a different coroutine.\n\n.. literalinclude:: ../../examples/doc_examples/quickstart/simple_counter_testcases.py\n   :language: python\n   :start-at: # Imports for all Quickstart examples\n   :end-before: # QUICKSTART 1\n\n.. literalinclude:: ../../examples/doc_examples/quickstart/simple_counter_testcases.py\n   :language: python\n   :start-at: # QUICKSTART 2\n   :end-before: # END QUICKSTART 2\n\nThings to note:\n   * Use :keyword:`async` to create a function that can be used as a coroutine.\n   * Use :func:`cocotb.start_soon` to start a coroutine.\n\nSee the sections :ref:`writing_tbs_concurrent_sequential` and :ref:`coroutines`\nfor more information on such concurrent processes.\n\nExample 3 - Reading a value can be quirky\n-----------------------------------------\n:func:`cocotb.triggers.RisingEdge` trigger returns immediately after a signal change,\nbefore any signal updates propagate.\nTo sample stable values, :keyword:`!await` the :func:`~cocotb.triggers.ReadOnly` trigger before reading a signal.\nTo resume after the ReadOnly phase, use :keyword:`!await` :func:`cocotb.triggers.NextTimeStep`.\nMore on this in :ref:`timing-model` chapter.\n\n.. literalinclude:: ../../examples/doc_examples/quickstart/simple_counter_testcases.py\n   :language: python\n   :start-at: # Imports for all Quickstart examples\n   :end-before: # QUICKSTART 1\n\n.. literalinclude:: ../../examples/doc_examples/quickstart/simple_counter_testcases.py\n   :language: python\n   :start-at: # QUICKSTART 3\n   :end-before: # END QUICKSTART 3\n\nThings to note:\n   * Use :func:`cocotb.triggers.ReadOnly` before sampling a signal.\n   * Use :func:`cocotb.triggers.NextTimeStep` to resume after the ReadOnly phase.\n\n.. _quickstart_running_a_test:\n\nRunning a Test\n==============\ncocotb testcases can be run in three ways:\n\n1. `make <https://www.gnu.org/software/make/>`_ with a Makefile, see section :ref:`quickstart_makefile`.\n2. The :class:`cocotb_tools.runner.Runner`, see :ref:`quickstart_runner`.\n3. A self-defined custom flow, see :ref:`custom-flows`.\n\nAll the files produced during simulation end up in the :file:`sim_build/` directory unless otherwise specified.\n\n.. _quickstart_makefile:\n\nMakefile\n---------\nIn order to run a test with a Makefile the following must be specified:\n   * the default simulator to use (:make:var:`SIM`),\n   * the default language of the toplevel module or entity (:make:var:`TOPLEVEL_LANG`, ``verilog`` in our case),\n   * the design source files (:make:var:`VERILOG_SOURCES` and :make:var:`VHDL_SOURCES`),\n   * the toplevel module or entity to instantiate (:envvar:`COCOTB_TOPLEVEL`, ``my_design`` in our case),\n   * and Python modules that contain our cocotb tests (:envvar:`COCOTB_TEST_MODULES`.\n     The file containing the test without the `.py` extension, ``simple_counter_testcases`` in our case).\n   * (optional) enable waveform dumping (:make:var:`WAVES`)\n\n.. literalinclude:: ../../examples/doc_examples/quickstart/Makefile\n   :language: make\n   :start-at: # Makefile\n\n.. _quickstart_running_a_makefile:\n\nRunning a Test with a Makefile\n------------------------------\nThe Makefile can be invoked by running:\n\n.. code-block:: bash\n\n   make\n\nIcarus Verilog will be used to simulate the Verilog implementation of the DUT because\nwe defined these as the default values.\n\nValues can be set in the command line to differ from the default defined in the Makefile.\nFor example to run the simulation with Siemens Questa and without waveform generation,\nmake can be invoked as follows:\n\n.. code-block:: bash\n\n    make SIM=questa WAVES=0\n\n.. _quickstart_runner:\n\nCreating a Runner\n-----------------\n\n.. warning::\n    Python runner and associated APIs are experimental and subject to change.\n\nAn alternative to :ref:`quickstart_makefile` is to use the :class:`cocotb_tools.Runner`, or \"runner\" for short.\n\nUsing the runner involves three steps:\n   1. *Instantiation* of the runner with: ``get_runner(sim)``\n   2. *Build*, where the HDL files are compiled: ``runner.build(...)``\n   3. *Test*, where cocotb testcases are run: ``runner.test(...)``\n\nSee the section :ref:`howto-python-runner` for more details.\n\nA minimal test runner can look like:\n\n.. literalinclude:: ../../examples/doc_examples/quickstart/test_runner.py\n   :language: python\n   :start-at: # test_runner.py\n\nRunning a test with a runner\n----------------------------\nThe test runner can be invoked by calling the ``test_simple_counter()``, in this case by running it with Python directly:\n\n.. code-block:: bash\n\n   python test_runner.py\n\nHowever, one of the benefits of using the runner is that it can be used with `pytest <https://pytest.org>`_,\nas long as the function name is discoverable by pytest, e.g. by prefixing the function with the ``test_`` prefix.\nRefer to the `pytest <https://pytest.org>`_ documentation for a more comprehensive guide.\n\nTo run the cocotb test runner with pytest:\n\n.. code-block:: bash\n\n   pytest\n\nViewing the waveform\n====================\nTo view a waveform it must be generated by the simulator, this is not enabled by default.\nThis \"flag\" can be set with :make:var:`WAVES` (``WAVES=1``) with make,\nor the ``waves=True`` argument for the runner.\n\nThe generated waveform file will be located in the :file:`sim_build/` directory unless otherwise specified.\nThe waveform file format generated will vary depending on the simulator used.\nNot all file formats are supported by all waveform viewers.\nSome file formats allow easy conversion back and forth. Mileage may vary.\n\nFor simulators that do not have a built-in waveform viewer,\n`GTKWave <https://gtkwave.github.io/gtkwave/index.html>`_ or the newer `Surfer <https://surfer-project.org>`_\nexist as an alternative.\n\nThis example is by default using the `Icarus Verilog <https://steveicarus.github.io/iverilog/>`_ simulator.\nThe ``.fst`` file format is generated by default and can be opened with either GTKWave or Surfer.\n"
  },
  {
    "path": "docs/source/refcard.rst",
    "content": ".. _refcard:\n\n**************\nReference Card\n**************\n..\n   Document \"best practice\"; leave out detail.\n   Keep format as 1/3rd width of A4/Letter for taping to monitor frames.\n\n   The \"| \" syntax is a \"Line Block\", see\n      https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#line-blocks\n\n.. spelling:word-list::\n   coro\n   coros\n   func\n   metavalue\n   TestFactory\n\n\n*coro*: a coroutine; *task*: a concurrently-running coroutine; *trigger*: a trigger\n\n+------------------------+-----------------------------------------------------------------+\n| Assign                 | ``dut.mysignal.value = 0xFF00``                                 |\n+------------------------+-----------------------------------------------------------------+\n| Assign immediately     | ``dut.mysignal.value = Immediate(0xFF00)``                      |\n+------------------------+-----------------------------------------------------------------+\n| Assign metavalue       | | ``dut.mysignal.value = Logic(\"X\")``                           |\n|                        | | ``dut.mysignal.value = LogicArray(\"01XZ\")``                   |\n+------------------------+-----------------------------------------------------------------+\n| Read                   | | ``val = dut.mysignal.value``                                  |\n|                        | | (``mysig = dut.mysignal`` *creates an alias/reference*)       |\n+------------------------+-----------------------------------------------------------------+\n| Bit slice              | | ``mybit = dut.mysignal.value[0]``                             |\n|                        | | ``mybits = dut.mysignal.value[3:1]``                          |\n+------------------------+-----------------------------------------------------------------+\n| Convert                | | ``val = dut.mysignal.value.to_unsigned()``                    |\n|                        | | ``val = dut.mysignal.value.to_signed()``                      |\n|                        | | ``val = dut.mysignal.value.to_bytes(byteorder=\"little\")``     |\n|                        | | ``val = str(dut.mysignal.value)``                             |\n+------------------------+-----------------------------------------------------------------+\n| Vector length          | ``num_bits = len(dut.mysignal)``                                |\n+------------------------+-----------------------------------------------------------------+\n| Check                  | ``assert dut.mysignal.value == exp, \"Not as expected!\"``        |\n+------------------------+---------------+-------------------------------------------------+\n| Access Extended / Escaped Identifiers  | ``dut[\"\\\\!Hello!\\\\\"]``                          |\n+----------------------------------------+-------------------------------------------------+\n|                                                                                          |\n+------------------------+-----------------------------------------------------------------+\n| Wait time              | ``await cocotb.triggers.Timer(12, \"ns\")``                       |\n+------------------------+-----------------------------------------------------------------+\n| Wait for signal edge   | | ``await cocotb.triggers.RisingEdge(dut.mysignal)``            |\n|                        | | ``await cocotb.triggers.FallingEdge(dut.mysignal)``           |\n|                        | | ``await cocotb.triggers.ValueChange(dut.mysignal)``           |\n+------------------------+-----------------------------------------------------------------+\n|                                                                                          |\n+------------------------+-----------------------------------------------------------------+\n| Run coros concurrently | | ``task_0 = cocotb.start_soon(coro)``                          |\n|                        | | ``result = await task_0``                                     |\n+------------------------+-----------------------------------------------------------------+\n| Cancel task            | ``task_0.cancel()``                                             |\n+------------------------++----------------------------------------------------------------+\n| Wait for task to finish | ``await task_0.complete``                                      |\n+------------------------++----------------------------------------------------------------+\n|                                                                                          |\n+----------------------------------+-------------------------------------------------------+\n| Resume after any Task or Trigger | ``await cocotb.triggers.select(task_0, trigger_1)``   |\n+----------------------------------+-------------------------------------------------------+\n| Resume after all Task or Trigger | ``await cocotb.triggers.gather(task_0, trigger_1)``   |\n+----------------------------------+-------------------------------------------------------+\n|                                                                                          |\n+------------------------+-----------------------------------------------------------------+\n| Generate clock         | ``clk = Clock(dut.clk, 12, \"ns\").start()``                      |\n+------------------------+-----------------------------------------------------------------+\n|                                                                                          |\n+------------------------+-----------------------------------------------------------------+\n| Queue write            | | ``await cocotb.queue.Queue.put(item)``                        |\n|                        | | ``cocotb.queue.Queue.put_nowait(item)``                       |\n+------------------------+-----------------------------------------------------------------+\n| Queue read             | | ``item = await cocotb.queue.Queue.get()``                     |\n|                        | | ``item = cocotb.queue.Queue.get_nowait()``                    |\n+------------------------+-----------------------------------------------------------------+\n| Queue attributes       | | ``queue.maxsize``  (``None`` *== unlimited*)                  |\n|                        | | ``queue.qsize()``                                             |\n|                        | | ``queue.empty()``                                             |\n|                        | | ``queue.full()``                                              |\n+------------------------+-----------------------------------------------------------------+\n| Specialized queues     | ``.PriorityQueue``, ``.LifoQueue``                              |\n+------------------------+-----------------------------------------------------------------+\n|                                                                                          |\n+------------------------+-----------------------------------------------------------------+\n| Set up event           | ``e = cocotb.triggers.Event()``                                 |\n+------------------------+-----------------------------------------------------------------+\n| Wake up waiters        | ``e.set()``                                                     |\n+------------------------+-----------------------------------------------------------------+\n| Wait until ``set()``   | ``await e.wait()``                                              |\n+------------------------+-----------------------------------------------------------------+\n| Reset after ``set()``  | ``e.clear()``                                                   |\n+------------------------+-----------------------------------------------------------------+\n| Timeout                | ``await cocotb.triggers.with_timeout(coro, 1, \"us\")``           |\n+------------------------+-----------------------------------------------------------------+\n|                                                                                          |\n+------------------------+-----------------------------------------------------------------+\n| Force value            | ``dut.mysignal.value = cocotb.handle.Force(0xFF00)``            |\n+------------------------+-----------------------------------------------------------------+\n| Keep value             | ``dut.mysignal.value = cocotb.handle.Freeze()``                 |\n+------------------------+-----------------------------------------------------------------+\n| Release Force/Freeze   | ``dut.mysignal.value = cocotb.handle.Release()``                |\n+------------------------+-----------------------------------------------------------------+\n| *Normal assignment is a \"deposit\"* (``cocotb.handle.Deposit()``)                         |\n+------------------------+-----------------------------------------------------------------+\n|                                                                                          |\n+------------------------+-----------------------------------------------------------------+\n| Mark as test           | ``@cocotb.test(skip, expect_fail, timeout_time, timeout_unit)`` |\n+------------------------+-----------+-----------------------------------------------------+\n|                                                                                          |\n+------------------------+-----------------------------------------------------------------+\n| Set up TestFactory     | ``tf = cocotb.regression.TestFactory(coro)``                    |\n+------------------------+-----------------------------------------------------------------+\n| Add test option        | ``tf.add_option(\"arg\", [\"val0\", \"val1\"])``                      |\n+------------------------+-----------------------------------------------------------------+\n| Generate tests         | ``tf.generate_tests()``                                         |\n+----------------------+-+-----------------------------------------------------------------+\n| Parametrize test     | | ``@cocotb.parametrize(arg1=[1, 2], arg2=[\"yes\", \"no\"])``        |\n|                      | | ``@cocotb.parametrize((\"arg1\", \"arg2\"), [(1, \"a\"), (3, \"b\")])`` |\n+----------------------+-------------------------------------------------------------------+\n"
  },
  {
    "path": "docs/source/regulator.rst",
    "content": "##################################\nThe cocotb ``regulator`` Testbench\n##################################\n\n.. versionadded:: 1.5\n\nThis is the testbench :mod:`test_regulator` for the design ``regulator`` showing\nhow cocotb can be used in an analog-mixed signal (AMS) simulation.\n\n.. note:: The analog probe module used in this testcase is currently only implemented for the\n          Cadence Incisive and Xcelium simulators (with the AMS option available).\n          Help is appreciated to provide equivalent modules for other simulators.\n\n******************\nOverview Schematic\n******************\n\n.. image:: diagrams/svg/example_regulator.svg\n   :width: 100%\n\n\n**********\nThe Design\n**********\n\nThe design ``i_regulator`` consists of a trimmable regulator model written in Verilog-AMS\n(instance name ``i_regulator_block``), and load resistor (instance name ``i_resistor``).\n\n.. literalinclude:: ../../examples/mixed_signal/hdl/regulator.sv\n   :caption: regulator.sv\n   :language: systemverilog\n   :start-at: module regulator\n\nThe regulator block itself is modeled as shown below:\n\n.. literalinclude:: ../../examples/mixed_signal/hdl/regulator_block.vams\n   :caption: regulator_block.vams\n   :language: systemverilog\n   :start-at: `include \"disciplines.vams\"\n\n\n*************\nThe Testbench\n*************\n\nThe testbench consists of both an :term:`HDL` part and a Python/cocotb part.\nWhile having HDL as part of the testbench is not common with cocotb, it is perfectly possible.\n\nThe HDL part of the Testbench\n=============================\n\nThe testbench HDL part is written in SystemVerilog and instantiates the design described above\nas ``i_regulator``.\nIt also contains a probe module for analog values as instance ``i_analog_probe`` —\nimagine this being a multimeter that you quickly connect to different nodes in the design,\nmeasuring either voltage or current.\n\n.. literalinclude:: ../../examples/mixed_signal/hdl/tb_regulator.sv\n   :caption: tb_regulator.sv\n   :language: systemverilog\n   :start-at: import nettypes_pkg\n\nThe probe module can capture voltage and current of a node specified by ``node_to_probe``\n(a string in this module containing a hierarchical path).\nThe capturing occurs whenever there is an edge on the logic signals\n``probe_voltage_toggle`` or ``probe_current_toggle``.\nThe captured values can be read on real-value signals ``voltage`` and ``current`` in this module.\n\nHere is the capture code for ``voltage`` with the \"user-interface\" highlighted:\n\n.. literalinclude:: ../../examples/mixed_signal/hdl/analog_probe_cadence.sv\n   :caption: analog_probe_cadence.sv\n   :language: systemverilog\n   :start-at: var string node_to_probe\n   :end-at: end  // probe_voltage\n   :emphasize-lines: 1-4\n   :dedent: 2\n\nThe cocotb part of the Testbench\n================================\n\ntest_regulator_plot\n-------------------\n\nThe testcase first sets a ``vdd`` voltage and three different trim values,\nsaving the resulting output voltage ``vout`` for each.\nThe saved data is written as a PNG file containing a graph.\n\n.. note:: This testcase depends on `matplotlib <https://matplotlib.org/>`_.\n\n.. image:: regulator.png\n\nTo run this testcase, call:\n\n.. code-block:: bash\n\n    make SIM=xcelium COCOTB_TOPLEVEL=tb_regulator COCOTB_TEST_MODULES=test_regulator_plot\n\n\ntest_regulator_trim\n-------------------\n\nThis testcase runs an automatic trimming routine :meth:`~test_regulator.Regulator_TB.find_trim_val()`\nto find the best trim value for a given target voltage.\nThe determined trim value and the resulting regulator output voltage\nare printed to the console.\n\n.. code-block:: bash\n\n         0.00ns INFO     Running trimming algorithm for target voltage 3.013 V\n         3.00ns INFO     Best trimming value is -1 --> voltage is 3.1 V (difference to target is 0.087 V)\n\nNote that the output voltage does not exactly hit the target value because of\nthe discrete nature of the trim steps.\n\nTo run this testcase, call:\n\n.. code-block:: bash\n\n    make SIM=xcelium COCOTB_TOPLEVEL=tb_regulator COCOTB_TEST_MODULES=test_regulator_trim\n"
  },
  {
    "path": "docs/source/release_notes.rst",
    "content": "*************\nRelease Notes\n*************\n\n.. spelling:word-list::\n   dev\n\nAll releases are available from the `GitHub Releases Page <https://github.com/cocotb/cocotb/releases>`_.\n\n.. include:: master-notes.rst\n\n.. towncrier release notes start\n\ncocotb 2.0.1 (2025-11-15)\n=========================\n\ncocotb 2.0.1 is the first patch release of cocotb 2.0, which fixes small problems identified with the cocotb 2.0.0 release.\n\nFeatures\n--------\n\n- Added support for passing Verilator control files to the ``sources`` argument of the :class:`~cocotb_tools.runner.Verilator` runner. (:pr:`4989`)\n- Added support for NVC on Windows. (:pr:`4995`)\n- Support MacOS ARM64 builds and provide pre-built wheels. (:pr:`5056`)\n\n\nBugfixes\n--------\n\n- Fix CI using the unintended version of Python to run regressions. (:pr:`4988`)\n- Fix support for Python 3.6. (:pr:`4988`)\n- Added filter to ``results.xml`` output to ensure only valid XML characters are emitted. (:pr:`5035`)\n\n\nChanges\n-------\n\n- The value of :data:`cocotb.RANDOM_SEED` is now modified for the duration of a test to be that tests's seed, rather than the regression-wide seed. (:pr:`5082`)\n\n\ncocotb 2.0.0 (2025-09-12)\n=========================\n\ncocotb 2.0 is a major release of cocotb and includes a lot of changes.\nAs indicated by the version number, this new version contains API-breaking changes that may require updates to existing testbenches.\nRefer to :doc:`upgrade-2.0` for a more high-level summary of the changes in cocotb 2.0 and to guide you through the upgrade process.\n\n\nFeatures\n--------\n\n- Made :external+cocotb20:class:`simulator objects <cocotb.handle.SimHandleBase>` hashable. Simulator objects can now be used as :class:`dict` keys and :class:`set` items. (:pr:`2720`)\n- Added the :external+cocotb20:attr:`ValueObjectBase.is_const <cocotb.handle.ValueObjectBase.is_const>` property to support checking if a :class:`ValueObject` is immutable. (:pr:`2720`)\n- Add a new compilation flow for Questa called ``qisqrun``. This flow uses uses the Questa Information System (QIS) for faster simulation performance, Qrun for automatic ordering of VHDL source files and Visualizer as GUI. The new flow can be enabled explicitly by passing :external+cocotb20:make:var:`SIM=questa-qisqrun <SIM>` to ``make``. Users using ``SIM=questa`` use the flow automatically if Questa 2025.2 or newer is detected. To explicitly choose the older flow (which uses ``vsim`` and friends) use ``SIM=questa-compat``. (:pr:`2852`)\n- Added :external+cocotb20:func:`@cocotb.parametrize <cocotb.parametrize>`, a decorator that serves as an alternative to :external+cocotb20:class:`~cocotb.regression.TestFactory`. (:pr:`3513`)\n- Added :any:`cocotb.packages` which contains handles to SystemVerilog packages in a design. (:pr:`3536`)\n- The current Git revision will now be added to :external+cocotb20:data:`cocotb.__version__` for all ``dev`` versions. (:pr:`3568`)\n- The :external+cocotb20:func:`@cocotb.test <cocotb.test>` decorator now accepts a ``name`` argument to override the name of the test in the :external+cocotb20:class:`~cocotb.regression.RegressionManager`. (:pr:`3578`)\n- Added :external+cocotb20:attr:`~cocotb.handle.HierarchyArrayObject.range`, :external+cocotb20:attr:`~cocotb.handle.HierarchyArrayObject.left`, :external+cocotb20:attr:`~cocotb.handle.HierarchyArrayObject.direction`, :external+cocotb20:attr:`~cocotb.handle.HierarchyArrayObject.right`, and :func:`len` support to :external+cocotb20:class:`~cocotb.handle.HierarchyArrayObject`. (:pr:`3655`)\n- Added :external+cocotb20:meth:`HierarchyObject._keys() <cocotb.handle.HierarchyObject._keys>`, :external+cocotb20:meth:`HierarchyObject._values() <cocotb.handle.HierarchyObject._values>`, and :external+cocotb20:meth:`HierarchyObject._items() <cocotb.handle.HierarchyObject._items>` to help users dynamically interact with hierarchical elements of the :term:`DUT`. (:pr:`3655`)\n- Add support for ``handle[sub_handle_name]`` syntax to :external+cocotb20:class:`~cocotb.handle.HierarchyObject` as a more readable alternative to :external+cocotb20:meth:`HierarchyObject._id() <cocotb.handle.HierarchyObject._id>`. (:pr:`3655`)\n- :external+cocotb20:class:`~cocotb.types.Array` now supports equality with :class:`list` and :class:`tuple`. (:pr:`3659`)\n- Support comparing :external+cocotb20:class:`~cocotb.types.LogicArray` with :class:`str`, :class:`list`, and :class:`tuple`. (:pr:`3696`)\n- Use parameter values in generated test names of :external+cocotb20:func:`@cocotb.parametrize <cocotb.parametrize>`, which should be clearer and allow the user to better group tests using :external+cocotb20:envvar:`COCOTB_TEST_FILTER`. (:pr:`3717`)\n- Support specifying arguments like in :external+cocotb20:meth:`TestFactory.add_option() <cocotb.regression.TestFactory.add_option>` in :external+cocotb20:func:`@cocotb.parametrize <cocotb.parametrize>`. (:pr:`3717`)\n- Added :attr:`!range`, :attr:`!left`, :attr:`!direction`, and :attr:`!right` properties to :external+cocotb20:class:`~cocotb.handle.LogicArrayObject`, :external+cocotb20:class:`~cocotb.handle.ArrayObject`, and :external+cocotb20:class:`~cocotb.handle.StringObject`. (:pr:`3733`)\n- Added support for using :class:`str` in assignment to :external+cocotb20:class:`~cocotb.handle.LogicObject`\\ s. (:pr:`3733`)\n- Setting a value with :external+cocotb20:attr:`ArrayObject.value <cocotb.handle.ValueObjectBase.value>` now accepts any :class:`~collections.abc.Sequence`\\ -like type, such as :class:`tuple` and :class:`list`, as well as :external+cocotb20:class:`~cocotb.types.Array`. (:pr:`3733`)\n- :external+cocotb20:meth:`handle.set() <cocotb.handle.ValueObjectBase.set>` was added to value-having simulation object handles as an alternative to the :external+cocotb20:attr:`~cocotb.handle.ValueObjectBase.value` property that provides correct type checking information. (:pr:`3733`)\n- Introduced :external+cocotb20:data:`cocotb.is_simulation` which is ``True`` only when the cocotb library was loaded in a simulation. (:pr:`3779`)\n- The :ref:`combine_results.py <combine-results>` script now ships with the cocotb installation. (:pr:`3791`)\n- Added :external+cocotb20:meth:`LogicArray.to_unsigned() <cocotb.types.LogicArray.to_unsigned>` and :external+cocotb20:meth:`LogicArray.to_signed() <cocotb.types.LogicArray.to_signed>` to convert :external+cocotb20:class:`~cocotb.types.LogicArray` into :class:`int`. (:pr:`3792`)\n- Added :external+cocotb20:meth:`LogicArray.from_unsigned() <cocotb.types.LogicArray.from_unsigned>` and :external+cocotb20:meth:`LogicArray.from_signed() <cocotb.types.LogicArray.from_signed>` to construct :external+cocotb20:class:`~cocotb.types.LogicArray` from :class:`int`. (:pr:`3792`)\n- Added :external+cocotb20:envvar:`COCOTB_TEST_FILTER` which filters tests like :external+cocotb20:envvar:`COCOTB_TESTCASE`, but is a regular expression to allow for more expressive test filtering. (:pr:`3841`)\n- Introduced :external+cocotb20:envvar:`COCOTB_TRUST_INERTIAL_WRITES` to enable a mode where VPI/VHPI/FLI inertial writes are trusted to behave properly. Enabling this feature can lead to behavioral changes and noticeable performance improvements. Some simulators do not handle writes properly, so use this option with caution. (:pr:`3873`)\n- Added :class:`!cocotb.simulator.cpp_clock`, a C++ clock generator implementation with higher performance due to less handshaking between Python and the GPI. :external+cocotb20:class:`~cocotb.clock.Clock` uses it automatically when it would behave identically to the Python implementation. (:pr:`3983`)\n- The :ref:`Siemens DSim <sim-dsim>` simulator is now supported by cocotb. (:pr:`3990`)\n- Added :external+cocotb20:meth:`LogicArray.to_bytes() <cocotb.types.LogicArray.to_bytes>` and :external+cocotb20:meth:`LogicArray.from_bytes() <cocotb.types.LogicArray.from_bytes>` for converting :external+cocotb20:class:`~cocotb.types.LogicArray` to and from :class:`bytes`. (:pr:`4098`)\n- :external+cocotb20:class:`~cocotb.types.LogicArray` can take :class:`int` as the second positional argument as shorthand for passing ``Range(width-1, \"downto\", 0)`` as ``range``. (:pr:`4142`)\n- :external+cocotb20:class:`~cocotb.types.Array` can take :class:`int` as the second positional argument or ``width`` keyword argument as shorthand for passing ``Range(0, \"to\", width-1)`` as ``range``. (:pr:`4142`)\n- Allow user to specify elaboration arguments (``elab_args``) to :external+cocotb20:meth:`Runner.test() <cocotb_tools.runner.Runner.test>` for :ref:`NVC <sim-nvc>` (e.g. to enable coverage collection). (:pr:`4267`)\n- Adding support for resolving ``X``, ``Z``, ``U``, ``W``, and ``-`` values to :external+cocotb20:meth:`LogicArray.to_unsigned() <cocotb.types.LogicArray.to_unsigned>` and :external+cocotb20:meth:`LogicArray.to_signed() <cocotb.types.LogicArray.to_signed>`. (:pr:`4298`)\n- :external+cocotb20:envvar:`PYGPI_USERS` supports multiple user modules by comma-separating them. (:pr:`4310`)\n- The Makefile flow no longer requires that :external+cocotb20:ref:`cocotb-config <cocotb-config>` be located on the ``PATH``. Set :external+cocotb20:envvar:`PYGPI_PYTHON_BIN` if the wrong Python executable is used. (:pr:`4338`)\n- Added :external+cocotb20:class:`~cocotb.task.TaskComplete` Trigger and :external+cocotb20:attr:`Task.complete <cocotb.task.Task.complete>` to get that Trigger for the Task. These are intended to replace :external+cocotb20:class:`~cocotb.task.Join` and :external+cocotb20:meth:`Task.join() <cocotb.task.Task.join>` and do not return the Tasks result when :keyword:`await`\\ ed. (:pr:`4341`)\n- :external+cocotb20:class:`~cocotb.triggers.ClockCycles` can be constructed by passing one of the :ref:`edge-triggers` as the ``edge_type`` argument. (:pr:`4396`)\n- :external+cocotb20:class:`~cocotb.clock.Clock` now owns the driver task, so the user does not need to pass the result of :external+cocotb20:meth:`Clock.start() <cocotb.clock.Clock.start>` to :external+cocotb20:func:`cocotb.start_soon`. Additionally, :external+cocotb20:meth:`Clock.stop() <cocotb.clock.Clock.stop>` was introduced to stop the clock driver. (:pr:`4396`)\n- Add :external+cocotb20:meth:`Clock.cycles() <cocotb.clock.Clock.cycles>` to wait a given number of clock cycles. (:pr:`4396`)\n- :external+cocotb20:class:`~cocotb.task.Task` objects which are already created or running can be passed to :external+cocotb20:func:`cocotb.start`, :external+cocotb20:func:`cocotb.start_soon`, and :external+cocotb20:func:`cocotb.create_task` more than once. (:pr:`4396`)\n- :external+cocotb20:envvar:`GPI_LOG_LEVEL` was added to control GPI loggers (``\"gpi\"`` and children). (:pr:`4467`)\n- Guarantee that :external+cocotb20:class:`~cocotb.triggers.Lock` acquisition is fair. (:pr:`4473`)\n- :external+cocotb20:func:`cocotb.pass_test` was introduced to immediately end a test with a passing outcome. (:pr:`4477`)\n- :external+cocotb20:class:`cocotb.handle.Immediate` was added to support :term:`no-delay deposit`\\ s. (:pr:`4479`)\n- :external+cocotb20:meth:`handle.get() <cocotb.handle.ValueObjectBase.get>` was added to parallel :external+cocotb20:meth:`handle.set() <cocotb.handle.ValueObjectBase.set>`. (:pr:`4479`)\n- Makefile runners no longer need to specify :external+cocotb20:make:var:`SIM`, and have the simulator executable available, to run ``make clean``. (:pr:`4505`)\n- Added :meth:`HierarchyObject._get() <cocotb.handle.HierarchyObject._get>` which returns ``None`` on failure instead of raising an exception to aid with optional signal discovery. It also accepts the optional parameter ``discovery_method`` that takes :external+cocotb20:class:`~cocotb.handle.GPIDiscovery` to specialize object discovery. (:pr:`4517`)\n- Added :external+cocotb20:func:`cocotb.triggers.current_gpi_trigger` to allow the user to determine the last GPI trigger that fired. (:pr:`4549`)\n- Running Tasks are now :external+cocotb20:meth:`cancelled <cocotb.task.Task.cancel>` at the end of the Test, which throws :exc:`~asyncio.CancelledError` into the Task allowing them to do cleanup actions at test end. (:pr:`4574`)\n- Added :external+cocotb20:meth:`Logic.resolve() <cocotb.types.Logic.resolve>` and :external+cocotb20:meth:`LogicArray.resolve() <cocotb.types.LogicArray.resolve>` to resolve non-``0``/``1`` values on demand. (:pr:`4622`)\n- :external+cocotb20:class:`~cocotb.types.LogicArray` now supports :class:`bool` casts and usage in conditionals (e.g. ``if dut.data.value: ...``). (:pr:`4622`)\n- The :external+cocotb20:make:var:`GUI` and :external+cocotb20:make:var:`WAVES` environment variables can be used to override the corresponding ``gui`` and ``waves`` arguments to pytest test benches. This means that they can be provided at run-time without modifying the test bench. (:pr:`4635`)\n- The ``gui`` argument to :external+cocotb20:meth:`Runner.test() <cocotb_tools.runner.Runner.test>` is now supported for NVC, GHDL, Icarus, Verilator, and Dsim using an external waveform viewer, displaying the results after the simulation has ended. cocotb will start Surfer or GTKWave, in that order, if they are in the system path. Use ``COCOTB_WAVEFORM_VIEWER`` to specify viewer. (:pr:`4635`)\n- Added a Python type checker (`mypy <https://mypy.readthedocs.io/en/stable/getting_started.html>`_) to CI to ensure type correctness. (:pr:`4672`)\n- Allow user to specify iverilog wave dump file location at run time with a plusarg. (:pr:`4721`)\n- Added :external+cocotb20:envvar:`COCOTB_REWRITE_ASSERTION_FILES` to allow users to select which files to enable ``pytest``'s assertion rewriting in, or disable it. (:pr:`4728`)\n- Added :external+cocotb20:func:`cocotb.task.current_task` to get the current task object. (:pr:`4730`)\n- Added the ``name`` keyword argument to :external+cocotb20:func:`cocotb.start_soon`, :external+cocotb20:func:`cocotb.start`, and :external+cocotb20:func:`cocotb.create_task` to set a :external+cocotb20:class:`~cocotb.task.Task`\\ s name during creation. (:pr:`4777`)\n- Added :external+cocotb20:meth:`Task.get_name() <cocotb.task.Task.get_name>` and :external+cocotb20:meth:`Task.set_name() <cocotb.task.Task.set_name>` to get and set a :external+cocotb20:class:`~cocotb.task.Task`\\ s name. (:pr:`4777`)\n- Added :external+cocotb20:attr:`Task.locals <cocotb.task.Task.locals>` namespace for Task-local user variables. (:pr:`4863`)\n- Added :external+cocotb20:data:`~cocotb.debug.debug` to allow users to programmatically control the collection of additional debugging information. (:pr:`4867`)\n- Added ``strip_ansi`` and ``reduced_log_fmt`` parameters to :external+cocotb20:func:`~cocotb.logging.default_config` to control log formatting. (:pr:`4871`)\n- Added ``period_high`` argument to :external+cocotb20:class:`~cocotb.clock.Clock` to allow the user to control the duty cycle of the generated clock. (:pr:`4872`)\n- Added :external+cocotb20:attr:`Logic.is_resolvable <cocotb.types.Logic.is_resolvable>` to mirror the method available on :external+cocotb20:class:`~cocotb.types.LogicArray`. (:pr:`4881`)\n- Added support for :func:`copy.deepcopy` on :external+cocotb20:class:`~cocotb.types.LogicArray`. :func:`copy.copy` is not supported. (:pr:`4884`)\n- Add support for :func:`copy.copy` and :func:`copy.deepcopy` on :external+cocotb20:class:`~cocotb.types.Range`, :external+cocotb20:class:`~cocotb.types.Array`, :external+cocotb20:class:`~cocotb.types.Logic`. (:pr:`4884`)\n- Added :external+cocotb20:envvar:`COCOTB_LOG_PREFIX` environment variable to allow users to customize the log message prefix. (:pr:`4900`)\n- Added :external+cocotb20:func:`cocotb.simtime.convert` to replace :external+cocotb20:func:`~cocotb.utils.get_time_from_sim_steps` and :external+cocotb20:func:`~cocotb.utils.get_sim_steps` with a single intuitive interface. (:pr:`4901`)\n- Added :external+cocotb20:data:`cocotb.simtime.time_precision` to allow users to set simulated time precision when not operating with a simulator. (:pr:`4901`)\n- :external+cocotb20:data:`cocotb.logging.strip_ansi` was added to allow the user to programmatically control ANSI escape code stripping in :external+cocotb20:class:`~cocotb.logging.SimLogFormatter`. (:pr:`4909`)\n- Added :class:`!cocotb.logging.ANSI` enum class for ANSI escape codes. (:pr:`4926`)\n\n\nBugfixes\n--------\n\n- Fixes handling of escaped identifiers containing characters that are special in regular expressions (e.g. dots). (:pr:`1610`)\n- Support reading and writing all possible 9-state values in VHDL; ``W``, ``H``, and ``L`` were missing before. (Note that GHDL only supports 4-state values.) (:pr:`4299`)\n- Fixed several memory and callback leaks in the GPI. Simulations may use less memory and run slightly faster. (:pr:`4392`)\n- Passing no triggers to :external+cocotb20:class:`~cocotb.triggers.First` previously hung the simulation indefinitely. Now, doing so raises a :exc:`ValueError` exception. (:pr:`4409`)\n- Passing no triggers to :external+cocotb20:class:`~cocotb.triggers.Combine` previously hung the simulation indefinitely. Now, doing so makes ``Combine`` behave equivalently to :external+cocotb20:class:`~cocotb.triggers.NullTrigger`. (:pr:`4409`)\n- Prevent multiple Tasks from sharing a :external+cocotb20:meth:`Lock.acquire() <cocotb.triggers.Lock.acquire>` Trigger. If this was shared it would cause all Tasks waiting on that same Trigger to think they have acquired the Lock. (:pr:`4473`)\n- Passing :external+cocotb20:class:`~cocotb.handle.Force`, :external+cocotb20:class:`~cocotb.handle.Freeze`, :external+cocotb20:class:`~cocotb.handle.Release`, and :external+cocotb20:class:`~cocotb.handle.Immediate` to :external+cocotb20:meth:`handle.set() <cocotb.handle.ValueObjectBase.set>` and :external+cocotb20:attr:`handle.value <cocotb.handle.ValueObjectBase.value>` now applies the set immediately instead of applying it inertially. (:pr:`4479`)\n- Fixed bug where scheduled writes at the end of a test are cancelled. (:pr:`4514`)\n- Fixed a bug where :external+cocotb20:meth:`cancelling <cocotb.task.Task.cancel>` a Task that is awaiting a :external+cocotb20:class:`~cocotb.triggers.First` or :external+cocotb20:class:`~cocotb.triggers.Combine` doesn't cancel the underlying waiter Tasks, leading to lower performance or concealing test failures. (:pr:`4542`)\n- Can no longer accidentally get :ref:`edge-triggers` on immutable signals that would indefinitely hang. (:pr:`4544`)\n- Fixed issue with ``$dumpfile`` and ``$dumpvars`` not working on Verilator without also turning on global tracing. (:pr:`4591`)\n- Support ``waves`` argument to :external+cocotb20:meth:`Runner.test() <cocotb_tools.runner.Runner.test>` for GHDL and NVC. (:pr:`4630`)\n- Support ``timescale`` argument to :external+cocotb20:meth:`Runner.build() <cocotb_tools.runner.Runner.build>` and :external+cocotb20:meth:`Runner.test() <cocotb_tools.runner.Runner.test>` for DSim. (:pr:`4645`)\n- Fix segfault when using VCS Slave Mode. (:pr:`4670`)\n- Fixed bug where calling :external+cocotb20:meth:`Event.wait() <cocotb.triggers.Event.wait>` but not ``await``\\ ing the returned Trigger, then calling :external+cocotb20:meth:`Event.set() <cocotb.triggers.Event.set>`, then ``await``\\ ing the Trigger would hang. (:pr:`4675`)\n- :external+cocotb20:data:`ANSI escape code stripping <cocotb.logging.strip_ansi>` is now correctly disabled when :external+cocotb20:envvar:`COCOTB_ANSI_OUTPUT` is set to ``0``. (:pr:`4909`)\n\n\nDeprecations and Removals\n-------------------------\n\n- Removed unmaintained WaveDrom support. Users (if any) are encouraged to include the code in their own codebase, or create a cocotb extension for it. (:pr:`2066`)\n- Removed iteration (``for sub_handle in handle: ...``) and querying the length (``len(handle)``) of :external+cocotb20:class:`~cocotb.handle.IntegerObject`, :external+cocotb20:class:`~cocotb.handle.EnumObject`, and :external+cocotb20:class:`~cocotb.handle.RealObject`. (:pr:`2720`)\n- Removed ``cocotb.handle.ConstantObject``. Use :external+cocotb20:attr:`ValueObjectBase.is_const <cocotb.handle.ValueObjectBase.is_const>` to determine is an object is immutable instead. (:pr:`2720`)\n- Deprecated :class:`int`, :class:`str`, and :class:`float` casts on :external+cocotb20:class:`simulator value objects <cocotb.handle.ValueObjectBase>`. Instead use the :external+cocotb20:attr:`ValueObjectBase.value <cocotb.handle.ValueObjectBase.value>` getter, then cast the value. (:pr:`2720`)\n- Removed the ``cocotb.decorators.public`` decorator. (:pr:`3251`)\n- The deprecated :external+cocotb19:func:`cocotb.fork()` function was removed. (:pr:`3425`)\n- Support for generator-based coroutines, which used the ``cocotb.coroutine`` decorator and :keyword:`yield` syntax, has been removed. To update to the new syntax, remove all uses of the decorator and convert the function to a :term:`coroutine function` using the :keyword:`async` and :keyword:`await` syntax. (:pr:`3509`)\n- Removed the ``cocotb.memdebug`` module. (:pr:`3543`)\n- :external+cocotb19:class:`cocotb.utils.lazy_property` was removed. Use :func:`functools.cached_property` instead. (:pr:`3547`)\n- Removed ``cocotb.clock.BaseClock``. (:pr:`3550`)\n- The ``prefix`` and ``postfix`` arguments to :external+cocotb20:meth:`TestFactory.generate_tests() <cocotb.regression.TestFactory.generate_tests>` are deprecated in favor of the more flexible ``name`` argument. (:pr:`3578`)\n- Methods :meth:`!SimHandleBase.get_definition_name()` and :meth:`@SimHandleBase.get_definition_file()` were removed in favor of :external+cocotb20:attr:`SimHandleBase._def_name <cocotb.handle.SimHandleBase._def_name>` and :external+cocotb20:attr:`SimHandleBase._def_file <cocotb.handle.SimHandleBase._def_file>`, respectively. (:pr:`3609`)\n- ``cocotb.binary.BinaryValue``, ``cocotb.binary.BinaryRepresentation``, and the ``cocotb.binary`` module have been removed in favor of :external+cocotb20:class:`~cocotb.types.LogicArray`. (:pr:`3634`)\n- Deprecated :external+cocotb19:envvar:`MODULE`, :external+cocotb19:envvar:`TOPLEVEL`, :external+cocotb19:envvar:`TESTCASE`, :external+cocotb19:envvar:`COVERAGE`, :external+cocotb19:make:var:`PLUSARGS`, and :external+cocotb19:envvar:`RANDOM_SEED`, that are respectively replaced with :external+cocotb20:envvar:`COCOTB_TEST_MODULES`, :external+cocotb20:envvar:`COCOTB_TOPLEVEL`, :external+cocotb20:envvar:`COCOTB_TESTCASE`, :external+cocotb20:envvar:`COCOTB_USER_COVERAGE`, :external+cocotb20:envvar:`COCOTB_PLUSARGS` and :external+cocotb20:envvar:`COCOTB_RANDOM_SEED` to avoid issues with simulators overwriting cocotb environment variables. (:pr:`3644`)\n- :external+cocotb20:meth:`HierarchyObject._id() <cocotb.handle.HierarchyObject._id>` is now deprecated. Use ``handle[\"sub_handle_name\"]`` syntax instead. (:pr:`3655`)\n- The module ``cocotb.outcomes`` was made private. (:pr:`3672`)\n- The module ``cocotb.xunit_reporter`` was made private. (:pr:`3672`)\n- ``cocotb.types.concat`` was removed. Use ``Array(itertools.chain(a, b))`` instead. (:pr:`3705`)\n- :external+cocotb20:class:`~cocotb.regression.TestFactory` is now deprecated. Use :external+cocotb20:func:`@cocotb.parametrize <cocotb.parametrize>` instead. (:pr:`3717`)\n- ``cocotb.handle.ModifiableObject`` was removed along with its non-functional ``drivers()`` and ``loads()`` methods. (:pr:`3733`)\n- Removed :data:`!cocotb.argc`. Use ``len(cocotb.argv)`` instead. (:pr:`3779`)\n- ``cocotb.LANGUAGE`` was removed, use ``os.environ[\"TOPLEVEL_LANG\"]`` if you need that information. (:pr:`3779`)\n- :external+cocotb20:attr:`LogicArray.signed_integer <cocotb.types.LogicArray.signed_integer>` has been deprecated. Use :external+cocotb20:meth:`LogicArray.to_signed() <cocotb.types.LogicArray.to_signed>` instead. (:pr:`3792`)\n- :external+cocotb20:attr:`LogicArray.binstr <cocotb.types.LogicArray.binstr>` has been deprecated. Use ``str(logic_array)`` instead. (:pr:`3792`)\n- :external+cocotb20:attr:`LogicArray.integer <cocotb.types.LogicArray.integer>` has been deprecated. Use :external+cocotb20:meth:`LogicArray.to_unsigned() <cocotb.types.LogicArray.to_unsigned>` instead. (:pr:`3792`)\n- The ``cocotb.scheduler`` module and ``cocotb.scheduler`` object have been made private. (:pr:`3806`)\n- Deprecated the ``verilog_sources`` and ``vhdl_sources`` parameters to :external+cocotb20:meth:`Runner.build() <cocotb_tools.runner.Runner.build>`. Use the language-agnostic ``sources`` parameter instead. (:pr:`3836`)\n- ``Event.fired`` attribute was made private. Use :external+cocotb20:meth:`Event.is_set() <cocotb.triggers.Event.is_set>`. (:pr:`3851`)\n- Removed ``cocotb.triggers.PythonTrigger``. Use ``not isinstance(trigger, cocotb.triggers.GPITrigger)`` instead. (:pr:`3851`)\n- Made ``cocotb.triggers.Trigger.primed``, ``cocotb.triggers.GPITrigger.cbhdl``, and ``cocotb.triggers.Timer.sim_steps`` private. (:pr:`3851`)\n- ``cocotb.result.TestComplete`` was removed. (:pr:`3864`)\n- ``cocotb.result.ExternalException`` was removed. (:pr:`3864`)\n- ``cocotb.triggers.Join.retval`` was removed. (:pr:`3931`)\n- Support for passing ``0`` as the ``time`` argument to :external+cocotb20:class:`~cocotb.triggers.Timer` has been removed. If a rounding operation causes the value to become ``0``, we change it to 1 simulation time step. (:pr:`3937`)\n- :external+cocotb20:attr:`LogicArray.buff <cocotb.types.LogicArray.buff>` has been deprecated. Use :external+cocotb20:meth:`LogicArray.to_bytes() <cocotb.types.LogicArray.to_bytes>` instead. (:pr:`3944`)\n- The ``outcome`` parameter to :external+cocotb20:class:`~cocotb.triggers.NullTrigger` was removed. There is no alternative. (:pr:`3969`)\n- Deprecated the undocumented ``data`` attribute on :external+cocotb20:class:`~cocotb.triggers.Event` and corresponding argument to :external+cocotb20:meth:`Event.set() <cocotb.triggers.Event.set>`. (:pr:`3980`)\n- Removed the ``cycles`` argument to :external+cocotb20:meth:`Clock.start() <cocotb.clock.Clock.start>`. Use :external+cocotb20:meth:`Clock.stop() <cocotb.clock.Clock.stop>` to stop the Clock at the desired time instead. (:pr:`3983`)\n- ``cocotb.utils.want_color_output()``, ``cocotb.utils.remove_traceback_frames``, ``cocotb.utils.walk_coro_stack``, and ``cocotb.utils.extract_coro_stack`` were made private. (:pr:`4023`)\n- The undocumented ``cocotb.triggers._TriggerException``, thrown when a trigger failed to register, was removed. :exc:`RuntimeError` is thrown in its place. (:pr:`4024`)\n- :external+cocotb20:class:`~cocotb.task.Join` was deprecated, use the :external+cocotb20:class:`~cocotb.task.Task` being joined directly wherever ``Join(task)`` was previously used. (:pr:`4084`)\n- :external+cocotb20:meth:`Task.join() <cocotb.task.Task.join>` was deprecated, use the :external+cocotb20:class:`~cocotb.task.Task` being joined directly wherever ``task.join()`` was previously used. (:pr:`4084`)\n- When constructing a :external+cocotb20:class:`~cocotb.types.LogicArray` from a :class:`int`, the ``range`` argument is now required. (:pr:`4093`)\n- Constructing a :external+cocotb20:class:`~cocotb.types.LogicArray` from an :class:`int` now only accepts integer literals (unsigned). Use :external+cocotb20:meth:`LogicArray.from_signed() <cocotb.types.LogicArray.from_signed>` to convert negative integers into :external+cocotb20:class:`~cocotb.types.LogicArray`\\ s using two's complement representation. (:pr:`4093`)\n- The module ``cocotb.decorators`` was removed. All functionality is now available directly in the ``cocotb`` namespace (e.g. ``cocotb.decorators.test`` is now :external+cocotb20:func:`@cocotb.test <cocotb.test>`). (:pr:`4129`)\n- Removed ``Task.has_started()``. (:pr:`4149`)\n- Removed ``cocotb.utils.ParametrizedSingleton``. (:pr:`4382`)\n- :external+cocotb20:class:`~cocotb.triggers.Edge` has been deprecated in favor of the new name :external+cocotb20:class:`~cocotb.triggers.ValueChange`. (:pr:`4382`)\n- The attribute ``frequency`` on :external+cocotb20:class:`~cocotb.clock.Clock` was removed. (:pr:`4396`)\n- :external+cocotb20:func:`cocotb.start` is deprecated in favor of :external+cocotb20:func:`cocotb.start_soon`. Follow the call to :external+cocotb20:func:`cocotb.start_soon` with an :external+cocotb20:class:`await NullTrigger() <cocotb.triggers.NullTrigger>` if you need the scheduled Task to run before continuing the current Task. (:pr:`4397`)\n- :any:`cocotb.logging.SimLog` is deprecated. Use ``logging.getLogger(f\"{name}.0x{ident:x}\")`` instead. (:pr:`4423`)\n- The attributes ``cocotb.handle.SimHandleBase._log``, ``cocotb.task.Task.log``, ``cocotb.clock.Clock.log``, and ``cocotb.triggers.Trigger.log`` have been made private. Users are encouraged to make their own loggers that aren't in the ``\"cocotb\"`` namespace. (:pr:`4467`)\n- :external+cocotb19:class:`~cocotb.result.TestSuccess` was deprecated. Use :external+cocotb20:func:`cocotb.pass_test` instead. (:pr:`4477`)\n- :external+cocotb20:meth:`handle.setimmediatevalue() <cocotb.handle.ValueObjectBase.setimmediatevalue>` is deprecated. Use :external+cocotb20:meth:`handle.set(value, Action.NO_DELAY) <cocotb.handle.ValueObjectBase.set>` instead. (:pr:`4479`)\n- Removed the undocumented ``__name__`` and ``__qualname__`` attributes from :external+cocotb20:class:`~cocotb.task.Task`. (:pr:`4524`)\n- ``cocotb.handle.RegionObject`` and ``cocotb.handle.NonHierarchyObject`` have been removed. (:pr:`4541`)\n- Deprecated :external+cocotb20:attr:`Event.name <cocotb.triggers.Event.name>` and passing a ``name`` argument to :external+cocotb20:class:`~cocotb.triggers.Event` constructors. (:pr:`4561`)\n- :external+cocotb20:meth:`Task.kill() <cocotb.task.Task.kill>` is deprecated in favor of :external+cocotb20:meth:`Task.cancel() <cocotb.task.Task.cancel>`. (:pr:`4573`)\n- :external+cocotb20:class:`~cocotb.types.Range`, :external+cocotb20:class:`~cocotb.types.Logic`, :external+cocotb20:class:`~cocotb.types.LogicArray`, and :external+cocotb20:class:`~cocotb.types.Array` are now only available from the :external+cocotb20:mod:`cocotb.types` module. Their implementation modules are now private. (:pr:`4623`)\n- ``cocotb.handle.SimHandle`` was made private. Generally, :external+cocotb20:class:`dut.hierarchy[\"path/to/thing\"] <cocotb.handle.HierarchyObject>` or :external+cocotb20:meth:`HierarchyObject._get() <cocotb.handle.HierarchyObject._get>` can be used get objects by a full path, which was the typical public use for this function originally. (:pr:`4623`)\n- ``cocotb.regression_manager``, the global :external+cocotb20:class:`~cocotb.regression.RegressionManager` singleton, is now private. (:pr:`4623`)\n- Deprecated :external+cocotb20:attr:`Lock.name <cocotb.triggers.Lock.name>` and passing a ``name`` argument to :external+cocotb20:class:`~cocotb.triggers.Lock` constructors. (:pr:`4723`)\n- Removed ``cocotb.logging.SimBaseLog`` as the class no longer did anything. (:pr:`4775`)\n- Deprecated :external+cocotb20:class:`~cocotb.logging.SimColourLogFormatter`. Use :external+cocotb20:class:`~cocotb.logging.SimLogFormatter` with ``strip_ansi=False`` instead. (:pr:`4871`)\n- Removed :mod:`!cocotb.ANSI` module. (:pr:`4926`)\n- Removed the deprecated :external+cocotb19:class:`cocotb.result.TestComplete`, :external+cocotb19:class:`cocotb.result.TestError`, and :external+cocotb19:class:`cocotb.result.TestFailure`. (:pr:`4960`)\n\n\nChanges\n-------\n\n- When casting a :external+cocotb20:class:`simulator object <cocotb.handle.SimHandleBase>` to a :class:`str` return the :func:`repr` of the object instead of the :external+cocotb20:attr:`path <cocotb.handle.SimHandleBase._path>`. (:pr:`2720`)\n- Testing equality of :external+cocotb20:class:`simulator value objects <cocotb.handle.ValueObjectBase>` now does identity equality instead of a value equality. Use ``handle.value == other_handle.value`` for the old behavior. (:pr:`2720`)\n- Constant value objects are now returned as their corresponding :external+cocotb20:class:`simulator value object <cocotb.handle.ValueObjectBase>` subtype (e.g. integers in VHDL and Verilog are now :external+cocotb20:class:`~cocotb.handle.IntegerObject`\\ s) instead of ``cocotb.handle.ConstantObject``. (:pr:`2720`)\n- cocotb-bus can no longer be installed at the same time as cocotb using ``pip install cocotb[bus]``. Use ``pip install cocotb-bus`` instead. (:pr:`3436`)\n- :external+cocotb20:func:`~cocotb.task.resume` and :external+cocotb20:func:`~cocotb.task.bridge` are now implemented as decorator functions and not types. All attributes, e.g. ``log``, are no longer available. (:pr:`3461`)\n- Use of the :external+cocotb20:envvar:`COCOTB_TESTCASE` variable has been changed so that each element of :external+cocotb20:envvar:`COCOTB_TESTCASE` will now select all tests with a matching name across all :external+cocotb20:envvar:`COCOTB_TEST_MODULES`\\ s instead of just the first one found. (:pr:`3578`)\n- Getting a value with :external+cocotb20:attr:`LogicArrayObject.value <cocotb.handle.ValueObjectBase.value>` now returns a :external+cocotb20:class:`~cocotb.types.LogicArray` instead of a ``cocotb.binary.BinaryValue``. (:pr:`3634`)\n- The module ``cocotb.log`` was renamed to :external+cocotb20:mod:`cocotb.logging` to prevent clashing with :external+cocotb20:data:`cocotb.log`. (:pr:`3673`)\n- Moved ``cocotb.config`` to ``cocotb_tools.config`` and ``cocotb.runner`` to ``cocotb_tools.runner`` to improve startup speed. (:pr:`3731`)\n- Getting a value with :external+cocotb20:attr:`ArrayObject.value <cocotb.handle.ValueObjectBase.value>` now returns an :external+cocotb20:class:`~cocotb.types.Array` with the appropriate :external+cocotb20:class:`~cocotb.types.Range` set instead of a :class:`list`. This will change how the object is indexed to match the range of the simulation object, instead of ``0`` to ``len(handle)-1`` like before. (:pr:`3733`)\n- Renamed ``cocotb.handle.NonConstantObject`` to :external+cocotb20:class:`~cocotb.handle.ValueObjectBase`. (:pr:`3733`)\n- Renamed ``cocotb.handle.NonHierarchyIndexableObject`` to :external+cocotb20:class:`~cocotb.handle.ArrayObject`. (:pr:`3733`)\n- Improved VHPI implementation of :external+cocotb20:func:`cocotb.simulator.get_root_handle`. The ``name`` parameter is now used for handle lookup only as the last fallback, after checking it against the name of the ``vhpiRootInst`` object and its associated ``entity`` object. Handle lookup by name now always includes the ``:`` prefix so that it matches the ``FullName`` of the instantiated object, and will not match objects in the library information model. (:pr:`3774`)\n- :external+cocotb20:meth:`Lock.locked() <cocotb.triggers.Lock.locked>` is now a method instead of an attribute. (:pr:`3851`)\n- The base class for :ref:`Python runners <howto-python-runner>` has been renamed from ``Simulator`` to :external+cocotb20:class:`~cocotb_tools.runner.Runner`. (:pr:`4025`)\n- Moved :external+cocotb20:class:`~cocotb.triggers.SimTimeoutError` from ``cocotb.result`` to :external+cocotb20:mod:`cocotb.triggers`. (:pr:`4039`)\n- ``cocotb.ipython_support`` was moved to :external+cocotb20:mod:`cocotb_tools.ipython_support`. (:pr:`4053`)\n- ``cocotb.external`` and ``cocotb.function`` have been renamed to :external+cocotb20:func:`cocotb.task.bridge` and :external+cocotb20:func:`cocotb.task.resume` to better reflect their intended use case. (:pr:`4054`)\n- Writes performed following an :keyword:`await` on :external+cocotb20:class:`~cocotb.triggers.ReadWrite` will be applied immediately (but inertially) and not scheduled for the next ``ReadWrite``. (:pr:`4115`)\n- Attempting to await on either the :external+cocotb20:class:`~cocotb.triggers.ReadWrite` or :external+cocotb20:class:`~cocotb.triggers.ReadOnly` trigger while in the ReadOnly phase, which is an illegal transition, now raises a :exc:`RuntimeError`. (:pr:`4208`)\n- The GPI ``get_range`` method now returns a range's direction in addition to the left and right bounds. When using VHDL, the direction is set explicitly by the ``to``/``downto`` keywords in the range definition; otherwise, the direction is inferred by the relative values of the left and right bounds. This change also allows null range sizes to be inferred correctly in VHDL. (:pr:`4212`)\n- Python interpreter embedding is now more robust when using Python 3.8+. Setting ``PYTHONHOME`` is no longer required, so simulator usage of Python scripts should no longer fail. (:pr:`4293`)\n- ``bool`` casts of :external+cocotb20:class:`cocotb.handle.SimHandleBase` subclasses will now fail, to prevent silent failures caused by the change in behavior to ``bool(handle)``. Instead use ``None`` to represent a lack of handle and ``handle is not None`` instead of the bool cast. (:pr:`4296`)\n- PyGPI user modules specified by :external+cocotb20:envvar:`PYGPI_USERS` no longer require the module-level definition of the function ``_sim_event``. Instead call :external+cocotb20:func:`cocotb.simulator.set_sim_event_callback` if you need this functionality. (:pr:`4310`)\n- PyGPI user modules specified by :external+cocotb20:envvar:`PYGPI_USERS` no longer require the module-level definition of functions ``_log_from_c`` and ``_filter_from_c``. Instead call :external+cocotb20:func:`cocotb.simulator.initialize_logger` if you need this functionality. (:pr:`4310`)\n- ``std_ulogic_vector``/``std_logic_vector`` signals and constants in VHDL and packed arrays of ``logic`` signals and parameters in Verilog are now discovered as :external+cocotb20:class:`~cocotb.handle.LogicArrayObject`\\ s instead of ``cocotb.handle.ModifiableObject``. (:pr:`2720`) (:pr:`4318`)\n- ``std_ulogic``/``std_logic`` signals and constants in VHDL and scalar ``logic`` signals and parameters in Verilog are now discovered as :external+cocotb20:class:`~cocotb.handle.LogicObject`\\ s instead of ``cocotb.handle.ModifiableObject``. (:pr:`2720`) (:pr:`4318`)\n- :exc:`KeyboardInterrupt` and :exc:`SystemExit` now end the simulation immediately. (:pr:`4330`)\n- The Makefile test flow now fails the ``sim`` target if there are test failures. (:pr:`4337`)\n- :external+cocotb20:attr:`Clock.period <cocotb.clock.Clock.period>` was changed to be in terms of the passed-in unit rather than simulation steps. (:pr:`4396`)\n- The ``units`` argument was renamed to ``unit`` in :external+cocotb20:class:`~cocotb.clock.Clock`, :external+cocotb20:class:`~cocotb.triggers.Timer`, :external+cocotb20:func:`~cocotb.simtime.get_sim_time`, :external+cocotb20:func:`~cocotb.utils.get_time_from_sim_steps`, and :external+cocotb20:func:`~cocotb.utils.get_sim_steps`. (:pr:`4455`)\n- Log test failures at log level :data:`logging.WARNING`. (:pr:`4463`)\n- :external+cocotb20:data:`cocotb.log` was previous the base ``\"cocotb\"`` Logger, but is now a Logger in the ``\"test\"`` namespace. It still defaults to the :data:`logging.INFO` log level. (:pr:`4467`)\n- :external+cocotb20:envvar:`COCOTB_LOG_LEVEL` no longer sets the GPI loggers log level if supplied; use :external+cocotb20:envvar:`GPI_LOG_LEVEL` to do that. (:pr:`4467`)\n- ``VPI_CHECKING`` and ``VHPI_CHECKING`` are removed and interface issues are now always emitted with a log level of :data:`logging.DEBUG`. (:pr:`4510`)\n- ``PYGPI_ENTRY_POINT`` renamed to :external+cocotb20:envvar:`PYGPI_USERS`. (:pr:`4513`)\n- :external+cocotb20:meth:`Task.cancel() <cocotb.task.Task.cancel>` now causes a :exc:`~asyncio.CancelledError` to be thrown into the coroutine. This behavior is *scheduled*, so Tasks will not become cancelled immediately. (:pr:`4524`)\n- Setting values too large for :external+cocotb20:class:`~cocotb.handle.IntegerObject`, :external+cocotb20:class:`~cocotb.handle.EnumObject`, and :external+cocotb20:class:`~cocotb.handle.LogicArrayObject` now raises :exc:`ValueError` instead of :exc:`OverflowError`. (:pr:`4543`)\n- :external+cocotb20:class:`~cocotb.task.Join` was moved from :external+cocotb20:mod:`cocotb.triggers` to :external+cocotb20:mod:`cocotb.task`. (:pr:`4544`)\n- :external+cocotb20:class:`bool(Logic) <cocotb.types.Logic>` casts now treat ``H`` as ``True`` and ``L`` as ``False`` instead of raising :exc:`ValueError`. (:pr:`4551`)\n- :external+cocotb20:attr:`LogicArray.is_resolvable() <cocotb.types.LogicArray.is_resolvable>` now returns ``True`` for arrays containing ``H`` and ``L`` values. (:pr:`4551`)\n- :external+cocotb20:class:`int(Logic) <cocotb.types.Logic>` casts now treat ``H`` as ``1`` and ``L`` as ``0`` instead of raising :exc:`ValueError`. (:pr:`4551`)\n- Renamed ``cocotb.types.ArrayLike`` to :external+cocotb20:class:`~cocotb.types.AbstractArray`. (:pr:`4623`)\n- The minimum supported version of Verilator has been increased to v5.036. (:pr:`4644`)\n- If the user requests coverage collection via ``COCOTB_LIBRARY_COVERAGE`` or :external+cocotb20:envvar:`COCOTB_USER_COVERAGE` and the :mod:`coverage` module is not available, the regression will fail. (:pr:`4656`)\n- Moved :external+cocotb20:class:`~cocotb.regression.SimFailure` from :mod:`!cocotb.result` to :external+cocotb20:mod:`cocotb.regression`. (:pr:`4685`)\n- :external+cocotb19:func:`~cocotb.utils.get_sim_time` was moved from :external+cocotb19:mod:`cocotb.utils` to :external+cocotb20:mod:`cocotb.simtime`. (:pr:`4901`)\n- Logging colorization is now :external+cocotb20:data:`ANSI escape code stripping <cocotb.logging.strip_ansi>`. This will strip any ANSI escape codes, including colorization, from both the logging prefix and messages. (:pr:`4909`)\n- Warnings emitted by the :mod:`warnings` module are now captured and redirected to the logging system using :func:`logging.captureWarnings`. (:pr:`4914`)\n\n\ncocotb 1.9.2 (2024-10-26)\n=========================\n\nBugfixes\n--------\n\n- Better handle errors happening during the startup phase.\n- Fix toplevel discovery in Questa and Modelsim.\n\nFeatures\n--------\n\n- Python 3.13 is now supported.\n\nDeprecations and Removals\n-------------------------\n\n- The :external+cocotb18:envvar:`!RTL_LIBRARY`` and :external+cocotb18:make:var:`TOPLEVEL_LIBRARY` Makefile variables were merged into :external+cocotb19:make:var:`TOPLEVEL_LIBRARY`. Update all uses of :envvar:`!RTL_LIBRARY`.\n\n\ncocotb 1.9.1 (2024-08-29)\n=========================\n\nBugfixes\n--------\n\n- Improve the Verilator Makefile to pass on ``--trace`` at runtime as well. (:issue:`4088`)\n- Pass :external+cocotb19:make:var:`EXTRA_ARGS` in the Verilator Makefile to both the compilation and the simulation step.\n\nChanges\n-------\n\n- Support setuptools 72.2.0\n\ncocotb 1.9.0 (2024-07-14)\n=========================\n\nFeatures\n--------\n\n- Not using parentheses on the :external+cocotb19:class:`@cocotb.test <cocotb.test>` decorator is now supported. (:pr:`2731`)\n- The :external+cocotb19:meth:`cocotb.runner.Simulator.build` method now accepts a ``clean`` argument to remove ``build_dir`` completely during build stage. (:pr:`3351`)\n- Added support for the `NVC <https://github.com/nickg/nvc>`_ VHDL simulator. (:pr:`3427`)\n- Added :external+cocotb19:make:var:`SIM_CMD_SUFFIX` to allow users to redirect simulator output or otherwise suffix the simulation command invocation. (:pr:`3561`)\n- Added ``--trace`` command line argument to Verilator simulation binaries for run-time trace generation. This new argument is passed to the binary when the ``waves`` argument to :external+cocotb19:meth:`cocotb.runner.Simulator.test` is ``True``. (:pr:`3667`)\n- The :external+cocotb19:meth:`cocotb.runner.Simulator.build` and :external+cocotb19:meth:`cocotb.runner.Simulator.test` methods now accept a ``log_file`` argument to redirect stdout and stderr to the specified file. (:pr:`3668`)\n- The ``results_xml`` argument to :external+cocotb19:meth:`cocotb.runner.Simulator.test` can now be an absolute path. (:pr:`3669`)\n- Added ``--trace-file`` command line argument to Verilator simulation binaries which specifies the trace file name. This can be passed to the binary by using the ``test_args`` argument to :external+cocotb19:meth:`cocotb.runner.Simulator.test`. (:pr:`3683`)\n- The :external+cocotb19:meth:`cocotb.runner.Simulator.test` method now accepts a ``pre_cmd`` argument to run given commands before the simulation starts. These are typically Tcl commands for simulators that support them. Only support for the Questa simulator has been implemented. (:pr:`3744`)\n- The ``sources`` option was added to :external+cocotb19:meth:`cocotb.runner.Simulator.build` to better support building mixed-language designs. (:pr:`3796`)\n- Enable use of VPI fallback in all simulators when attempting to access generate blocks directly via lookup. This enables better support for simulators that don't support ``vpiGenScopeArray``, allowing discovery of generate blocks without having to iterate over the parent handle. (:pr:`3817`)\n- Added support for comparing :external+cocotb19:class:`~cocotb.binary.BinaryValue` with :external+cocotb19:class:`~cocotb.types.Logic`, :external+cocotb19:class:`~cocotb.types.LogicArray`, and :class:`str`. (:pr:`3845`)\n- Riviera-PRO now supports compilation into (multiple) VHDL libraries using :make:var:`!VHDL_SOURCES_\\<lib\\>`. (:pr:`3922`)\n\n\nBugfixes\n--------\n\n- Xcelium 23.09.004 and newer can now be used to test designs with a VHDL toplevel. (:pr:`1076`)\n- Fixed a potential issue where pseudo-region lookup may find the wrong generate block if the name of one generate block starts with the name of another generate block. (:pr:`2255`)\n- Support ``waves`` argument to :external+cocotb19:meth:`cocotb.runner.Simulator.build` for Verilator. (:pr:`3681`)\n- The ``test_args`` argument to :external+cocotb19:meth:`cocotb.runner.Simulator.test` is now passed to the Verilator simulation binary when running the simulation, which was previously missing. (:pr:`3682`)\n\n\nDeprecations and Removals\n-------------------------\n\n- ``bool(Lock())`` is deprecated. Use :external+cocotb19:meth:`~cocotb.triggers.Lock.locked` instead. (:pr:`3871`)\n- :external+cocotb19:attr:`cocotb.triggers.Join.retval` is deprecated. Use :external+cocotb19:meth:`cocotb.task.Task.result` to get the result of a finished Task. (:pr:`3871`)\n- Passing the ``outcome`` argument to :class:`!NullTrigger` - which allowed the user to inject arbitrary outcomes when the trigger was :keyword:`await`\\ ed - is deprecated. There is no alternative. (:pr:`3871`)\n- :attr:`!Event.fired` is deprecated. Use :external+cocotb19:meth:`~cocotb.triggers.Event.is_set` instead. (:pr:`3871`)\n\n\nChanges\n-------\n\n- For Aldec simulators, the ``-dbg`` and ``-O2`` options are no longer passed by default, as they reduce simulation speed. Pass these options in :external+cocotb19:make:var:`COMPILE_ARGS` and :external+cocotb19:make:var:`SIM_ARGS` if you need them for increased observability. (:pr:`3490`)\n- :keyword:`await`\\ ing a :external+cocotb19:class:`~cocotb.triggers.Join` trigger will yield the Join trigger and not the result of the task in the 2.0 release. (:pr:`3871`)\n- :external+cocotb19:meth:`Lock.locked <cocotb.triggers.Lock.locked>` is now a method rather than an attribute to mirror :meth:`asyncio.Lock.locked`. (:pr:`3871`)\n\n\ncocotb 1.8.1 (2023-10-06)\n=========================\n\nFeatures\n--------\n\n- Python 3.12 is now supported. (:issue:`3409`)\n\nBugfixes\n--------\n\n- Fix incorrect cleanup of pending Tasks (queued by :external+cocotb18:func:`cocotb.start_soon` but not started yet) when a test ends. (:issue:`3354`)\n\n\ncocotb 1.8.0 (2023-06-15)\n=========================\n\nFeatures\n--------\n\n- :external+cocotb18:class:`cocotb.types.LogicArray` now supports a default value construction if a :external+cocotb19:class:`~cocotb.types.Range` is given. (:pr:`3031`)\n- Add support for :class:`fractions.Fraction` and :class:`decimal.Decimal` to the ``period`` argument of :external+cocotb18:class:`cocotb.clock.Clock`. (:pr:`3045`)\n- This release adds the :external+cocotb18:ref:`Python Test Runner <howto-python-runner>`, an experimental replacement for the traditional Makefile-based build and run flow. (:pr:`3103`)\n- Incisive now supports compilation into a named VHDL library ``lib`` using ``VHDL_SOURCES_<lib>``. (:pr:`3261`)\n- cocotb can now correctly drive Verilator when its new ``--timing`` flag is used. (:pr:`3316`)\n- Creating an FST waveform dump in Icarus Verilog can now be done by setting the :external+cocotb18:make:var:`WAVES` environment variable. Icarus-specific Verilog code is no longer required. (:pr:`3324`)\n\n\nBugfixes\n--------\n\n- Fixed Verilator not writing coverage files in some cases. (:pr:`1478`)\n- The :external+cocotb18:data:`Regression Manager <cocotb.regression_manager>` now correctly handles exceptions raised in tests when the exceptions inherit from `BaseException`. (:pr:`3196`)\n- Fix a performance regression when using Questa with FLI introduced in cocotb 1.7.0. (:pr:`3229`)\n- Adds support for packed union in SystemVerilog when using Cadence Xcelium. (:pr:`3239`)\n- Fixed :class:`RecursionError` caused by certain corner cases in the scheduler. (:pr:`3267`)\n- Fixed cleanup in scheduler which caused sporadic warning messages and bugs in some corner cases. (:pr:`3270`)\n- Fix \"use after free\" bug in VHPI implementation causing Riviera to fail to discover some simulation objects. (:pr:`3307`)\n\n\nChanges\n-------\n\n- Removed ``level`` arg from ``_sim_event`` function in the :external+cocotb18:envvar:`PYGPI_ENTRY_POINT` interface. This function can only indicate a request to shutdown from the simulator or GPI. (:pr:`3066`)\n- Moved :external+cocotb18:class:`cocotb.task.Task` and friends to ``cocotb.task`` module to alleviate internal cyclic import dependency. Users should update imports of the :class:`!Task` to import from the top-level :mod:`!cocotb` namespace. (:pr:`3067`)\n- Added support for :external+cocotb18:make:var:`VERILOG_INCLUDE_DIRS` in the Makefiles. (:pr:`3189`)\n- Changed platform support: Added Red Hat Enterprise Linux 9 (RHEL) and compatible clones, added macOS 13 x86_64 (Ventura on Intel), removed Ubuntu 18.04 (end-of-life). Note that Python wheels compatible with Ubuntu 18.04 remain available for the time being. Even though the cocotb project does not provide pre-compiled binaries for unsupported platforms users can typically compile cocotb themselves, as done automatically when running ``pip install``.\n\ncocotb 1.7.2 (2022-11-15)\n=========================\n\nChanges\n-------\n- Python 3.11 is now supported.\n- ``find_libpython``, a library to find (as the name indicates) libpython, is now a dependency of cocotb.\n  Its latest version resolves an issue for users on RedHat Enterprise Linux (RHEL) 8 and Python 3.8, where the correct Python library would not be detected. (:issue:`3097`)\n\nBugfixes\n--------\n\n- Fixed a segmentation fault in Aldec Riviera-PRO that prevented mixed-language simulation from running. (:issue:`3078`)\n\ncocotb 1.7.1 (2022-09-17)\n=========================\n\nBugfixes\n--------\n\n- Fixed the packaging of the source distribution (sdist) to include all necessary files. (:pr:`3072`)\n- Documented the fact that ``libstdc++-static`` needs to be available on some Linux distributions to install cocotb from source. (:pr:`3082`)\n\ncocotb 1.7.0 (2022-09-06)\n=========================\n\nFeatures\n--------\n\n- Removed the need for ModelSim or Questa being installed when building cocotb. Similar to the approach taken with VPI and VHPI, cocotb now includes all C header files to build the FLI interface. This improvement was done in close collaboration with Siemens EDA, who changed the license of the relevant source code file. (:pr:`2948`)\n- With Questa 2022.3 VHPI support is now fully working and no longer experimental. cocotb still defaults to using the FLI interface for VHDL toplevels with Questa. Users can choose VHPI instead by setting the :external+cocotb17:make:var:`VHDL_GPI_INTERFACE` environment variable to ``vhpi`` before running cocotb. (:pr:`2803`)\n- cocotb tests are now more reproducible. (:pr:`2721`)\n- :external+cocotb17:class:`~cocotb.handle.Force`, :external+cocotb17:class:`~cocotb.handle.Freeze`, and :external+cocotb17:class:`~cocotb.handle.Release` are now supported when using the FLI, Questa's traditional method to access VHDL. (:pr:`2775`)\n- cocotb binaries now statically link libstdc++ on Linux, which prevents library load errors even if the simulator ships its own libstdc++. (:pr:`3002`)\n\n\nBugfixes\n--------\n\n- Fixed write scheduling to apply writes oldest to newest. (:pr:`2792`)\n- Fixed Riviera makefile error for mixed-language simulation when VHDL is the top-level. This bug prevented the VPI library from loading correctly, and was a regression in 1.5.0. (:pr:`2912`)\n- Fixed FLI issue where unprimed triggers were still firing. (:pr:`3010`)\n\n\nDeprecations and Removals\n-------------------------\n\n- :external+cocotb17:func:`cocotb.fork()` has been deprecated in favor of :external+cocotb17:func:`cocotb.start_soon` or :external+cocotb17:func:`cocotb.start`. (:pr:`2663`)\n\n\nChanges\n-------\n\n- Passing :term:`python:coroutine`\\ s to :external+cocotb17:func:`~cocotb.triggers.with_timeout` is now supported. (:pr:`2494`)\n- Renamed ``RunningTask`` to :external+cocotb17:class:`~cocotb.decorators.Task`. (:pr:`2876`)\n- Made :external+cocotb17:class:`~cocotb.decorators.Task` interface more like :class:`asyncio.Task`'s. (:pr:`2876`)\n- When code coverage is enabled with :external+cocotb17:envvar:`COVERAGE` and a configuration file is specified with :envvar:`!COVERAGE_RCFILE`, default coverage configuration is not applied to avoid overriding the user-defined configuration. (:pr:`3014`)\n\n\ncocotb 1.6.2 (2022-02-07)\n=========================\n\nBugfixes\n--------\n\n- Fix regression in :external+cocotb16:class:`~cocotb.regression.TestFactory` when using generator-based test coroutines. (:issue:`2839`)\n\nChanges\n-------\n\n- Change how :envvar:`PYTHONHOME` is populated to work with broken mingw environments. (:issue:`2739`)\n\n\ncocotb 1.6.1 (2021-12-07)\n=========================\n\nBugfixes\n--------\n\n- Fix regression in :external+cocotb16:class:`~cocotb.regression.TestFactory` wrt unique test names. (:issue:`2781`)\n\ncocotb 1.6.0 (2021-10-20)\n=========================\n\nFeatures\n--------\n\n- Support a custom entry point from C to Python with :external+cocotb16:envvar:`PYGPI_ENTRY_POINT`. (:pr:`1225`)\n- Added :external+cocotb16:class:`~cocotb.types.Logic` and ``cocotb.types.Bit`` modeling datatypes. (:pr:`2059`)\n- ModelSim and Questa now support compilation into a named VHDL library ``lib`` using ``VHDL_SOURCES_<lib>``. (:pr:`2465`)\n- Added the :external+cocotb16:class:`~cocotb.types.LogicArray` modeling datatype. (:pr:`2514`)\n- Xcelium now supports compilation into a named VHDL library ``lib`` using ``VHDL_SOURCES_<lib>``. (:pr:`2614`)\n- Add the :external+cocotb16:make:var:`SIM_CMD_PREFIX` to supported Makefile variables, allowing users to pass environment variables and other command prefixes to simulators. (:pr:`2615`)\n- To support VHDL libraries in ModelSim/Questa/Xcelium, :external+cocotb16:make:var:`VHDL_LIB_ORDER` has been added to specify a library compilation order. (:pr:`2635`)\n- :external+cocotb16:func:`cocotb.fork()`, :external+cocotb16:func:`cocotb.start`, :external+cocotb16:func:`cocotb.start_soon`, and :external+cocotb16:func:`cocotb.create_task` now accept any object that implements the :class:`collections.abc.Coroutine` protocol. (:pr:`2647`)\n- :external+cocotb16:class:`~cocotb.regression.TestFactory` and :external+cocotb16:class:`cocotb.test` now accept any :class:`collections.abc.Callable` object which returns a :class:`collections.abc.Coroutine` as a test function. (:pr:`2647`)\n- Added :external+cocotb16:func:`cocotb.start` and :external+cocotb16:func:`cocotb.start_soon` scheduling functions. (:pr:`2660`)\n- Add :external+cocotb16:func:`cocotb.create_task` API for creating a Task from a Coroutine without scheduling. (:pr:`2665`)\n- Support rounding modes in :external+cocotb16:class:`~cocotb.triggers.Timer`. (:pr:`2684`)\n- Support rounding modes in :external+cocotb16:func:`~cocotb.utils.get_sim_steps`. (:pr:`2684`)\n- Support passing ``'step'`` as a time unit in :external+cocotb16:func:`cocotb.utils.get_sim_time`. (:pr:`2691`)\n\n\nBugfixes\n--------\n\n- VHDL signals that are zero bits in width now read as the integer ``0``, instead of raising an exception. (:pr:`2294`)\n- Correctly parse plusargs with ``=``\\ s in the value. (:pr:`2483`)\n- :external+cocotb16:envvar:`COCOTB_RESULTS_FILE` now properly communicates with the :external+cocotb16:data:`Regression Manager <cocotb.regression_manager>` to allow overloading the result filename. (:pr:`2487`)\n- Fixed several scheduling issues related to the use of :external+cocotb16:func:`cocotb.start_soon`. (:pr:`2504`)\n- Verilator and Icarus now support running without specifying a :external+cocotb16:envvar:`TOPLEVEL`. (:pr:`2547`)\n- Fixed discovery of signals inside SystemVerilog interfaces. (:pr:`2683`)\n\n\nImproved Documentation\n----------------------\n\n- The :external+cocotb16:doc:`analog_model` example has been added, showing how to use Python models for analog circuits together with a digital part. (:pr:`2438`)\n\n\nDeprecations and Removals\n-------------------------\n\n- Setting values on indexed handles using the ``handle[i] = value`` syntax is deprecated. Instead use the ``handle[i].value = value`` syntax. (:pr:`2490`)\n- Setting values on handles using the ``dut.handle = value`` syntax is deprecated. Instead use the ``handle.value = value`` syntax. (:pr:`2490`)\n- Setting values on handles using the ``signal <= newval`` syntax is deprecated. Instead, use the ``signal.value = newval`` syntax. (:pr:`2681`)\n- :external+cocotb16:func:`cocotb.utils.hexdump` is deprecated; use :func:`scapy.utils.hexdump` instead. (:pr:`2691`)\n- :external+cocotb16:func:`cocotb.utils.hexdiffs` is deprecated; use :func:`scapy.utils.hexdiff` instead. (:pr:`2691`)\n- Passing ``None`` to :external+cocotb16:func:`cocotb.utils.get_sim_time` is deprecated; use ``'step'`` as the time unit instead. (:pr:`2691`)\n- The ``stdout`` and ``stderr`` attributes on :external+cocotb16:class:`cocotb.result.TestComplete` and subclasses are deprecated. (:pr:`2692`)\n- ``TestFailure`` is deprecated, use an :keyword:`assert` statement instead. (:pr:`2692`)\n\n\nChanges\n-------\n\n- Assigning out-of-range Python integers to signals will now raise an :exc:`OverflowError`. (:pr:`2316`)\n- cocotb now requires Python 3.6+. (:pr:`2422`)\n- Selecting tests using :external+cocotb16:envvar:`TESTCASE` will now search for the first occurrence of a test of that name in order of modules listed in :external+cocotb16:envvar:`MODULE`\\ s, and not just the first module in that list. (:pr:`2434`)\n- The environment variable :external+cocotb16:envvar:`COCOTB_LOG_LEVEL` now supports ``TRACE`` value, which is used for verbose low-level logging that was previously in ``DEBUG`` logs. (:pr:`2502`)\n- Improves formatting on test-related logging outputs. (:pr:`2564`)\n- Shorter log lines (configurable with :external+cocotb16:envvar:`COCOTB_REDUCED_LOG_FMT`) are now the default. For wider log output, similar to previous cocotb releases, set the :external+cocotb16:envvar:`COCOTB_REDUCED_LOG_FMT` environment variable to ``0``. (:pr:`2564`)\n\n\ncocotb 1.5.2 (2021-05-03)\n=========================\n\nBugfixes\n--------\n\n- Changed some makefile syntax to support GNU Make 3. (:pr:`2496`)\n- Fixed behavior of ``cocotb-config --libpython`` when finding libpython fails. (:pr:`2522`)\n\n\ncocotb 1.5.1 (2021-03-20)\n=========================\n\nBugfixes\n--------\n\n- Prevent pytest assertion rewriting (:pr:`2028`) from capturing stdin, which causes problems with IPython support. (:pr:`1649`) (:pr:`2462`)\n- Add dependency on `cocotb_bus <https://github.com/cocotb/cocotb-bus>`_ to prevent breaking users that were previously using the bus and testbenching objects. (:pr:`2477`)\n- Add back functionality to ``cocotb.binary.BinaryValue`` that allows the user to change ``binaryRepresentation`` after object creation. (:pr:`2480`)\n\n\ncocotb 1.5.0 (2021-03-11)\n=========================\n\nFeatures\n--------\n\n- Support for building with Microsoft Visual C++ has been added.\n  See :external+cocotb15:ref:`install` for more details. (:pr:`1798`)\n- Makefiles now automatically deduce :external+cocotb15:make:var:`TOPLEVEL_LANG` based on the value of :external+cocotb15:make:var:`VERILOG_SOURCES` and :external+cocotb15:make:var:`VHDL_SOURCES`.\n  Makefiles also detect incorrect usage of :external+cocotb15:make:var:`TOPLEVEL_LANG` for simulators that only support one language. (:pr:`1982`)\n- :external+cocotb15:func:`cocotb.fork()` will now raise a descriptive :class:`TypeError` if a coroutine function is passed into them. (:pr:`2006`)\n- Added ``cocotb.scheduler.start_soon()`` which schedules a coroutine to start *after* the current coroutine yields control.\n  This behavior is distinct from :external+cocotb15:func:`cocotb.fork()` which schedules the given coroutine immediately. (:pr:`2023`)\n- If ``pytest`` is installed, its assertion-rewriting framework will be used to\n  produce more informative tracebacks from the :keyword:`assert` statement. (:pr:`2028`)\n- The handle to :external+cocotb15:envvar:`TOPLEVEL`, typically seen as the first argument to a cocotb test function, is now available globally as :external+cocotb15:data:`cocotb.top`. (:pr:`2134`)\n- The ``units`` argument to :external+cocotb15:class:`~cocotb.triggers.Timer`,\n  :external+cocotb15:class:`~cocotb.clock.Clock` and :external+cocotb15:func:`~cocotb.utils.get_sim_steps`,\n  and the ``timeout_unit`` argument to\n  :external+cocotb15:func:`~cocotb.triggers.with_timeout` and :external+cocotb15:class:`cocotb.test`\n  now accepts ``'step'`` to mean the simulator time step.\n  This used to be expressed using ``None``, which is now deprecated. (:pr:`2171`)\n- :external+cocotb15:meth:`TestFactory.add_option() <cocotb.regression.TestFactory.add_option>` now supports groups of options when a full Cartesian product is not desired. (:pr:`2175`)\n- Added asyncio-style queues, :external+cocotb15:class:`~cocotb.queue.Queue`, :external+cocotb15:class:`~cocotb.queue.PriorityQueue`, and :external+cocotb15:class:`~cocotb.queue.LifoQueue`. (:pr:`2297`)\n- Support for the SystemVerilog type ``bit`` has been added. (:pr:`2322`)\n- Added the ``--lib-dir``,  ``--lib-name`` and ``--lib-name-path`` options to the ``cocotb-config`` command to make cocotb integration into existing flows easier. (:pr:`2387`)\n- Support for using Questa's VHPI has been added.\n  Use :external+cocotb15:make:var:`VHDL_GPI_INTERFACE` to select between using the FLI or VHPI when dealing with VHDL simulations.\n  Note that VHPI support in Questa is still experimental at this time. (:pr:`2408`)\n\n\nBugfixes\n--------\n\n- Assigning Python integers to signals greater than 32 bits wide will now work correctly for negative values. (:pr:`913`)\n- Fix GHDL's library search path, allowing libraries other than ``work`` to be used in simulation. (:pr:`2038`)\n- Tests skipped by default (created with `skip=True`) can again be run manually by setting the :external+cocotb15:envvar:`TESTCASE` variable. (:pr:`2045`)\n- In :external+cocotb15:ref:`Icarus Verilog <sim-icarus>`, generate blocks are now accessible directly via lookup without having to iterate over parent handle. (:pr:`2079`, :pr:`2143`)\n\n    .. code-block:: python\n\n        # Example pseudo-region\n        dut.genblk1       #<class 'cocotb.handle.HierarchyArrayObject'>\n\n    .. consume the towncrier issue number on this line. (:pr:`2079`)\n- Fixed an issue with VHPI on Mac OS and Linux where negative integers were returned as large positive values. (:pr:`2129`)\n\n\nImproved Documentation\n----------------------\n\n- The  :external+cocotb15:ref:`mixed_signal` example has been added,\n  showing how to use HDL helper modules in cocotb testbenches that exercise\n  two mixed-signal (i.e. analog and digital) designs. (:pr:`1051`)\n- New example :external+cocotb15:ref:`matrix_multiplier`. (:pr:`1502`)\n- A :external+cocotb15:ref:`refcard` showing the most used features of cocotb has been added. (:pr:`2321`)\n- A chapter :external+cocotb15:ref:`custom-flows` has been added. (:pr:`2340`)\n\n\nDeprecations and Removals\n-------------------------\n\n- The contents of :external+cocotb15:mod:`cocotb.generators` have been deprecated. (:pr:`2047`)\n- The outdated \"Sorter\" example has been removed from the documentation. (:pr:`2049`)\n- Passing :class:`bool` values to ``expect_error`` option of :external+cocotb15:class:`cocotb.test` is deprecated.\n  Pass a specific :class:`Exception` or a tuple of Exceptions instead. (:pr:`2117`)\n- The system task overloads for ``$info``, ``$warn``, ``$error`` and ``$fatal`` in Verilog and mixed language testbenches have been removed. (:pr:`2133`)\n- ``TestError`` has been deprecated, use :ref:`python:bltin-exceptions`. (:pr:`2177`)\n- The undocumented class ``cocotb.xunit_reporter.File`` has been removed. (:pr:`2200`)\n- Deprecated :external+cocotb15:class:`cocotb.hook` and :external+cocotb15:envvar:`COCOTB_HOOKS`.\n  See the documentation for :external+cocotb15:class:`cocotb.hook` for suggestions on alternatives. (:pr:`2201`)\n- Deprecate ``cocotb.utils.pack`` and ``cocotb.utils.unpack`` and the use of :class:`ctypes.Structure` in signal assignments. (:pr:`2203`)\n- The outdated \"ping\" example has been removed from the documentation and repository. (:pr:`2232`)\n- Using the undocumented custom format :class:`dict` object in signal assignments has been deprecated. (:pr:`2240`)\n- The access modes of many interfaces in the cocotb core libraries were re-evaluated.\n  Some interfaces that were previously public are now private and vice versa.\n  Accessing the methods through their old name will create a :class:`DeprecationWarning`.\n  In the future, the deprecated names will be removed. (:pr:`2278`)\n- The bus and testbenching components in cocotb have been officially moved to the `cocotb-bus <https://github.com/cocotb/cocotb-bus>`_ package.\n  This includes\n  :class:`!cocotb.bus.Bus`,\n  :class:`!cocotb.scoreboard.Scoreboard`,\n  everything in :mod:`!cocotb.drivers`,\n  and everything in :mod:`!cocotb.monitor`.\n  Documentation will remain in the main cocotb repository for now.\n  Old names will continue to exist, but their use will cause a :class:`DeprecationWarning`,\n  and will be removed in the future. (:pr:`2289`)\n\n\nChanges\n-------\n\n- Assigning negative Python integers to handles does an implicit two's compliment conversion. (:pr:`913`)\n- Updated :external+cocotb15:class:`~cocotb_bus.drivers.Driver`, :external+cocotb15:class:`~cocotb_bus.monitors.Monitor`, and all their subclasses to use the :keyword:`async`/:keyword:`await` syntax instead of the :keyword:`yield` syntax. (:pr:`2022`)\n- The package build process is now fully :pep:`517` compliant. (:pr:`2091`)\n- Improved support and performance for :external+cocotb15:ref:`sim-verilator` (version 4.106 or later now required). (:pr:`2105`)\n- Changed how libraries are specified in :external+cocotb15:envvar:`GPI_EXTRA` to allow specifying libraries with paths, and names that don't start with \"lib\". (:pr:`2341`)\n\n\ncocotb 1.4.0 (2020-07-08)\n=========================\n\nFeatures\n--------\n\n- :external+cocotb14:class:`~cocotb.triggers.Lock` can now be used in :keyword:`async with` statements. (:pr:`1031`)\n- Add support for distinguishing between ``net`` (``vpiNet``) and ``reg`` (``vpiReg``) type when using the VPI interface. (:pr:`1107`)\n- Support for dropping into :mod:`pdb` upon failure, via the new :external+cocotb14:envvar:`COCOTB_PDB_ON_EXCEPTION` environment variable. (:pr:`1180`)\n- Simulators run through a Tcl script (Aldec Riviera Pro and Mentor simulators) now support a new :external+cocotb14:make:var:`RUN_ARGS` Makefile variable, which is passed to the first invocation of the tool during runtime. (:pr:`1244`)\n- cocotb now supports the following example of forking a *non-decorated* :external+cocotb14:ref:`async coroutine <async_functions>`.\n\n  .. autolink-skip::\n  .. code-block:: python\n\n     async def example():\n         for i in range(10):\n             await cocotb.triggers.Timer(10, \"ns\")\n\n     cocotb.fork(example())\n\n  ..\n     towncrier will append the issue number taken from the file name here:\n\n  Issue (:pr:`1255`)\n- The cocotb log configuration is now less intrusive, and only configures the root logger instance, ``logging.getLogger()``, as part of :external+cocotb14:func:`cocotb.log.default_config` (:pr:`1266`).\n\n  As such, it is now possible to override the default cocotb logging behavior with something like:\n\n  .. autolink-skip::\n  .. code-block:: python\n\n     # remove the cocotb log handler and formatting\n     root = logging.getLogger()\n     for h in root.handlers[:]:\n         root.remove_handler(h)\n         h.close()\n\n     # add your own\n     logging.basicConfig()\n\n  .. consume the towncrier issue number on this line. (:pr:`1266`)\n- Support for ``vpiRealNet``. (:pr:`1282`)\n- The colored output can now be disabled by the :external+cocotb14:envvar:`NO_COLOR` environment variable. (:pr:`1309`)\n- cocotb now supports deposit/force/release/freeze actions on simulator handles, exposing functionality similar to the respective Verilog/VHDL assignments.\n\n  .. code-block:: python\n\n     from cocotb.handle import Deposit, Force, Release, Freeze\n\n     dut.q <= 1            # A regular value deposit\n     dut.q <= Deposit(1)   # The same, higher verbosity\n     dut.q <= Force(1)     # Force value of q to 1\n     dut.q <= Release()    # Release q from a Force\n     dut.q <= Freeze()     # Freeze the current value of q\n\n  ..\n     towncrier will append the issue number taken from the file name here:\n\n  Issue (:pr:`1403`)\n- Custom logging handlers can now access the simulator time using\n  :external+cocotb14:attr:`logging.LogRecord.created_sim_time`, provided the\n  :external+cocotb14:class:`~cocotb.log.SimTimeContextFilter` filter added by\n  :external+cocotb14:func:`~cocotb.log.default_config` is not removed from the logger instance. (:pr:`1411`)\n- Questa now supports :external+cocotb14:make:var:`PLUSARGS`.\n  This requires that ``tcl.h`` be present on the system.\n  This is likely included in your installation of Questa, otherwise, specify ``CFLAGS=-I/path/to/tcl/includedir``. (:pr:`1424`)\n- The name of the entry point symbol for libraries in :external+cocotb14:envvar:`GPI_EXTRA` can now be customized.\n  The delimiter between each library in the list has changed from ``:`` to ``,``. (:pr:`1457`)\n- New methods for setting the value of a ``cocotb.handle.NonHierarchyIndexableObject`` (HDL arrays). (:pr:`1507`)\n\n  .. code-block:: python\n\n      # Now supported\n      dut.some_array <= [0xAA, 0xBB, 0xCC]\n      dut.some_array.value = [0xAA, 0xBB, 0xCC]\n\n      # For simulators that support n-dimensional arrays\n      dut.some_2d_array <= [[0xAA, 0xBB], [0xCC, 0xDD]]\n      dut.some_2d_array.value = [[0xAA, 0xBB], [0xCC, 0xDD]]\n\n  .. consume the towncrier issue number on this line. (:pr:`1507`)\n- Added support for Aldec's Active-HDL simulator. (:pr:`1601`)\n- Including ``Makefile.inc`` from user makefiles is now a no-op and deprecated. Lines like  ``include $(shell cocotb-config --makefiles)/Makefile.inc`` can be removed from user makefiles without loss in functionality. (:pr:`1629`)\n- Support for using :keyword:`await` inside an embedded IPython terminal, using ``cocotb.ipython_support``. (:pr:`1649`)\n- Added :external+cocotb14:meth:`~cocotb.triggers.Event.is_set`, so users may check if an :external+cocotb14:class:`~cocotb.triggers.Event` has fired. (:pr:`1723`)\n- The :external+cocotb14:func:`cocotb.simulator.is_running` function was added so a user of cocotb could determine if they are running within a simulator. (:pr:`1843`)\n\n\nBugfixes\n--------\n\n- Tests which fail at initialization, for instance due to no ``yield`` being present, are no longer silently ignored. (:pr:`1253`)\n- Tests that were not run because predecessors threw ``cocotb.result.SimFailure``, and caused the simulator to exit, are now recorded with an outcome of ``cocotb.result.SimFailure``.\n  Previously, these tests were ignored. (:pr:`1279`)\n- Makefiles now correctly fail if the simulation crashes before a ``results.xml`` file can be written. (:pr:`1314`)\n- Logging of non-string messages with colored log output is now working. (:pr:`1410`)\n- Getting and setting the value of a ``cocotb.handle.NonHierarchyIndexableObject`` now iterates through the correct range of the simulation object, so arrays that do not start/end at index 0 are supported. (:pr:`1507`)\n- The :external+cocotb14:class:`~cocotb.monitors.xgmii.XGMII` monitor no longer crashes on Python 3, and now assembles packets as :class:`bytes` instead of :class:`str`. The :external+cocotb14:class:`~cocotb.drivers.xgmii.XGMII` driver has expected :class:`bytes` since cocotb 1.2.0. (:pr:`1545`)\n- ``signal <= value_of_wrong_type`` no longer breaks the scheduler, and throws an error immediately. (:pr:`1661`)\n- Scheduling behavior is now consistent before and after the first :keyword:`await` of a :external+cocotb14:class:`~cocotb.triggers.GPITrigger`. (:pr:`1705`)\n- Iterating over ``for generate`` statements using VHPI has been fixed. This bug caused some simulators to crash, and was a regression in version 1.3. (:pr:`1882`)\n- The :external+cocotb14:class:`~cocotb.drivers.xgmii.XGMII` driver no longer emits a corrupted word on the first transfer. (:pr:`1905`)\n\n\nImproved Documentation\n----------------------\n\n- If a makefile uses cocotb's :file:`Makefile.sim`, ``make help`` now lists the supported targets and variables. (:pr:`1318`)\n- A new section :external+cocotb14:ref:`rotating-logger` has been added. (:pr:`1400`)\n- The documentation at http://docs.cocotb.org/ has been restructured,\n  making it easier to find relevant information. (:pr:`1482`)\n\n\nDeprecations and Removals\n-------------------------\n\n- ``cocotb.utils.reject_remaining_kwargs`` is deprecated, as it is no longer\n  needed now that we only support Python 3.5 and newer. (:pr:`1339`)\n- The value of :external+cocotb14:class:`cocotb.handle.StringObject`\\ s is now of type :class:`bytes`, instead of  :class:`str` with an implied ASCII encoding scheme. (:pr:`1381`)\n- ``ReturnValue`` is now deprecated. Use a :keyword:`return` statement instead; this works in all supported versions of Python. (:pr:`1489`)\n- The makefile variable :make:var:`!VERILATOR_TRACE`\n  that was not supported for all simulators has been deprecated.\n  Using it prints a deprecation warning and points to the documentation section\n  :external+cocotb14:ref:`simulator-support` explaining how to get the same effect by other means. (:pr:`1495`)\n- ``cocotb.binary.BinaryValue.get_hex_buff`` produced nonsense and has been removed. (:pr:`1511`)\n- Passing :class:`str` instances to ``cocotb.utils.hexdump`` and ``cocotb.utils.hexdiffs`` is deprecated. :class:`bytes` objects should be passed instead. (:pr:`1519`)\n- ``Makefile.pylib``, which provided helpers for building C extension modules for Python, has been removed.\n  Users of the ``PYTHON_LIBDIR`` and ``PYTHON_INCLUDEDIR`` variables will now have to compute these values themselves.\n  See the ``endian_swapper`` example for how to do this. (:pr:`1632`)\n- Makefile and documentation for the NVC simulator which has never worked have been removed. (:pr:`1693`)\n\n\nChanges\n-------\n\n- cocotb no longer supports Python 2, at least Python 3.5 is now required.\n  Users of Python 2.7 can still use cocotb 1.3, but are heavily encouraged to update.\n  It is recommended to use the latest release of Python 3 for improved performance over older Python 3 versions. (:pr:`767`)\n- Mentor Questa, Aldec Riviera-PRO and GHDL are now started in the directory containing the Makefile and also save :file:`results.xml` there, bringing them in line with the behavior used by other simulators. (:pr:`1598`) (:pr:`1599`) (:pr:`1063`)\n- Tests are now evaluated in order of their appearance in the :external+cocotb14:envvar:`MODULE` environment variable, their stage, and the order of invocation of the :external+cocotb14:class:`cocotb.test` decorator within a module. (:pr:`1380`)\n- All libraries are compiled during installation to the ``cocotb/libs`` directory.\n  The interface libraries ``libcocotbvpi`` and ``libcocotbvhpi`` have been renamed to have a ``_simulator_name`` postfix.\n  The ``simulator`` module has moved to :external+cocotb14:mod:`cocotb.simulator`.\n  The ``LD_LIBRARY_PATH`` environment variable no longer needs to be set by the makefiles, as the libraries now discover each other via ``RPATH`` settings. (:pr:`1425`)\n- cocotb must now be :external+cocotb14:ref:`installed <installation-via-pip>` before it can be used. (:pr:`1445`)\n- ``cocotb.handle.NonHierarchyIndexableObject.value`` is now a list in left-to-right range order of the underlying simulation object.\n  Previously the list was always ordered low-to-high. (:pr:`1507`)\n- Various binary representations have changed type from :class:`str` to :class:`bytes`. These include:\n\n  * ``cocotb.binary.BinaryValue.buff``, which as a consequence means ``cocotb.binary.BinaryValue.assign``, no longer accepts malformed ``10xz``-style :class:`str`\\ s (which were treated as binary).\n  * The objects produced by :func:`!cocotb.generators.byte`, which means that single bytes are represented by :class:`int` instead of 1-character :class:`str`\\ s.\n  * The packets produced by the :external+cocotb14:class:`~cocotb.drivers.avalon.AvalonSTPkts`.\n\n  Code working with these objects may find it needs to switch from creating :class:`str` objects like ``\"this\"`` to :class:`bytes` objects like ``b\"this\"``.\n  This change is a consequence of the move to Python 3. (:pr:`1514`)\n- There's no longer any need to set the ``PYTHON_BIN`` makefile variable, the Python executable automatically matches the one cocotb was installed into. (:pr:`1574`)\n- The :external+cocotb14:make:var:`SIM` setting for Aldec Riviera-PRO has changed from ``aldec`` to ``riviera``. (:pr:`1691`)\n- Certain methods on the :external+cocotb14:mod:`cocotb.simulator` Python module now throw a :exc:`RuntimeError` when no simulator is present, making it safe to use :mod:`!cocotb` without a simulator present. (:pr:`1843`)\n- Invalid values of the environment variable :external+cocotb14:envvar:`COCOTB_LOG_LEVEL` are no longer ignored.\n  They now raise an exception with instructions how to fix the problem. (:pr:`1898`)\n\n\ncocotb 1.3.2 (2020-07-08)\n=========================\n\nNotable changes and bug fixes\n-----------------------------\n\n- Iterating over ``for generate`` statements using VHPI has been fixed.\n  This bug caused some simulators to crash, and was a regression in version 1.3.1. (:pr:`1882`)\n\n\ncocotb 1.3.1 (2020-03-15)\n=========================\n\nNotable changes and bug fixes\n-----------------------------\n- The Makefiles for the Aldec Riviera and Cadence Incisive simulators have been fixed to use the correct name of the VHPI library (``libcocotbvhpi``).\n  This bug prevented VHDL designs from being simulated, and was a regression in 1.3.0. (:pr:`1472`)\n\ncocotb 1.3.0 (2020-01-08)\n=========================\n\nThis will likely be the last release to support Python 2.7.\n\nNew features\n------------\n\n- Initial support for the Verilator simulator (version 4.020 and above).\n  The integration of Verilator into cocotb is not yet as fast or as powerful as it is for other simulators.\n  Please use the latest version of Verilator, and `report bugs <https://github.com/cocotb/cocotb/issues/new>`_ if you experience problems.\n- New makefile variables :external+cocotb13:make:var:`COCOTB_HDL_TIMEUNIT` and :external+cocotb13:make:var:`COCOTB_HDL_TIMEPRECISION` for setting the default time unit and precision that should be assumed for simulation when not specified by modules in the design. (:pr:`1113`)\n- New ``timeout_time`` and ``timeout_unit`` arguments to :external+cocotb13:class:`cocotb.test`, for adding test timeouts. (:pr:`1119`)\n- :external+cocotb13:func:`~cocotb.triggers.with_timeout`, for a shorthand for waiting for a trigger with a timeout. (:pr:`1119`)\n- The ``expect_error`` argument to :external+cocotb13:class:`cocotb.test` now accepts a specific exception type. (:pr:`1116`)\n- New environment variable :external+cocotb13:envvar:`COCOTB_RESULTS_FILE`, to allow configuration of the xUnit XML output filename. (:pr:`1053`)\n- A new ``bus_separator`` argument to :external+cocotb13:class:`cocotb.drivers.BusDriver`. (:pr:`1160`)\n- A new ``start_high`` argument to :external+cocotb13:attr:`cocotb.clock.Clock.start`. (:pr:`1036`)\n- A new :data:`!cocotb.__version__` constant, which contains the version number of the running cocotb. (:pr:`1196`)\n\nNotable changes and bug fixes\n-----------------------------\n\n- ``DeprecationWarning``\\ s are now shown in the output by default.\n- Tracebacks are now preserved correctly for exceptions in Python 2.\n  The tracebacks in all Python versions are now a little shorter.\n- :external+cocotb13:class:`cocotb.external` and :external+cocotb13:class:`cocotb.function` now work more reliably and with fewer race conditions.\n- A failing :keyword:`assert` will be considered a test failure. Previously, it was considered a test *error*.\n- :external+cocotb13:meth:`~cocotb.handle.NonConstantObject.drivers` and :external+cocotb13:meth:`~cocotb.handle.NonConstantObject.loads` now also work correctly in Python 3.7 onwards.\n- :external+cocotb13:class:`~cocotb.triggers.Timer` can now be used with :class:`decimal.Decimal` instances, allowing constructs like ``Timer(Decimal(\"1e-9\"), units=\"sec\")`` as an alternate spelling for ``Timer(100, units=\"us\")``. (:pr:`1114`)\n- Many (editorial) documentation improvements.\n\nDeprecations\n------------\n\n- :external+cocotb13:func:`cocotb.result.raise_error` and :external+cocotb13:func:`cocotb.result.create_error` are deprecated in favor of using Python exceptions directly.\n  :external+cocotb13:exc:`~cocotb.result.TestError` can still be used if the same exception type is desired. (:pr:`1109`)\n- The ``AvalonSTPktsWithChannel`` type is deprecated.\n  Use the ``report_channel`` argument to :external+cocotb13:class:`~cocotb.monitors.avalon.AvalonSTPkts` instead.\n- The ``colour`` attribute of log objects like ``cocotb.log`` or ``some_coro.log`` is deprecated.\n  Use ``cocotb.utils.want_color_output`` instead. (:pr:`1231`)\n\nOther news\n----------\n\n- cocotb is now packaged for Fedora Linux and available as `python-cocotb <https://src.fedoraproject.org/rpms/python-cocotb>`_. (`Fedora bug #1747574 <https://bugzilla.redhat.com/show_bug.cgi?id=1747574>`_) (thanks Ben Rosser)\n\n\ncocotb 1.2.0 (2019-07-24)\n=========================\n\nNew features\n------------\n\n- cocotb is now built as Python package and installable through pip. (:pr:`517`, :pr:`799`, :pr:`800`, :pr:`803`, :pr:`805`)\n- Support for :keyword:`async` functions and generators was added (Python 3 only). Please have a look at :external+cocotb12:ref:`async_functions` for an example how to use this new feature.\n- VHDL block statements can be traversed. (:pr:`850`)\n- Support for Python 3.7 was added.\n\nNotable changes and bug fixes\n-----------------------------\n\n- The heart of cocotb, its scheduler, is now even more robust. Many small bugs, inconsistencies and unreliable behavior have been ironed out.\n- Exceptions are now correctly propagated between coroutines, giving users the \"natural\" behavior they'd expect with exceptions. (:pr:`633`)\n- The :meth:`!handle.setimmediatevalue` function now works for values larger than 32 bit. (:pr:`768`)\n- The documentation was cleaned up, improved and extended in various places, making it more consistent and complete.\n- Tab completion in newer versions of IPython is fixed. (:pr:`825`)\n- Python 2.6 is officially not supported any more. cocotb supports Python 2.7 and Python 3.5+.\n- The cocotb GitHub project moved from ``potentialventures/cocotb`` to ``cocotb/cocotb``.\n  Redirects for old URLs are in place.\n\nDeprecations\n------------\n\n- The `bits` argument to ``cocotb.binary.BinaryValue``, which is now called `n_bits`.\n- The `logger` attribute of log objects like ``cocotb.log`` or ``some_coro.log``, which is now just an alias for ``self``.\n- The ``cocotb.utils.get_python_integer_types`` function, which was intended to be private.\n\nKnown issues\n------------\n\n- Depending on your simulation, cocotb 1.2 might be roughly 20 percent slower than cocotb 1.1.\n  Much of the work in this release cycle went into fixing correctness bugs in the scheduler, sometimes at the cost of performance.\n  We are continuing to investigate this in issue :issue:`961`.\n  Independent of the cocotb version, we recommend using the latest Python 3 version, which is shown to be significantly faster than previous Python 3 versions, and slightly faster than Python 2.7.\n\nPlease have a look at the `issue tracker <https://github.com/cocotb/cocotb/issues>`_ for more outstanding issues and contribution opportunities.\n\n\ncocotb 1.1 (2019-01-24)\n=======================\n\nThis release is the result of four years of work with too many bug fixes, improvements and refactorings to name them all.\n\n\ncocotb 1.0 (2015-02-15)\n=======================\n\nNew features\n------------\n\n- FLI support for ModelSim\n- Mixed Language, Verilog and VHDL\n- Windows\n- 300% performance improvement with VHPI interface\n- WaveDrom support for wave diagrams.\n\n\ncocotb 0.4 (2014-02-25)\n=======================\n\nNew features\n------------\n\n- Issue :issue:`101`: Implement Lock primitive to support mutex\n- Issue :issue:`105`: Compatibility with Aldec Riviera-Pro\n- Issue :issue:`109`: Combine multiple :file:`results.xml` into a single results file\n- Issue :issue:`111`: XGMII drivers and monitors added\n- Issue :issue:`113`: Add operators to ``BinaryValue`` class\n- Issue :issue:`116`: Native VHDL support by implementing VHPI layer\n- Issue :issue:`117`: Added AXI4-Lite Master BFM\n\nBugs fixed\n----------\n\n- Issue :issue:`100`: Functional bug in endian_swapper example RTL\n- Issue :issue:`102`: Only 1 coroutine wakes up of multiple coroutines wait() on an Event\n- Issue :issue:`114`: Fix build issues with Cadence IUS simulator\n\nNew examples\n------------\n\n- Issue :issue:`106`: TUN/TAP example using ping\n\n\ncocotb 0.3 (2013-09-27)\n=======================\n\nThis contains a raft of fixes and feature enhancements.\n\n\ncocotb 0.2 (2013-07-19)\n=======================\n\nNew features\n------------\n\n- Release 0.2 supports more simulators and increases robustness over 0.1.\n- A centralized installation is now supported (see documentation) with supporting libraries build when the simulation is run for the first time.\n\n\ncocotb 0.1 (2013-07-09)\n=======================\n\n- The first release of cocotb.\n- Allows installation and running against Icarus, VCS, Aldec simulators.\n"
  },
  {
    "path": "docs/source/rescap.rst",
    "content": "###############################\nThe cocotb ``rescap`` Testbench\n###############################\n\n.. versionadded:: 1.5\n\nThis is the testbench :mod:`test_rescap` for the design ``rescap`` showing\nhow cocotb can be used in an analog-mixed signal (AMS) simulation.\n\n.. note:: The analog probe module used in this testcase is currently only implemented for the\n          Cadence Incisive and Xcelium simulators (with the AMS option available).\n          Help is appreciated to provide equivalent modules for other simulators.\n\n******************\nOverview Schematic\n******************\n\n.. image:: diagrams/svg/example_rescap.svg\n   :width: 100%\n\n\n**********\nThe Design\n**********\n\nThe design consists of a resistor and capacitor model (both written in Verilog-AMS) connected\nin series in a SystemVerilog module:\n\n.. literalinclude:: ../../examples/mixed_signal/hdl/rescap.sv\n   :caption: rescap.sv\n   :language: systemverilog\n   :start-at: // the design-under-test\n\n\n*************\nThe Testbench\n*************\n\nThe testbench consists of both an :term:`HDL` part and a Python/cocotb part.\nWhile having HDL as part of the testbench is not common with cocotb, it is perfectly possible.\n\nThe HDL part of the Testbench\n=============================\n\nThe testbench :term:`HDL` part is written in SystemVerilog and instantiates the design described above\nas ``i_rescap``.\nIt also contains a probe module for analog values as instance ``i_analog_probe`` —\nimagine this being a multimeter that you quickly connect to different nodes in the design,\nmeasuring either voltage or current.\n\n.. literalinclude:: ../../examples/mixed_signal/hdl/tb_rescap.sv\n   :caption: tb_rescap.sv\n   :language: systemverilog\n   :start-at: import nettypes_pkg\n\nThe probe module can capture voltage and current of a node specified by ``node_to_probe``\n(a string in this module containing a hierarchical path).\nThe capturing occurs whenever there is an edge on the logic signals\n``probe_voltage_toggle`` or ``probe_current_toggle``.\nThe captured values can be read on real-value signals ``voltage`` and ``current`` in this module.\n\nHere is the capture code for ``voltage`` with the \"user-interface\" highlighted:\n\n.. literalinclude:: ../../examples/mixed_signal/hdl/analog_probe_cadence.sv\n   :caption: analog_probe_cadence.sv\n   :language: systemverilog\n   :start-at: var string node_to_probe\n   :end-at: end  // probe_voltage\n   :emphasize-lines: 1-4\n   :dedent: 2\n\nThe cocotb part of the Testbench\n================================\n\n``test_rescap_minimalist``\n--------------------------\n\nThis is a very minimalist testcase.\nTo run it, call:\n\n.. code-block:: bash\n\n    make SIM=xcelium COCOTB_TOPLEVEL=tb_rescap COCOTB_TEST_MODULES=test_rescap_minimalist\n\n\nThe testcase supplies ``vdd``,\nmeasures some pairs of voltage and current at ``vout``\n(same as the ``p`` terminal of the capacitor),\nspaced 50 ns apart,\nand prints the values as shown below.\n\n.. code-block:: bash\n\n        50.00ns INFO     tb_hdl.i_analog_probe@tb_rescap.i_rescap.vout=2.03e-14 V  -2.996e-07 A\n       100.00ns INFO     tb_hdl.i_analog_probe@tb_rescap.i_rescap.vout=3.029 V  2.67e-18 A\n       150.00ns INFO     tb_hdl.i_analog_probe@tb_rescap.i_rescap.vout=4.862 V  3.574e-18 A\n       200.00ns INFO     tb_hdl.i_analog_probe@tb_rescap.i_rescap.vout=5.975 V  6.285e-18 A\n       250.00ns INFO     tb_hdl.i_analog_probe@tb_rescap.i_rescap.vout=6.652 V  6.171e-18 A\n       300.01ns INFO     tb_hdl.i_analog_probe@tb_rescap.i_rescap.vout=7.063 V  6.033e-18 A\n\nThere is no current flowing out of the ``vout`` terminal,\nso the current measurement always yields zero\n(within the accuracy of the analog solver).\n\n``test_rescap``\n---------------\n\nThis is a more advanced testcase.\n\n.. note:: This testcase depends on `matplotlib <https://matplotlib.org/>`_.\n\nThe cocotb part of the testbench provides functions to:\n\n* do the sampling of voltage and current of a given node (:meth:`~test_rescap.ResCap_TB.get_sample_data()`),\n* plot the sampled data to a file (:meth:`~test_rescap.ResCap_TB.plot_data()`).\n\nThe testcase supplies first a positive voltage to the circuit at ``vdd``, followed by a negative voltage,\nthus charging the capacitor in opposite directions.\nThe following graph shows the charge curve.\n\n.. image:: rescap.png\n\nThere is no current flowing out of this output voltage terminal,\nso the current measurement always yields zero.\n\nTo run this testcase, call:\n\n.. code-block:: bash\n\n    make SIM=xcelium COCOTB_TOPLEVEL=tb_rescap COCOTB_TEST_MODULES=test_rescap\n"
  },
  {
    "path": "docs/source/roadmap.rst",
    "content": "*******\nRoadmap\n*******\n\ncocotb is under development;\nhowever there is no \"master plan\".\nWe depend upon users to contribute new features and improvements\nwhile maintainers focus mostly on reviewing PRs, project management, and bugfixes.\nReleases will occur approximately every 6 months.\n\nWe use GitHub issues to track our pending tasks.\nTake a look at the `open feature list <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+is%3Aopen+label%3Atype%3Afeature>`_ to see the work that's lined up,\nor the `list of good first issues <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22>`_ to get your feet wet.\n\nIf you have a GitHub account you can also `raise an enhancement request <https://github.com/cocotb/cocotb/issues/new>`_ to suggest new features.\n\nYou may be interested in discussions about `planned deprecations <https://github.com/cocotb/cocotb/issues?q=is%3Aopen+label%3Atype%3Adeprecation>`_\nor review the `list of already applied deprecations <https://github.com/cocotb/cocotb/issues?q=is%3Aclosed+label%3Atype%3Adeprecation>`_.\n"
  },
  {
    "path": "docs/source/rotating_logger.rst",
    "content": ".. _rotating-logger:\n\n******************\nRotating Log Files\n******************\n\nThe following is an example of how to support rotation of log files.\nIt will keep the newest 3 files which are at most 5 MiB in size.\n\nSee also :ref:`logging-reference-section`,\nand the Python documentation for :class:`logging.handlers.RotatingFileHandler`.\n\n.. code-block:: python\n\n    from logging.handlers import RotatingFileHandler\n    from cocotb.logging import SimLogFormatter\n\n    root_logger = logging.getLogger()\n\n    # undo the setup cocotb did\n    for handler in root_logger.handlers:\n        root_logger.removeHandler(handler)\n        handler.close()\n\n    # do whatever configuration you want instead\n    file_handler = RotatingFileHandler(\"rotating.log\", maxBytes=(5 * 1024 * 1024), backupCount=2)\n    file_handler.setFormatter(SimLogFormatter())\n    root_logger.addHandler(file_handler)\n"
  },
  {
    "path": "docs/source/runner.rst",
    "content": ".. _howto-python-runner:\n\n******************************\nBuilding HDL and Running Tests\n******************************\n\n.. versionadded:: 1.8\n\n.. warning::\n    Python runners and associated APIs are an experimental feature and subject to change.\n\n\nThe Python Test Runner (short: \"runner\") described here is a replacement\nfor cocotb's traditional Makefile flow.\nIt builds the :term:`HDL` for the simulator and runs the tests.\n\nIt is not meant to be the ideal solution for everyone.\nYou can easily integrate cocotb into your custom flow, see :ref:`custom-flows`.\n\n\nUsage with pytest\n=================\n\nThe runner can be used with `pytest <https://pytest.org>`_\nwhich is Python's go-to testing tool.\n\nFor an example on how to set up the runner with pytest,\nsee the file\n:file:`{cocotb-root}/examples/simple_dff/test_dff.py`,\nwith the relevant part shown here:\n\n.. autolink-preface:: from cocotb_tools.runner import get_runner\n.. literalinclude:: ../../examples/simple_dff/test_dff.py\n   :language: python\n   :start-at: def test_simple_dff_runner():\n   :end-at: runner.test(hdl_toplevel=\"dff\", test_module=\"test_dff,\")\n\nYou run this file with pytest like\n\n.. code-block:: bash\n\n    SIM=questa TOPLEVEL_LANG=vhdl pytest examples/simple_dff/test_dff.py\n\nNote that the environment variables ``SIM`` and ``TOPLEVEL_LANG``\nare defined in this test file to set arguments to the runner's\n:meth:`Runner.build <cocotb_tools.runner.Runner.build>` and :meth:`Runner.test <cocotb_tools.runner.Runner.test>` functions;\nthey are not directly handled by the runner itself.\n\nTest filenames and functions have to follow the\n`pytest discovery <https://docs.pytest.org/explanation/goodpractices.html#test-discovery>`_\nconvention in order to be automatically found.\n\nBy default, pytest will only show you a terse \"pass/fail\" information.\nTo see more details of the simulation run,\nincluding the output produced by cocotb,\nadd the ``-s`` option to the ``pytest`` call:\n\n.. code-block:: bash\n\n    SIM=questa TOPLEVEL_LANG=vhdl pytest examples/simple_dff/test_dff.py -s\n\n.. note::\n    Take a look at the\n    :ref:`list of command line flags <pytest:command-line-flags>`\n    in pytest's official documentation.\n\n\nUsage with plugin\n-----------------\n\n:py:mod:`cocotb_tools.pytest.plugin` is a plugin for pytest that will allow to use pytest as regression manager for\ncocotb tests and extend cocotb testing capabilities with pytest features like `fixtures`_.\n\nPlease see the chapter about :ref:`pytest-support` to learn how to enable plugin in your project.\n\nAbove example will just run fine with enabled plugin. But we could also slightly refactor it to gain all benefits from\nusing pytest like showing all available cocotb tests in our project with ``pytest --collect-only`` or adding support for\ncommand line arguments.\n\n.. code:: python\n\n    import pytest\n    from cocotb_tools.pytest.hdl import HDL\n\n\n    @pytest.fixture(name=\"dff\")\n    def dff_fixture(hdl: HDL) -> HDL:\n        \"\"\"Define new HDL design by using pytest fixture.\"\"\"\n        hdl.toplevel = \"dff\"\n\n        proj_path = Path(__file__).resolve().parent\n\n        if hdl.toplevel_lang == \"verilog\":\n            hdl.sources = (proj_path / \"dff.sv\",)\n        else:\n            hdl.sources = (proj_path / \"dff.vhdl\",)\n\n        hdl.build(always=True)\n\n        return hdl\n\n\n    @pytest.mark.cocotb_runner  # NOTE: mark this test function as cocotb runner\n    def test_simple_dff_runner(dff: HDL) -> None:\n        \"\"\"Run HDL simulator with cocotb tests to test DFF.\"\"\"\n        dff.test()\n\n\n    # NOTE: When using plugin, there is no need for using @pytest.mark.cocotb_test or @cocotb.test decorators\n    async def test_simple_dff_feature_1(dut) -> None:\n        \"\"\"Test DFF feature 1.\"\"\"\n\n\nTo run it:\n\n.. code:: shell\n\n    pytest examples/simple_dff/test_dff.py -s --cocotb-toplevel-lang=vhdl --cocotb-simulator=questa\n\n\nDirect usage\n============\n\nYou can also run the test directly, that is, without using pytest, like so\n\n.. code-block:: bash\n\n    python examples/simple_dff/test_dff.py\n\nThis requires that you define the test to run in the testcase file itself.\nFor example, add the following code at the end:\n\n.. code-block:: bash\n\n    if __name__ == \"__main__\":\n        test_simple_dff_runner()\n\nGenerate waveforms\n==================\n\nFor many simulators it is possible to generate simulation waveforms.\nThis can be done by setting the *waves* argument to ``True`` in the\n:meth:`Runner.build <cocotb_tools.runner.Runner.build>` and :meth:`Runner.test <cocotb_tools.runner.Runner.test>` functions.\nIt is also possible to set the environment variable :envvar:`WAVES` to\na non-zero value to generate waveform files at run-time without modifying the test code, e.g.,\n\n.. code-block:: bash\n\n    WAVES=1 pytest examples/simple_dff/test_dff.py\n\nSimilarly, it is possible to disable the waveform generation set in the test\ncode by setting ``WAVES`` to 0.\n\nStarting in GUI mode/viewing waveforms\n======================================\n\nTo start the simulator GUI or, for simulators not having a GUI, view\nthe waveform file in a waveform viewer after the simulation, it is possible\nto set the *gui* argument to ``True`` in :meth:`Runner.test <cocotb_tools.runner.Runner.test>`.\nIt is also possible to set the :envvar:`GUI` environment variable to a non-zero value, e.g.,\n\n.. code-block:: bash\n\n    GUI=1 pytest examples/simple_dff/test_dff.py\n\nFor simulators without a GUI, cocotb will open a waveform viewer. Either `Surfer <https://surfer-project.org/>`_\nor `GTKWave <https://gtkwave.github.io/gtkwave/>`_, in that order, if available in the system path.\nTo specify preferred waveform viewer, the :envvar:`COCOTB_WAVEFORM_VIEWER` environment variable\ncan be used. This can also be used to set, e.g., the ``surfer.sh`` startup script for WSL.\n\nAPI\n===\n\nThe API of the Python runner is documented in section :ref:`api-runner`.\n\n\n.. _fixtures: https://docs.pytest.org/en/stable/explanation/fixtures.html#about-fixtures\n"
  },
  {
    "path": "docs/source/simulator_support.rst",
    "content": ".. _simulator-support:\n\n*****************\nSimulator Support\n*****************\n\nThis page lists the simulators that cocotb can be used with\nand documents specifics, limitations, workarounds etc.\n\nIn general, cocotb can be used with any simulator supporting the industry-standard VPI, VHPI or FLI interfaces.\nHowever, in practice simulators exhibit small differences in behavior that cocotb mostly takes care of.\n\nIf a simulator you would like to use with cocotb is not listed on this page\nopen an issue at the `cocotb GitHub issue tracker <https://github.com/cocotb/cocotb/issues>`_.\n\n\n.. _sim-icarus:\n\nIcarus Verilog\n==============\n\n.. note::\n\n    **cocotb supports Icarus 11.0+.**\n\nIn order to use this simulator, set :make:var:`SIM` to ``icarus``:\n\n.. code-block:: bash\n\n    make SIM=icarus\n    # or\n    SIM=icarus [...] pytest [...]\n\nFor simulator-specific limitations when running with the :ref:`Python Runner <howto-python-runner>` flow,\nsee :class:`cocotb_tools.runner.Icarus`.\n\n.. note::\n\n    A working installation of `Icarus Verilog <https://github.com/steveicarus/iverilog>`_ is required.\n    You can find installation instructions `in the Icarus Verilog Installation Guide <https://iverilog.fandom.com/wiki/Installation_Guide>`_.\n\n.. _sim-icarus-waveforms:\n\nWaveforms\n---------\n\nIcarus Verilog can produce waveform traces in the FST format.\nFST traces are much smaller and more efficient to write than VCD.\nThey can be viewed with GTKWave or with `Surfer <https://surfer-project.org/>`_.\n\nTo enable FST tracing, set :make:var:`WAVES` to ``1``.\n\n.. code-block:: bash\n\n    make SIM=icarus WAVES=1\n\nBy default, the wave file will be named `<hdl_toplevel>.fst`. Unlike other simulators, it will be placed in the build directory, rather than the test directory.\n\nTo redirect the wave file to a different location, use the plusarg `dumpfile_path` when running the test.\n\n.. _sim-icarus-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:icarus <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Aicarus>`_\n\n\n.. _sim-verilator:\n\nVerilator\n=========\n\n.. note::\n\n    **cocotb supports Verilator 5.036+.**\n\nIn order to use this simulator, set :make:var:`SIM` to ``verilator``:\n\n.. code-block:: bash\n\n    make SIM=verilator\n    # or\n    SIM=verilator [...] pytest [...]\n\nFor simulator-specific limitations when running with the :ref:`Python Runner <howto-python-runner>` flow,\nsee :class:`cocotb_tools.runner.Verilator`.\n\n.. note::\n\n    A working installation of `Verilator <https://www.veripool.org/verilator/>`_ is required.\n    You can find installation instructions `in the Verilator documentation <https://verilator.org/guide/latest/install.html>`_.\n\n.. versionadded:: 1.3\n\n.. versionchanged:: 1.5 Improved cocotb support and greatly improved performance when using a higher time precision.\n\n.. versionchanged:: 2.0\n\n    Reimplemented the Verilator evaluator loop used in cocotb tests.\n    This allowed for better performance and behavior more consistent with event-based simulators.\n    Additionally, added support for inertial writes,\n    which noticeably improves performance.\n\nCoverage\n--------\n\nTo enable :term:`HDL` code coverage, add Verilator's coverage option(s) to the :make:var:`EXTRA_ARGS` make variable, for example:\n\n .. code-block:: make\n\n    EXTRA_ARGS += --coverage\n\nThis will result in coverage data being written to :file:`coverage.dat`.\n\n.. _sim-verilator-waveforms:\n\nWaveforms\n---------\n\nTo get waveforms in VCD format, add Verilator's trace option(s) to the\n:make:var:`EXTRA_ARGS` make variable, for example in a Makefile:\n\n  .. code-block:: make\n\n    EXTRA_ARGS += --trace --trace-structs\n\nTo set the same options on the command line, use ``EXTRA_ARGS=\"--trace --trace-structs\" make ...``.\nA VCD file named ``dump.vcd`` will be generated in the current directory.\n\nVerilator can produce waveform traces in the FST format.\nFST traces are much smaller and more efficient to write.\nThey can be viewed with GTKWave or with `Surfer <https://surfer-project.org/>`_.\n\nTo enable FST tracing, add ``--trace-fst`` to :make:var:`EXTRA_ARGS` as shown below.\n\n  .. code-block:: make\n\n    EXTRA_ARGS += --trace --trace-fst --trace-structs\n\nThe resulting file will be :file:`dump.fst` and can be opened by ``gtkwave dump.fst``.\n\nPower Estimation\n----------------\n\nVerilator (versions 5.042 and higher) can generate SAIF activity files for use in power estimation.\nThese compact files do not record the state of signals over time, rather they record general switching statistics to calculate the amount of power dissipated by each signal.\n\nTo enable SAIF tracing, if using the Makefiles, add ``--trace-saif`` to :make:var:`EXTRA_ARGS` as shown below.\n\n.. code-block:: make\n\n    EXTRA_ARGS += --trace --trace-saif --trace-structs\n\nIf you are using the runner add ``--trace-saif`` to the ``build_args`` argument to :func:`.Runner.build`.\n\n.. code-block:: python\n\n    runner.build(\n        build_args=[\"--trace\", \"--trace-saif\", \"--trace-structs\"],\n    )\n\nThe resulting file will be :file:`dump.saif` which can be processed by most synthesis tools.\n\n.. note::\n\n    For any given build, only one output format (VCD, FST, or SAIF) can be used.\n    If both waveform tracing and activity tracing are needed, they should be done with different builds.\n\n.. _sim-verilator-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:verilator <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Averilator>`_\n\n\n.. _sim-vcs:\n\nSynopsys VCS\n============\n\nIn order to use this simulator, set :make:var:`SIM` to ``vcs``:\n\n.. code-block:: bash\n\n    make SIM=vcs\n    # or\n    SIM=vcs [...] pytest [...]\n\nFor simulator-specific limitations when running with the :ref:`Python Runner <howto-python-runner>` flow,\nsee :class:`cocotb_tools.runner.Vcs`.\n\n.. note::\n\n    A working installation of the simulator itself is required.\n\ncocotb currently only supports :term:`VPI` for Synopsys VCS, not :term:`VHPI`.\n\n.. _sim-vcs-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:vcs <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Avcs>`_\n\n\n.. _sim-aldec:\n.. _sim-riviera:\n\nAldec Riviera-PRO\n=================\n\nIn order to use this simulator, set :make:var:`SIM` to ``riviera``:\n\n.. code-block:: bash\n\n    make SIM=riviera\n    # or\n    SIM=riviera [...] pytest [...]\n\nFor simulator-specific limitations when running with the :ref:`Python Runner <howto-python-runner>` flow,\nsee :class:`cocotb_tools.runner.Riviera`.\n\n.. note::\n\n    A working installation of the simulator itself is required.\n\n.. note::\n\n   On Windows, do not install the C++ compiler, i.e. unselect it during the installation process of Riviera-PRO.\n   (A workaround is to remove or rename the ``mingw`` directory located in the Riviera-PRO installation directory.)\n\n.. deprecated:: 1.4\n\n   Support for Riviera-PRO was previously available with ``SIM=aldec``.\n\nThe :envvar:`LICENSE_QUEUE` environment variable can be used for this simulator –\nthis setting will be mirrored in the TCL ``license_queue`` variable to control runtime license checkouts.\n\n\n.. _sim-aldec-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:riviera <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Ariviera>`_\n\n\n.. _sim-activehdl:\n\nAldec Active-HDL\n================\n\nIn order to use this simulator, set :make:var:`SIM` to ``activehdl``:\n\n.. code-block:: bash\n\n    make SIM=activehdl\n\nThis simulator is not currently supported in the :ref:`Python Runner <howto-python-runner>` flow.\n\n.. note::\n\n    A working installation of the simulator itself is required.\n\n.. warning::\n\n    cocotb does not work with some versions of Active-HDL (see :issue:`1494`).\n\n    Known affected versions:\n\n    - Aldec Active-HDL 10.4a\n    - Aldec Active-HDL 10.5a\n\n.. _sim-activehdl-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:activehdl <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Aactivehdl>`_\n\n\n.. _sim-questa:\n\nMentor/Siemens EDA Questa\n=========================\n\nIn order to use this simulator, set :make:var:`SIM` to ``questa``:\n\n.. code-block:: bash\n\n    make SIM=questa\n    # or\n    SIM=questa [...] pytest [...]\n\nFor simulator-specific limitations when running with the :ref:`Python Runner <howto-python-runner>` flow,\nsee :class:`cocotb_tools.runner.Questa`.\n\n.. note::\n\n    A working installation of the simulator itself is required.\n\ncocotb implements two flows for Questa.\nThe most suitable flow is chosen based on the Questa version being used.\n\nThe newer **QIS/Qrun flow** uses the Questa Information System (QIS) together with the ``qrun`` command.\nOne of the most visible user-facing benefits of the ``qrun`` flow is the ability to automatically order VHDL sources.\nThe use of the QIS should reduce the overhead from accessing design internals at runtime and mandates the use of Visualizer as GUI.\n\nThe QIS/Qrun flow is chosen automatically if Questa 2025.2 or newer is detected.\nUsers can explicitly use the QIS/Qrun flow with :make:var:`SIM=questa-qisqrun <SIM>`.\nIf you are passing simulator-specific arguments to the Makefile, we recommend not relying on the automatic flow selection and instead explicitly selecting a flow by using either ``SIM=questa-qisqrun`` or ``SIM=questa-compat`` to ensure they are interpreted as expected.\n\nThe **compat flow** uses the commands ``vlog``, ``vopt`` and ``vsim`` to build and run the simulation, together with the ``+acc`` switch to enable design access for cocotb.\n\nThe compat flow is used for ModelSim and Questa older than 2025.2.\nUsers can explicitly use the compat flow with ``SIM=questa-compat``.\n\nIn order to start Questa with the graphical interface and for the simulator to remain active after the tests have completed, set :make:var:`GUI=1`.\n\nUsers of the QIS/Qrun flow can set ``GUI=livesim`` to open Visualizer during the simulation in Live Simulation mode (an alias for ``GUI=1``), or set ``GUI=postsim`` to open Visualizer after the simulation has ended (Post Simulation mode).\n\nStarting with Questa 2022.3 and cocotb 1.7 users with VHDL toplevels can choose between two communication interfaces between Questa and cocotb: the proprietary FLI and VHPI.\nFor backwards-compatibility cocotb defaults to FLI.\nUsers can choose VHPI instead by setting the :envvar:`VHDL_GPI_INTERFACE` environment variable to ``vhpi`` before running cocotb.\n\nFor more information, see :ref:`sim-modelsim`.\n\n.. _sim-questa-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:questa <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Aquesta>`_\n\n\n.. _sim-modelsim:\n\nMentor/Siemens EDA ModelSim\n===========================\n\nIn order to use this simulator, set :make:var:`SIM` to ``modelsim``:\n\n.. code-block:: bash\n\n    make SIM=modelsim\n\nThis simulator is not currently supported in the :ref:`Python Runner <howto-python-runner>` flow.\n\n.. note::\n\n    A working installation of the simulator itself is required.\n\nAny ModelSim PE or ModelSim PE derivatives (like the ModelSim Microsemi, Intel, Lattice Editions) do not support the VHDL :term:`FLI` feature.\nIf you try to use them with :term:`FLI`, you will see a ``vsim-FLI-3155`` error:\n\n.. code-block:: bash\n\n    ** Error (suppressible): (vsim-FLI-3155) The FLI is not enabled in this version of ModelSim.\n\nModelSim DE and SE (and Questa, of course) support the :term:`FLI`.\n\nIn order to start ModelSim with the graphical interface and for the simulator to remain active after the tests have completed, set :make:var:`GUI=1 <GUI>`.\n\nIf you have previously launched a test without this setting, you might have to delete the :make:var:`SIM_BUILD` directory (``sim_build`` by default) to get the correct behavior.\n\n.. _sim-modelsim-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:modelsim <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Amodelsim>`_\n\n\n.. _sim-incisive:\n\nCadence Incisive\n================\n\nIn order to use this simulator, set :make:var:`SIM` to ``ius``:\n\n.. code-block:: bash\n\n    make SIM=ius\n\nThis simulator is not currently supported in the :ref:`Python Runner <howto-python-runner>` flow.\n\n.. note::\n\n    A working installation of the simulator itself is required.\n\nFor more information, see :ref:`sim-xcelium`.\n\n.. _sim-incisive-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:ius <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Aius>`_\n\n\n.. _sim-xcelium:\n\nCadence Xcelium\n===============\n\nIn order to use this simulator, set :make:var:`SIM` to ``xcelium``:\n\n.. code-block:: bash\n\n    make SIM=xcelium\n    # or\n    SIM=xcelium [...] pytest [...]\n\nFor simulator-specific limitations when running with the :ref:`Python Runner <howto-python-runner>` flow,\nsee :class:`cocotb_tools.runner.Xcelium`.\n\n.. note::\n\n    A working installation of the simulator itself is required.\n\nThe simulator automatically loads :term:`VPI` even when only :term:`VHPI` is requested.\n\nTesting designs with VHDL toplevels is only supported with Xcelium 23.09.004 and newer.\n\n.. _sim-xcelium-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:xcelium <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Axcelium>`_\n\n\n.. _sim-ghdl:\n\nGHDL\n====\n\n.. note::\n\n    **cocotb supports GHDL 2.0+.**\n\nIn order to use this simulator, set :make:var:`SIM` to ``ghdl``:\n\n.. code-block:: bash\n\n    make SIM=ghdl\n    # or\n    SIM=ghdl [...] pytest [...]\n\nFor simulator-specific limitations when running with the :ref:`Python Runner <howto-python-runner>` flow,\nsee :class:`cocotb_tools.runner.Ghdl`.\n\n.. note::\n\n    A working installation of `GHDL <https://ghdl.github.io/ghdl/about.html>`_ is required.\n    You can find installation instructions `in the GHDL documentation <https://ghdl.github.io/ghdl/getting.html>`_.\n\nNoteworthy is that despite GHDL being a VHDL simulator, it implements the :term:`VPI` interface.\nThis prevents cocotb from accessing some VHDL-specific constructs, like 9-value signals.\n\nTo specify a VHDL architecture to simulate, set the ``ARCH`` make variable to the architecture name.\n\n.. _sim-ghdl-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:ghdl <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Aghdl>`_\n\n\n.. _sim-ghdl-waveforms:\n\nWaveforms\n---------\n\nTo get waveforms in VCD format, set the :make:var:`SIM_ARGS` option to ``--vcd=anyname.vcd``,\nfor example in a Makefile:\n\n.. code-block:: make\n\n    SIM_ARGS+=--vcd=anyname.vcd\n\nThe option can be set on the command line, as shown in the following example.\n\n.. code-block:: bash\n\n    SIM_ARGS=--vcd=anyname.vcd make SIM=ghdl\n\nA VCD file named :file:`anyname.vcd` will be generated in the current directory.\n\n:make:var:`SIM_ARGS` can also be used to pass command line arguments related to :ref:`other waveform formats supported by GHDL <ghdl:export_waves>`.\n\n\n.. _sim-nvc:\n\nNVC\n===\n\n.. note::\n\n    NVC version **1.11.0** or later is required.\n\n.. note::\n\n    Using NVC versions greater than **1.16.0** will automatically add the ``--preserve-case`` option build commands.\n    This is standards-compliant behavior and may become default behavior in NVC, so think twice before overriding it.\n\nIn order to use this simulator, set :make:var:`SIM` to ``nvc``:\n\n.. code-block:: bash\n\n    make SIM=nvc\n    # or\n    SIM=nvc [...] pytest [...]\n\nFor simulator-specific limitations when running with the :ref:`Python Runner <howto-python-runner>` flow,\nsee :class:`cocotb_tools.runner.Nvc`.\n\n.. _sim-nvc-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:nvc <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Anvc>`_\n\nCoverage\n--------\n\nTo enable code coverage, add ``--cover`` to :make:var:`SIM_ARGS`, for example\nin a Makefile:\n\n.. code-block:: make\n\n    SIM_ARGS += --cover\n\nSpecifying types of coverage is also supported.\nFor example, to collect statement and branch coverage:\n\n.. code-block:: make\n\n    SIM_ARGS += --cover=statement,branch\n\nThe ``covdb`` files will be placed in the :make:var:`TOPLEVEL_LIBRARY` subdirectory of :make:var:`SIM_BUILD`.\nFor instructions on how to specify coverage types and produce a report, refer to `NVC's code coverage documentation <https://www.nickg.me.uk/nvc/manual.html#CODE_COVERAGE>`_.\n\n.. _sim-nvc-waveforms:\n\nWaveforms\n---------\n\nTo get waveforms in FST format, set the :make:var:`SIM_ARGS` option to ``--wave=anyname.fst``, for example in a Makefile:\n\n.. code-block:: make\n\n    SIM_ARGS += --wave=anyname.fst\n\n:make:var:`SIM_ARGS` can also be used to set the waveform output to VCD by adding ``--format=vcd``.\n\n\n.. _sim-cvc:\n\nTachyon DA CVC\n==============\n\nIn order to use `Tachyon DA <http://www.tachyon-da.com/>`_'s `CVC <https://github.com/cambridgehackers/open-src-cvc>`_ simulator,\nset :make:var:`SIM` to ``cvc``:\n\n.. code-block:: bash\n\n    make SIM=cvc\n\nThis simulator is not currently supported in the :ref:`Python Runner <howto-python-runner>` flow.\n\n.. note::\n\n    A working installation of the simulator itself is required.\n\nNote that cocotb's makefile is using CVC's interpreted mode.\n\n.. _sim-cvc-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:cvc <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Acvc>`_\n\n.. _sim-dsim:\n\nSiemens DSim\n============\n\n.. warning::\n\n    DSim support for cocotb is experimental.\n    Some features of cocotb may not work correctly or at all.\n    At least DSim version 2025 is required.\n\nIn order to use this simulator, set :make:var:`SIM` to ``dsim``:\n\n.. code-block:: bash\n\n    make SIM=dsim\n    # or\n    SIM=dsim [...] pytest [...]\n\nFor simulator-specific limitations when running with the :ref:`Python Runner <howto-python-runner>` flow,\nsee :class:`cocotb_tools.runner.DSim`.\n\n.. note::\n\n    A working installation of `DSim <https://altair.com/dsim>`_ is required.\n    You can install DSim simulator directly from `Altair Marketplace <https://altairone.com/Marketplace?tab=Info&app=dsim>`_ and find information regarding getting a free license.\n\n.. _sim-dsim-waveforms:\n\nWaveforms\n---------\n\nDSim can produce waveform traces in the VCD format.\nThey can be viewed with GTKWave or with `Surfer <https://surfer-project.org/>`_.\n\nTo enable VCD tracing, set :make:var:`WAVES` to ``1``.\n\n.. code-block:: bash\n\n    make SIM=dsim WAVES=1\n\n.. _sim-dsim-issues:\n\nReported Issues for this Simulator\n----------------------------------\n\n* `All issues with label category:simulators:dsim <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Acategory%3Asimulators%3Adsim>`_\n\n.. versionadded:: 2.0\n"
  },
  {
    "path": "docs/source/spelling_wordlist.txt",
    "content": "AMS\nAXI\nAldec\nAltera\nAvalon\nCosimulation\nDeprecations\nFLI\nGPI\nGTKWave\nGigabit\nGitHub\nGitLab\nHDL\nIPython\nIndices\nLite\nMiB\nMicrosemi\nMinGW\nModelSim\nMsys\nNVC\nPyPi\nQuesta\nQuickstart\nREADME\nRoadmap\nSynopsys\nSystemVerilog\nTODO\nTachyon\nTcl\nUbuntu\nVHDL\nVHPI\nVPI\nVerilator\nVerilog\nWaveDrom\nWiki\nXML\nXcelium\nbackpressure\nbugfixes\nbuiltin\ncallgraph\ncartesian\ncocotb\ncoroutine\ncoroutines\ndiff\ndocstring\ndurations\nendian\nendianness\nfilename\ngotchas\nhexdump\nimplementors\nincrementing\nindexable\ninstallable\ninstantiation\niterable\nlibgpi\nlibpython\nlookup\nloopback\nmacOS\nmakefile\nmakefiles\nmetaclass\nmetadata\nmicrocontroller\nmsys\nmultimeter\nmutex\nnamespace\nnamespaced\nnamespaces\nns\npacketized\npicoseconds\nplusargs\npostfix\npre\nprebuilt\nprepend\nprepends\nps\nrefactorings\nruntime\nschedulable\nscoreboarded\nscoreboarding\nsignedness\nsimulatormodule\nstacktrace\nsubclassed\nsubclasses\nsubdirectories\nsubdirectory\nsubtypes\nswapper\ntestbench\ntestbenches\ntestbenching\ntestcase\ntestcases\ntimeout\ntimestamps\ntimestep\ntimesteps\ntodo\ntoplevel\ntracebacks\ntrimmable\ntuple\ntuples\nunhandled\nunresolvable\nunselect\nutils\nversa\nwaitable\nwaveform\nwaveforms\nwhitespace\nxUnit\n"
  },
  {
    "path": "docs/source/support.rst",
    "content": "************\nGetting Help\n************\n\nGetting in Contact with a Maintainer\n====================================\n\nAll of the :ref:`maintainers <maintainers>` are active on the `Gitter channel <https://gitter.im/cocotb/Lobby>`__.\nThey prefer inquiries go through direct messages on Gitter,\nor by mentioning them in the main `cocotb Gitter channel <https://gitter.im/cocotb/Lobby>`__ using ``@{maintainer name}``.\nMaintainers are unpaid volunteers, so it might take a while for a maintainer to get back to you.\n\n\nCode of Conduct\n===============\n\nThe cocotb development community aims to be welcoming to everyone.\nThe `FOSSi Foundation Code of Conduct <https://www.fossi-foundation.org/code-of-conduct>`__ applies.\nPlease contact any of the maintainers if you feel uncomfortable in the cocotb development community.\n"
  },
  {
    "path": "docs/source/timing_model.rst",
    "content": ".. _timing-model:\n\n****************\nThe Timing Model\n****************\n\ncocotb's timing model is a simplification of the :term:`VPI`\\ 's, :term:`VHPI`\\ 's, and :term:`FLI`\\ 's timing model,\nmade by choosing the common subset of the most important aspects of those timing models.\n\nLike the aforementioned timing models, cocotb's is organized around :term:`time steps <time step>`.\nA time step is a single point in simulated time,\ncomprised of one or more :term:`evaluation cycles <evaluation cycle>`.\nFor example, there is a time step that occurs on a rising clock edge, and the next time step is typically on the falling clock edge.\nMoving between time steps will advance simulated time.\n\nEvaluation cycles occur when HDL or cocotb code is executed in reaction to events,\nsuch as simulated time advancing or a signal or variable changing value.\nThe executed code tends to create more events, leading to the next evaluation cycle.\nEvaluation cycles don't advance simulated time.\n\ncocotb provides Python timing :term:`triggers <trigger>` allowing users to move through time steps and evaluation cycles.\n:keyword:`await`\\ ing these triggers will cause the current cocotb coroutine to block until simulation reaches the specific point in time.\n\nThe Time Step\n=============\n\nTime steps are split into five phases in the cocotb timing model,\nsome of which are repeated many times.\n\nThe time step starts in the :ref:`beginning-of-time-step` phase and ends in the :ref:`end-of-time-step` phase.\nEvaluation cycles occur between these two points,\nwith the simulator running in the :ref:`evaluation` phases,\nand cocotb code reacting in the :ref:`values-change` and :ref:`values-settle` phases.\n\n.. figure:: diagrams/svg/timing_model.svg\n   :align: center\n\n   The phases of a time step\n\n\n.. _beginning-of-time-step:\n\nBeginning of Time Step\n----------------------\n\nThis is the phase where the :class:`.NextTimeStep` and :class:`.Timer` triggers will return.\nThis phase begins the time step before any HDL code has executed or any signal or variable have changed value.\nIn this phase, users are allowed to read and write any signal or variable.\nOnce control returns to the simulator, it will enter the :ref:`evaluation` phase.\n\nUsers can :keyword:`await` the following triggers in this phase:\n\n* :class:`.NextTimeStep` to move to the :ref:`beginning of the next time step <beginning-of-time-step>`.\n* :class:`.Timer` to move to the :ref:`beginning of any following time step <beginning-of-time-step>`.\n* :class:`.ValueChange`, :class:`.RisingEdge` or :class:`.FallingEdge` to move to the next :ref:`values-change` phase where the requested value changes.\n* :class:`.ReadWrite` to move to the :ref:`end of the first evaluation cycle <values-settle>`.\n* :class:`.ReadOnly` to move to the :ref:`end of the current time step <end-of-time-step>`.\n\n.. _evaluation:\n\nHDL Evaluation\n--------------\n\nThis phase represents the time spent in the simulator evaluating ``always`` or ``process`` blocks, continuous assignments, or other HDL code.\nIf a signal or variable passed to a :class:`.ValueChange`, :class:`.RisingEdge`, or :class:`.FallingEdge` trigger changes value accordingly,\nthe simulator will enter the :ref:`values-change` phase.\nAlternatively, after all values have changed and all HDL has finished executing,\nit will enter the :ref:`values-settle` phase.\n\n.. note::\n    cocotb is not executing during this phase.\n\n.. _values-change:\n\nValues Change\n-------------\n\nThis is the phase where the :class:`.ValueChange`, :class:`.RisingEdge`, or :class:`.FallingEdge` triggers will return.\nThe signal or variable given to the trigger will have changed value,\nbut no HDL that reacts to that value change will have executed;\nmeaning \"downstream\" signals and variables will not have updated values.\nIn this phase, users can read and write values on any signal or variable.\nAfter control returns to the simulator, it will re-enter the :ref:`evaluation` phase.\n\nThere are 0 or more of these phases in a time step and they are not distinguishable from cocotb.\nThere is no way to jump to any particular one of these phases in a time step.\n\nUsers can :keyword:`await` the following triggers in this phase:\n\n* :class:`.NextTimeStep` to move to the :ref:`beginning of the next time step <beginning-of-time-step>`.\n* :class:`.Timer` to move to the :ref:`beginning of any following time step <beginning-of-time-step>`.\n* :class:`.ValueChange`, :class:`.RisingEdge`, or :class:`.FallingEdge` to move to the next :ref:`values-change` phase where the requested value changes.\n* :class:`.ReadWrite` to move to the :ref:`end of the current evaluation cycle <values-settle>`.\n* :class:`.ReadOnly` to move to the :ref:`end of the current time step <end-of-time-step>`.\n\n.. _values-settle:\n\nValues Settle\n-------------\n\nThis is the phase where the :class:`.ReadWrite` trigger will return.\nAll signals and variables will have their final values and all HDL will have executed for the time step.\nIn this phase, users can read and write values on any signal or variable.\nIf they do write, the simulator will re-enter the :ref:`evaluation` phase.\nAlternatively, the simulator will enter the :ref:`end-of-time-step` phase.\n\nThere are 0 or more of these phases in a time step and they are not distinguishable from cocotb.\nThere is no way to jump to any particular one of these phases in a time step.\n\nUsers can :keyword:`await` the following triggers in this phase:\n\n* :class:`.NextTimeStep` to move to the :ref:`beginning of the next time step <beginning-of-time-step>`.\n* :class:`.Timer` to move to the :ref:`beginning of any following time step <beginning-of-time-step>`.\n* :class:`.ValueChange`, :class:`.RisingEdge`, or :class:`.FallingEdge` to move to the next :ref:`values-change` phase where the requested value changes.\n* :class:`.ReadWrite` to move to the :ref:`end of the next evaluation cycle <values-settle>`.\n* :class:`.ReadOnly` to move to the :ref:`end of the current time step <end-of-time-step>`.\n\n.. _end-of-time-step:\n\nEnd of Time Step\n----------------\n\nThis is the phase where the :class:`.ReadOnly` trigger will return.\nAll signals and variables will have their final values and all HDL will have executed for the time step.\nHowever, unlike the :ref:`values-settle` phase, no writes are allowed in this phase;\nmeaning no new evaluation cycles can occur.\nUsers can still freely read in this phase.\nOnce control returns to the simulator, it will move to the :ref:`beginning of the next time step <beginning-of-time-step>`.\n\nUsers can :keyword:`await` the following triggers in this phase:\n\n* :class:`.NextTimeStep` to move to the :ref:`beginning of the next time step <beginning-of-time-step>`.\n* :class:`.Timer` to move to the :ref:`beginning of any following time step <beginning-of-time-step>`.\n* :class:`.ValueChange`, :class:`.RisingEdge`, or :class:`.FallingEdge` to move to the next :ref:`values-change` phase where the requested value changes.\n\n.. note::\n    ``await ReadWrite()`` or ``await ReadOnly()`` in this phase **are not** well defined behaviors and will result in a :exc:`RuntimeError` being raised.\n\n\nTriggers\n========\n\n:class:`!Timer`\n---------------\n\nThe :class:`.Timer` trigger allows users to jump forward in simulated time arbitrarily.\nIt will always return at the :ref:`beginning of time step <beginning-of-time-step>`.\nSimulated time cannot move backwards, meaning negative and ``0`` time values are not valid.\n:class:`!Timer` cannot be used to move between evaluation cycles, only between time steps.\n\n:class:`!NextTimeStep`\n----------------------\n\n:class:`.NextTimeStep` is like :class:`.Timer`,\nexcept that it always returns at the :ref:`beginning of the next time step <beginning-of-time-step>`.\nThe next time step could be at any simulated time thereafter, **or never**.\nIt is only safe to use if there is scheduled behavior that will cause another time step to occur.\nUsing :class:`.NextTimeStep` in other situations will result in undefined behavior.\n\n:class:`!ValueChange` / :class:`!RisingEdge` / :class:`!FallingEdge`\n--------------------------------------------------------------------\n\nThe edge triggers (:class:`.ValueChange`, :class:`.RisingEdge`, and :class:`.FallingEdge`)\nallow users to block a cocotb coroutine until a signal or variable changes value at some point in the future.\nThat point in the future may be in a different evaluation cycle in the same time step, in a different time step, **or never**.\nUsing an edge trigger on a signal or variable that will never change value will result in undefined behavior.\n\nAfter returning, an edge trigger returns at the point where the signal or variable given to the trigger will have changed value,\nbut no HDL that reacts to that value change will have executed;\nmeaning \"downstream\" signals and variables will not have updated values.\n\nUsing a flip-flop for example, after an ``await RisingEdge(dut.clk)``, ``dut.clk`` will be ``1``,\nbut the output of the flip-flop will remain the previous value.\nWait until :class:`.ReadWrite` or :class:`.ReadOnly` to see the output change.\n\n:class:`!ReadWrite`\n-------------------\n\n:class:`.ReadWrite` allows users to synchronize with the :ref:`end of the current evaluation cycle <values-settle>`.\nAt the end of the evaluation cycle, all signals and variables will have their final values and all HDL will have executed for the time step.\nHowever, users are still allowed to write.\nThis can be useful when trying to react combinationally to a registered signal.\n\nFor example, to set ``dut.valid`` high in reaction to ``dut.ready`` going high as a combinational circuit would,\nusers could write the following.\n\n.. code-block:: python\n\n    while True:\n        await RisingEdge(dut.clk)\n        await ReadWrite()\n        dut.valid.value = 0\n        if dut.ready.value == 1:\n            dut.valid.value = 1\n\n\n:class:`!ReadOnly`\n------------------\n\n:class:`.ReadOnly` allows users to jump to the :ref:`end of the time step <end-of-time-step>`;\nallowing them to read the final values of signals or variables before more simulated time is consumed.\nThis may be necessary if they wish to sample a signal or variable whose value glitches (changes value in multiple evaluation cycles).\n\n.. note::\n    ``await ReadWrite()`` or ``await ReadOnly()`` after an ``await ReadOnly()`` **is not** well defined and will result in a :exc:`RuntimeError` being raised.\n\n\nState Transitions\n=================\n\n.. parsed-literal::\n\n    N := time step\n    M := evaluation cycle\n\n    BEGIN{N} ->\n        BEGIN{>N} : Timer\n        BEGIN{N+1} : NextTimeStep\n        CHANGE{N,>=0} : ValueChange/RisingEdge/FallingEdge\n        CHANGE{>N,>=0} : ValueChange/RisingEdge/FallingEdge\n        SETTLE{N,0} : ReadWrite\n        END{N} : ReadOnly\n\n    CHANGE{N,M} ->\n        BEGIN{>N} : Timer\n        BEGIN{N+1} : NextTimeStep\n        CHANGE{N,>M} : ValueChange/RisingEdge/FallingEdge\n        CHANGE{>N,>=0} : ValueChange/RisingEdge/FallingEdge\n        SETTLE{N,M} : ReadWrite\n        END{N} : ReadOnly\n\n    SETTLE{N,M} ->\n        BEGIN{>N} : Timer\n        BEGIN{N+1} : NextTimeStep\n        CHANGE{N,>M} : ValueChange/RisingEdge/FallingEdge\n        CHANGE{>N,>=0} : ValueChange/RisingEdge/FallingEdge\n        SETTLE{N,M+1} : ReadWrite\n        END{N} : ReadOnly\n\n    END{N} ->\n        BEGIN{>N} : Timer\n        BEGIN{N+1} : NextTimeStep\n\n\nDifferences in Verilator\n========================\n\nVerilator is a cycle-based simulator, meaning it does not have discrete events like \"value changed.\"\nInstead it has \"cycles\", meaning it evaluates all HDL code in a time step iteratively until quiescence, without stopping.\nThis frees the simulator to evaluate the HDL however it sees fit, as long as it can maintain correctness, allowing for optimizations.\n\nIn Verilator, the timing triggers (:class:`.Timer`, :class:`.NextTimeStep`, :class:`.ReadWrite`, and :class:`.ReadOnly`) work as intended, as these map to \"cycles\" well.\nHowever, the value change triggers (:class:`.ValueChange`, :class:`.RisingEdge`, and :class:`.FallingEdge`) can not be handled in the middle of a cycle,\nso they are handled after the cycle has ended (equivalent to the :ref:`values-settle` phase).\nThe easiest way to think of the behavior is as if the value change triggers all have an implicit :class:`await ReadWrite() <cocotb.triggers.ReadWrite>` after them.\n"
  },
  {
    "path": "docs/source/troubleshooting.rst",
    "content": "***************\nTroubleshooting\n***************\n\nSimulation Hangs\n================\n\nDid you call an :keyword:`async def` function or create a trigger without :keyword:`await`\\ ing it?\n\nIf you want to exit cocotb and the simulator using :kbd:`Control-C` (the Unix signal ``SIGINT``) but this doesn't work,\nyou can try :kbd:`Control-\\\\` (the Unix signal ``SIGQUIT``).\n\n\nIncreasing Verbosity\n====================\n\nIf things fail in the :term:`VPI`/:term:`VHPI`/:term:`FLI` area, check your simulator's documentation to see if it has options to\nincrease its verbosity about what may be wrong. You can then set these options on the :command:`make` command line\nas :make:var:`COMPILE_ARGS`, :make:var:`SIM_ARGS` or :make:var:`EXTRA_ARGS` (see :doc:`building` for details).\nIf things fail from within Python, or coroutines aren't being called when you expect, the\n:envvar:`COCOTB_SCHEDULER_DEBUG` variable can be used to (greatly) increase the verbosity of the scheduler.\n\n\nBuilding cocotb In Development Mode\n===================================\n\nBy default cocotb binaries installed from PyPi are stripped, i.e. they do not contain debug symbols.\nRebuilding cocotb from source can add this information back, making it significantly easier to debug cocotb code.\nIn the following, we'll assume the use of a Linux machine for debugging cocotb, which simplifies the process significantly.\n\nFirst, install all build requirements as listed at :ref:`install-devel`.\n\nThen execute the following commands to download a development version of cocotb and prepare a shell environment with this a development build of cocotb available:\n\n.. code-block:: shell-session\n\n  $ # Obtain the latest development version of cocotb through git\n  $ git clone https://github.com/cocotb/cocotb.git\n  $ # Build cocotb in debug mode, and enter a bash shell\n  $ cd cocotb\n  $ uv sync --dev\n\n\n.. _troubleshooting-attaching-debugger:\n\nAttaching a Debugger\n====================\n\n.. _troubleshooting-attaching-debugger-c:\n\nC and C++\n---------\n\nThe most convenient way to debug the cocotb C code and the interaction between cocotb and the simulator is using GDB.\nThis is a two-step process:\n\n1. Run the simulation with :envvar:`COCOTB_ATTACH` set.\n2. Use ``gdb -p`` to attach to the simulator process.\n\nHave a look at :ref:`building` for various useful variables related to debugging.\n\nExample:\nDebug the test ``test_array_simple`` with Questa, using the VHDL toplevel and the VHPI.\n\n1. Run the simulation and take note of the process identifier (PID) displayed after the simulator starts up.\n\n  .. code-block:: shell-session\n\n    $ make -C tests/test_cases/test_array_simple SIM=questa TOPLEVEL_LANG=vhdl VHDL_GPI_INTERFACE=vhpi COCOTB_ATTACH=300 COCOTB_LOG_LEVEL=trace\n    ...\n    #      -.--ns ERROR    gpi                                ..mbed/gpi_embed.cpp:154  in _embed_init_python              Waiting for 300 seconds - attach to PID 9583 with your debugger\n\n\n2. Open a new terminal window or tab, and attach GDB to the running process.\n\n  .. code-block::\n\n    $ gdb -p 9583\n    ...\n    48        r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep_time64, clock_id, flags, req,\n    (gdb) # Set breakpoints or do anything else you'd like to do. Finally, let the simulation run:\n    (gdb) continue\n    Continuing.\n    [Inferior 1 (process 9583) exited normally]\n    (gdb) quit\n\n.. _troubleshooting-attaching-debugger-python:\n\nPython\n------\n\nWhen executing the Makefile to run a cocotb test, a Python shell interpreter is called from within the\n:term:`VPI`/:term:`VHPI`/:term:`FLI` library.\nHence it is not possible to directly attach a Python debugger to the Python process being part of the simulator that uses the aforementioned library.\nUsing ``import pdb; pdb.set_trace()`` directly is also frequently not possible,\ndue to the way that simulators interfere with ``stdin``.\n\nTo successfully debug your Python code use the `remote_pdb`_ Python package to create a :command:`pdb` instance\naccessible via a TCP socket:\n\n.. _remote_pdb: https://pypi.org/project/remote-pdb/\n\n1. In your code insert the line:\n\n   .. code:: python\n\n      from remote_pdb import RemotePdb; rpdb = RemotePdb(\"127.0.0.1\", 4000)\n\n2. Then before the line of code you want the debugger to stop the execution, add a breakpoint:\n\n   .. code:: python\n\n      rpdb.set_trace()  # <-- debugger stops execution after this line\n\n3. Run the Makefile so that the interpreter hits the breakpoint line and *hangs*.\n4. Connect to the freshly created socket, for instance through :command:`telnet`:\n\n   .. code:: shell\n\n      telnet 127.0.0.1 4000\n\n\nEmbedding an IPython shell\n==========================\n\n.. module:: cocotb_tools.ipython_support\n    :synopsis: Support for embedding an IPython shell.\n\n.. versionadded:: 1.4\n\nA prebuilt test is included to easily launch an IPython shell in an existing design.\n\n.. autofunction:: run_ipython\n\nTo embed a shell within an existing test, where it can inspect local variables, the :func:`embed` function can be used.\n\n.. autofunction:: embed\n\n\n.. _troubleshooting-make-vars:\n\nSetting make variables on the command line\n==========================================\n\nWhen trying to set one of the make variables listed in :ref:`building` from the command line,\nit is strongly recommended to use an environment variable, i.e.\n``EXTRA_ARGS=\"...\" make`` (for the ``fish`` and ``csh`` shells: ``env EXTRA_ARGS=\"...\" make``)\nand *not* ``make EXTRA_ARGS=...``.\n\nThis is because in the case of the discouraged ``make EXTRA_ARGS=...``,\nif one of the involved Makefiles contains lines to assign (``=``) or append (``+=``) to :make:var:`EXTRA_ARGS` internally,\nsuch lines will be ignored.\nThese lines are needed for the operation of cocotb however,\nand having them ignored is likely to lead to strange errors.\n\nAs a side note,\nwhen you need to *clear* a Makefile variable from the command line,\nuse the syntax ``make EXTRA_ARGS=``.\n\n``GLIBCXX_3.4.XX`` not found\n============================\n\nThis error can occur on Linux, and will raise ``ImportError: /some/libstdc++.so.6: version `GLIBCXX_3.4.XX' not found``.\nThis occurs because an older non-C++11 version of ``libstdc++`` is being loaded by the simulator or cocotb.\nIt is usually an issue with your environment, but sometimes can occur when using a very old version of certain simulators.\n\nCheck your environment\n----------------------\n\nTo see if your environment is the issue, look at the value of the :envvar:`LD_LIBRARY_PATH` environment variable.\nEnsure the first path in the colon-delimited list is the path to the ``libstdc++`` that shipped with the compiler you used to build cocotb.\n\n.. code:: shell\n\n    echo $LD_LIBRARY_PATH\n\nThis variable might be empty, in which case the loader looks in the system's libraries.\nIf the library you built cocotb with is not first, prepend that path to the list.\n\n.. code:: shell\n\n    export LD_LIBRARY_PATH=/path/to/newer/libraries/:$LD_LIBRARY_PATH\n\nCheck your simulator\n--------------------\n\nSometimes, simulators modify the :envvar:`LD_LIBRARY_PATH` so they point to the libraries that are shipped with instead of the system libraries.\nIf you are running an old simulator, the packaged libraries may include a pre-C++11 ``libstdc++``.\nTo see if your simulator is modifying the :envvar:`LD_LIBRARY_PATH`, open the simulator up to an internal console and obtain the environment variable.\n\nFor example, with Mentor Questa and Cadence Xcelium, one could open a Tcl console and run the :command:`env` command to list the current environment.\nThe :envvar:`LD_LIBRARY_PATH` should appear in the list.\n\nIf the simulator does modify the :envvar:`LD_LIBRARY_PATH`, refer to the simulator documentation on how to prevent or work around this issue.\n\nFor example, Questa ships with GCC.\nSometimes that version of GCC is old enough to not support C++11 (<4.8).\nWhen you install cocotb, :command:`pip` uses the system (or some other) compiler that supports C++11.\nBut when you try to run cocotb with the older Questa, it prepends the older libraries Questa ships with to :envvar:`LD_LIBRARY_PATH`.\nThis causes the older ``libstdc++`` Questa ships with to be loaded, resulting in the error message.\nFor Questa, you can use the ``-noautoldlibpath`` option to turn off the :envvar:`LD_LIBRARY_PATH` prepend to resolve this issue.\n\n\nUsing cocotb with more than one Python installation\n===================================================\n\nUsers of cocotb with more than one installation of a single Python version (including ``conda env`` users)\nmust take care not to reuse cached versions of the installed cocotb package.\nIf this isn't done, running simulations fails with errors like ``libpython3.7m.so.1.0: cannot open shared object file: No such file or directory``.\n\ncocotb builds binary libraries during its installation process.\nThese libraries are tailored to the installation of Python used when installing cocotb.\nWhen switching between Python installations, cocotb needs to be re-installed without using cached build artifacts, e.g. with ``pip install --no-cache-dir cocotb``.\n\nOn Linux distributions, setting ``LD_DEBUG=libs`` (example: ``LD_DEBUG=libs make SIM=verilator``) prints detailed output about which libraries are loaded from where.\nOn Mac OS, you can use ``DYLD_PRINT_LIBRARIES=1`` instead of ``LD_DEBUG=libs`` to get similar information.\nOn Windows, use `Process Explorer <https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer>`_.\n\nFurther details are available in :issue:`1943`.\n"
  },
  {
    "path": "docs/source/update_indexing.rst",
    "content": ".. _update-indexing:\n\n******************************\nUpdate Indexing for cocotb 2.0\n******************************\n\ncocotb 2.0 changes what types are returned when getting a value from a\n:ref:`Logic-like <logic-handle-value-changes>` or :ref:`Array-like <array-handle-value-changes>` simulator object.\nThis can require a change to the testbench code in how those values are indexed.\nBecause this change breaks backwards compatibility silently,\nthis document and the following set of features were added to assist users in updating the indexing in their existing tests built against cocotb 1.x.\n\n.. autoclass:: cocotb.types.IndexingChangedWarning\n\n.. envvar:: COCOTB_INDEXING_CHANGED_WARNING\n\n    Set this environment variable to ``1`` to cause a warning to be emitted on all :class:`.LogicArray` and :class:`.Array` indexing and slicing operations\n    if the indexing would have changed between cocotb 1.x and 2.x.\n\nHow to Find Indexing Changes\n============================\n\nSet the :envvar:`!COCOTB_INDEXING_CHANGED_WARNING` environment variable to ``1`` and run your test.\nYou should see warnings emitted on every line of your testbench that indices or slices a :class:`.LogicArray` or :class:`.Array` where the indexing has changed.\nThe warning will tell you what index you used and what the new index should be.\n\n.. code-block:: console\n\n    $ export COCOTB_INDEXING_CHANGED_WARNING=1\n    $ make\n    ...\n    /home/user/project/tests/unit_tests.py:160: IndexingChangedWarning: Index 0 is now 7\n      left_bit = dut.signal.value[0]\n    ...\n    /home/user/project/tests/unit_tests.py:543: IndexingChangedWarning: Index 0 is now 3\n      if handle.value[i]:\n    /home/user/project/tests/unit_tests.py:543: IndexingChangedWarning: Index 1 is now 2\n      if handle.value[i]:\n    /home/user/project/tests/unit_tests.py:543: IndexingChangedWarning: Index 2 is now 1\n      if handle.value[i]:\n    /home/user/project/tests/unit_tests.py:543: IndexingChangedWarning: Index 3 is now 0\n      if handle.value[i]:\n    ...\n    /home/user/project/tests/unit_tests.py:232: IndexingChangedWarning: Slice 0:3 is now 7:4\n      field = dut.signal.value[:3]\n\n\nHow to Update Indexing\n======================\n\nFor static indices or slices, simply change the index or slice to the new value.\n\n.. code-block:: verilog\n    :caption: Signal definition\n\n    logic [3:0] signal;\n    logic [3:0] array [1:4];\n\n.. code-block:: python\n    :caption: Old 0-based indexing\n    :class: removed\n\n    dut.signal.value = \"1010\"\n    ...\n    assert dut.signal.value[0] == 1  # index 0 is always left-most\n\n    dut.array.value = [100, 101, 102, 103]\n    ...\n    assert dut.array.value[0] == 100  # index 0 is always left-most\n\n.. code-block:: python\n    :caption: New HDL-based indexing (packed object / logic array)\n    :class: new\n\n    dut.signal.value = \"1010\"\n    ...\n    assert dut.signal.value[3] == 1  # index 3 is now the left-most\n\n    dut.array.value = [100, 101, 102, 103]\n    ...\n    assert dut.array.value[1] == 100  # index 1 is now the left-most\n\n.. note::\n\n    If you previously used the static indices ``0`` or ``-1`` to refer to the first or last element in an array,\n    ``array[array.left]`` or ``array[array.right]``, respectively, may be a better spelling.\n\nWhen dealing with loops involving indices, there are several options, depending on your needs.\nIf you are looping over the indices to then index each element, you can instead iterate over the array directly.\nThis can be combined with :func:`enumerate` to get the ``0``-based index of each element, if needed.\n\n.. code-block:: python\n    :caption: Looping over indices\n    :class: removed\n\n    for i in range(len(dut.signal.value)):\n        bit = dut.signal.value[i]\n        ...\n\n.. code-block:: python\n    :caption: Looping over elements directly\n    :class: new\n\n    for i, bit in enumerate(dut.signal.value):\n        ...\n\nIf you need to use the index value, you can loop over the ``array.range`` object to get the indices in left-to-right order.\n\n.. code-block:: verilog\n    :caption: HDL signal being used\n\n    // Two arrays using the same indices\n    logic [3:0] array [1:4];\n    logic [4:0] doubled_array [1:4];\n\n.. code-block:: python\n    :caption: Looping over indices\n    :class: removed\n\n    for i in range(len(dut.array.value)):  # 0, 1, 2, 3\n        dut.doubled_array[i].value = 2 * dut.array.value[i]\n\n.. code-block:: python\n    :caption: Looping over ``range``\n    :class: new\n\n    array_value = dut.array.value\n    for i in array_value.range:  # 1, 2, 3, 4\n        dut.doubled_array[i].value = 2 * array_value[i]\n\n\nYou can also use the ``array.range`` object to translate ``0`` to ``len()-1`` indexing to the one used by :class:`!LogicArray` and :class:`!Array`.\nUse this as a last resort, as it is less readable and has runtime overhead compared to the other options.\n\n.. code-block:: python\n    :class: new\n\n    val = LogicArray(\"1010\", Range(3, 0))\n    assert val[0] == 0      # index 0 is right-most\n    ind = val.range[0]      # 0th range value is 3\n    assert val[ind] == \"1\"  # index 3 is left-most\n\n\nGradual Update\n==============\n\nThe recommended approach is to update one module at a time.\nThis is done by using the :envvar:`PYTHONWARNINGS` environment variable to limit which modules can emit an :class:`!IndexingChangedWarning`.\nThe :envvar:`!PYTHONWARNINGS` value below will ignore all :class:`!IndexingChangedWarning` except those from the ``unit_tests`` module.\n\n.. code-block:: console\n\n    $ export PYTHONWARNINGS=ignore::cocotb.types.IndexingChangedWarning,default::cocotb.types.IndexingChangedWarning:unit_tests\n    $ export COCOTB_INDEXING_CHANGED_WARNING=1\n    $ make\n\nAfter eliminating all warnings from one module, update the :envvar:`!PYTHONWARNINGS` environment variable to the next module and repeat until all modules are updated.\nThen rerun all tests with :envvar:`!PYTHONWARNINGS` unset to ensure all warnings are gone.\n"
  },
  {
    "path": "docs/source/upgrade-2.0.rst",
    "content": "=======================\nUpgrading to cocotb 2.0\n=======================\n\ncocotb 2.0 makes testbenches easier to understand and write.\nSome of these improvements require updates to existing testbenches.\nThis guide helps you port existing testbenches to cocotb 2.0.\n\n**************************\nStep-by-step to cocotb 2.0\n**************************\n\nThe migration to cocotb 2.0 is a two-step process.\nThe first step is a gradual migration that can be performed in small increments as time permits and keeps the testbench fully operational.\nThe second step is a flag-day migration to switch outdated APIs to their new counterparts.\n\nStep 1: Upgrade to cocotb 1.9 and resolve all deprecation warnings\n==================================================================\n\nMany of the new features in cocotb 2.0 were already introduced in cocotb 1.x, while keeping existing functionality in place.\nDeprecation warnings highlight where functionality is used that will be gone in cocotb 2.0.\nResolving all deprecations is therefore the first step in upgrading.\n\n1. Upgrade to the latest version of cocotb 1.9.\n2. Resolve all deprecation warnings.\n\nWith every warning resolved, your code will be better prepared for cocotb 2.0.\n\nStep 2: Move to cocotb 2.0\n==========================\n\nAfter step 1 your testbenches are ready for the final migration to cocotb 2.0.\n\n1. Start from a known-good state.\n   Ensure all tests are passing, the logic is stable, and all code is committed.\n2. Upgrade to cocotb 2.0.\n3. Run the testbench to see where it fails.\n   Replace outdated constructs as needed.\n   Rinse and repeat.\n4. Your testbenches are now running on cocotb 2.0!\n\nContinue reading on this page for common migration steps.\nAlso have a look at the :doc:`release_notes` for cocotb 2.0 and the linked GitHub pull requests or issues, which often also include changes to the cocotb tests that show the before and after of a change.\n\nYou might see some new deprecation warnings in your code after the upgrade.\nAs in step one, address those at your convenience (the sooner the better, of course).\n\nIf you get lost or have questions, :doc:`reach out through one of our support channels <support>`, we're happy to help!\n\n\n**************************************************************\nUse :func:`!cocotb.start_soon` instead of :func:`!cocotb.fork`\n**************************************************************\n\nChange\n======\n\n:external+cocotb19:py:func:`cocotb.fork` was removed and replaced with :func:`cocotb.start_soon`.\n\nHow to Upgrade\n==============\n\n* Replace all instances of :func:`!cocotb.fork` with :func:`!cocotb.start_soon`.\n* Run tests to check for any changes in behavior.\n\n.. code-block:: python\n    :caption: Old way with :func:`!cocotb.fork`\n    :class: removed\n\n    task = cocotb.fork(drive_clk())\n\n.. code-block:: python\n    :caption: New way with :func:`!cocotb.start_soon`\n    :class: new\n\n    task = cocotb.start_soon(drive_clk())\n\nRationale\n=========\n\n:func:`!cocotb.fork` would turn :term:`coroutine`\\s into :class:`~cocotb.task.Task`\\s that would run concurrently to the current :term:`task`.\nHowever, it would immediately run the coroutine until the first :keyword:`await` was seen.\nThis made the scheduler re-entrant and caused a series of hard to diagnose bugs\nand required extra state/sanity checking leading to runtime overhead.\nFor these reasons :func:`!cocotb.fork` was deprecated in cocotb 1.7 and replaced with :func:`!cocotb.start_soon`.\n:func:`!cocotb.start_soon` does not start the coroutine immediately, but rather \"soon\",\npreventing scheduler re-entrancy and sidestepping an entire class of bugs and runtime overhead.\n\n`The cocotb blog post on this change <https://fossi-foundation.org/blog/2021-10-20-cocotb-1-6-0>`_\nis very illustrative of how :func:`!cocotb.start_soon` and :func:`!cocotb.fork` are different.\n\nAdditional Details\n==================\n\nCoroutines run immediately\n--------------------------\n\nThere is a slight change in behavior due to :func:`!cocotb.start_soon` not running the given coroutine immediately.\nThis will not matter in most cases, but cases where it does matter are difficult to spot.\n\nIf you have a coroutine (the parent) which :func:`!cocotb.fork`\\ s another coroutine (the child)\nand expects the child coroutine to run to a point before allowing the parent to continue running,\nyou will have to add additional code to ensure that happens.\n\nIn general, the easiest way to fix this is to add an :class:`await NullTrigger() <cocotb.triggers.NullTrigger>` after the call to :func:`!cocotb.start_soon`.\n\n.. code-block:: python\n    :caption: Set up example...\n\n    async def hello_world():\n        cocotb.log.info(\"Hello, world!\")\n\n.. code-block:: python\n    :caption: Behavior of the old :func:`!cocotb.fork`\n    :class: removed\n\n    cocotb.fork(hello_world())\n    # \"Hello, world!\"\n\n.. code-block:: python\n    :caption: Behavior of the new :func:`!cocotb.start_soon`\n    :class: new\n\n    cocotb.start_soon(hello_world())\n    # No print...\n    await NullTrigger()\n    # \"Hello, world!\"\n\nOne caveat of this approach is that :class:`!NullTrigger` also allows every other scheduled coroutine to run as well.\nBut this should generally not be an issue.\n\nIf you require the \"runs immediately\" behavior of :func:`!cocotb.fork`,\nbut are not calling it from a :term:`coroutine function`,\nupdate the function to be a coroutine function and add an ``await NullTrigger``, if possible.\nOtherwise, more serious refactorings will be necessary.\n\n\nExceptions before the first :keyword:`!await`\n---------------------------------------------\n\nAlso worth noting is that with :func:`!cocotb.fork`, if there was an exception before the first :keyword:`!await`,\nthat exception would be thrown back to the caller of :func:`!cocotb.fork` and the ``Task`` object would not be successfully constructed.\n\n.. code-block:: python\n    :caption: Set up example...\n\n    async def has_exception():\n        if variable_does_not_exist:  # throws NameError\n            await Timer(1, 'ns')\n\n.. code-block:: python\n    :caption: Behavior of the old :func:`!cocotb.fork`\n    :class: removed\n\n    try:\n        task = cocotb.fork(has_exception())  # NameError comes out here\n    except NameError:\n        cocotb.log.info(\"Got expected NameError!\")\n    # no task object exists\n\n.. code-block:: python\n    :caption: Behavior of the new :func:`!cocotb.start_soon`\n    :class: new\n\n    task = cocotb.start_soon(has_exception())\n    # no exception here\n    try:\n        await task  # NameError comes out here\n    except NameError:\n        cocotb.log.info(\"Got expected NameError!\")\n\n\n****************************************\nMove away from :deco:`!cocotb.coroutine`\n****************************************\n\nChange\n======\n\nSupport for generator-based coroutines using the :external+cocotb19:py:class:`@cocotb.coroutine <cocotb.coroutine>` decorator\nwith Python :term:`generator functions <generator>` was removed.\n\nHow to Upgrade\n==============\n\n* Remove the :deco:`!cocotb.coroutine` decorator.\n* Add :keyword:`async` keyword directly before the :keyword:`def` keyword in the function definition.\n* Replace any ``yield [triggers, ...]`` with :class:`await First(triggers, ...) <cocotb.triggers.First>`.\n* Replace all ``yield``\\ s in the function with :keyword:`await`\\ s.\n* Remove all imports of the :deco:`!cocotb.coroutine` decorator\n\n.. code-block:: python\n    :caption: Old way with :deco:`!cocotb.coroutine`\n    :class: removed\n\n    @cocotb.coroutine\n    def my_driver():\n        yield [RisingEdge(dut.clk), FallingEdge(dut.areset_n)]\n        yield Timer(random.randint(10), 'ns')\n\n.. code-block:: python\n    :caption: New way with :keyword:`!async`\\ /:keyword:`!await`\n    :class: new\n\n    async def my_driver():  # async instead of @cocotb.coroutine\n        await First(RisingEdge(dut.clk), FallingEdge(dut.areset_n))  # await First() instead of yield [...]\n        await Timer(random.randint(10), 'ns')  # await instead of yield\n\nRationale\n=========\n\nThese existed to support defining coroutines in Python 2 and early versions of Python 3 before :term:`coroutine functions <coroutine function>`\nusing the :keyword:`!async`\\ /:keyword:`!await` syntax was added in Python 3.5.\nWe no longer support versions of Python that don't support :keyword:`!async`\\ /:keyword:`!await`.\nPython coroutines are noticeably faster than :deco:`!cocotb.coroutine`'s implementation,\nand the behavior of :deco:`!cocotb.coroutine` would have had to be changed to support changes to the scheduler.\nFor all those reasons the :deco:`!cocotb.coroutine` decorator and generator-based coroutine support was removed.\n\n\n.. _logic-array-over-binary-value:\n\n*********************************************************\nUse :class:`!LogicArray` instead of :class:`!BinaryValue`\n*********************************************************\n\nChange\n======\n\n:external+cocotb19:py:class:`~cocotb.binary.BinaryValue` and :external+cocotb19:py:class:`~cocotb.binary.BinaryRepresentation` were removed\nand replaced with the existing :class:`.Logic` and :class:`.LogicArray`.\n\n\nHow to Upgrade\n==============\n\nChange all constructions of :class:`!BinaryValue` to :class:`!LogicArray`.\n\nReplace construction from :class:`int` with :meth:`.LogicArray.from_unsigned` or :meth:`.LogicArray.from_signed`.\n\nReplace construction from :class:`bytes` with :meth:`.LogicArray.from_bytes` and pass the appropriate ``byteorder`` argument.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    BinaryValue(10, 10)\n    BinaryValue(\"1010\", n_bits=4)\n    BinaryValue(-10, 8, binaryRepresentation=BinaryRepresentation.SIGNED)\n    BinaryValue(b\"1234\", bigEndian=True)\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`\n    :class: new\n\n    LogicArray.from_unsigned(10, 10)\n    LogicArray(\"1010\")\n    LogicArray.from_signed(-10, 8)\n    LogicArray.from_bytes(b\"1234\", byteorder=\"big\")\n\n----\n\nReplace usage of :external+cocotb19:py:attr:`BinaryValue.integer <cocotb.binary.BinaryValue.integer>` and\n:external+cocotb19:py:attr:`BinaryValue.signed_integer <cocotb.binary.BinaryValue.signed_integer>`\nwith :meth:`.LogicArray.to_unsigned` or :meth:`.LogicArray.to_signed`, respectively.\n\nReplace usage of :external+cocotb19:py:attr:`BinaryValue.binstr <cocotb.binary.BinaryValue.binstr>`\nwith the :class:`str` cast (this works with :class:`!BinaryValue` as well).\n\nReplace conversion to :class:`!bytes` with :meth:`.LogicArray.to_bytes` and pass the appropriate ``byteorder`` argument.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    val = BinaryValue(10, 4)\n    assert val.integer == 10\n    assert val.signed_integer == -6\n    assert val.binstr == \"1010\"\n    assert val.buff == b\"\\x0a\"\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`\n    :class: new\n\n    val = LogicArray(10, 4)\n    assert val.to_unsigned() == 10\n    assert val.to_signed() == -6\n    assert str(val) == \"1010\"\n    assert val.to_bytes(byteorder=\"big\") == b\"\\x0a\"\n\n----\n\nRemove setting of the :attr:`!BinaryValue.big_endian` attribute to change endianness.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    val = BinaryValue(b\"12\", bigEndian=True)\n    assert val.buff == b\"12\"\n    val.big_endian = False\n    assert val.buff == b\"21\"\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`\n    :class: new\n\n    val = LogicArray.from_bytes(b\"12\", byteorder=\"big\")\n    assert val.to_bytes(byteorder=\"big\") == b\"12\"\n    assert val.to_bytes(byteorder=\"little\") == b\"21\"\n\n----\n\nConvert all objects to an unsigned :class:`!int` before doing any arithmetic operation,\nsuch as ``+``, ``-``, ``/``, ``//``, ``%``, ``**``, ``- (unary)``, ``+ (unary)``, ``abs(value)``, ``>>``, or ``<<``.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    val = BinaryValue(12, 8)\n    assert 8 * val == 96\n    assert val << 2 == 48\n    assert val / 6 == 2.0\n    assert -val == -12\n    # inplace modification\n    val *= 3\n    assert val == 36\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`\n    :class: new\n\n    val = LogicArray(12, 8)\n    val_int = b.to_unsigned()\n    assert 8 * val_int == 96\n    assert val_int << 2 == 48\n    assert val_int / 6 == 2.0\n    assert -val_int == -12\n    # inplace modification\n    val[:] = val_int * 3\n    assert val == 36\n\n----\n\nChange bit indexing and slicing to use the indexing provided by the ``range`` argument to the constructor.\n\n.. note::\n    Passing an :class:`!int` as the ``range`` argument will default the range to :class:`Range(range-1, \"downto\", 0) <cocotb.types.Range>`.\n    This means index ``0`` will be the rightmost bit and not the leftmost bit like in :class:`BinaryValue`.\n    Pass ``Range(0, range-1)`` when constructing :class:`!LogicArray` to retain the old indexing scheme, or update the indexing and slicing usage.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    val = BinaryValue(10, 4)\n    assert val[0] == 1\n    assert val[3] == 0\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`, specifying an ascending range\n    :class: new\n\n    val = LogicArray(10, Range(0, 3))\n    assert val[0] == 1\n    assert val[3] == 0\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`, changing indexing\n    :class: new\n\n    val = LogicArray(10, 4)\n    assert val[3] == 1\n    assert val[0] == 0\n\nSee :ref:`update-indexing` for more details on how to update indexing and slicing.\n\n----\n\nChange all uses of the :attr:`.LogicArray.binstr`, :attr:`.LogicArray.integer`, :attr:`.LogicArray.signed_integer`, and :attr:`.LogicArray.buff` setters,\nas well as calls to :external+cocotb19:py:meth:`BinaryValue.assign() <cocotb.binary.BinaryValue.assign>`, to use :class:`!LogicArray`'s setitem syntax.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    val = BinaryValue(10, 8)\n    val.binstr = \"00001111\"\n    val.integer = 0b11\n    val.signed_integer = -123\n    val.buff = b\"a\"\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`\n    :class: new\n\n    val = LogicArray(10, 8)\n    val[:] = \"00001111\"\n    val[:] = LogicArray.from_unsigned(3, 8)\n    # or\n    val[:] = 0b00000011\n    val[:] = LogicArray.from_signed(-123, 8)\n    val[:] = LogicArray.from_bytes(b\"a\", byteorder=\"big\")\n\n.. note::\n    Alternatively, don't modify the whole value in place, but instead modify the variable with a new value.\n\n----\n\nChange expected type of single indexes to :class:`.Logic` and slices to :class:`.LogicArray`.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    val = BinaryValue(10, 4)\n    assert isinstance(val[0], BinaryValue)\n    assert isinstance(val[0:3], BinaryValue)\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`\n    :class: new\n\n    val = LogicArray(10, 4)\n    assert isinstance(val[0], Logic)\n    assert isinstance(val[0:3], LogicArray)\n\n.. note::\n    :class:`Logic` supports usage in conditional expressions (e.g. ``if val: ...``),\n    equality with :class:`!str`, :class:`!bool`, or :class:`!int`,\n    and casting to :class:`!str`, :class:`!bool`, or :class:`!int`;\n    so many behaviors overlap with :class:`!LogicArray`\n    or how these values would be used previously with :class:`!BinaryValue`.\n\n.. note::\n    This also implies a change to type annotations.\n\nRationale\n=========\n\nIn many cases :class:`!BinaryValue` would behave in unexpected ways that were often reported as errors.\nThese unexpected behaviors were either an unfortunate product of its design or done purposefully.\nThey could not necessarily be \"fixed\" and any fix would invariably break the API.\nSo rather than attempt to fix it, it was outright replaced.\nUnfortunately, a gradual change is not possible with such core functionality,\nso it was replaced in one step.\n\n\nAdditional Details\n==================\n\nThere are some behaviors of :class:`!BinaryValue` that are *not* supported anymore.\nThey were deliberately not added to :class:`!LogicArray` because they were unnecessary, unintuitive, or had bugs.\n\n\nDynamic-sized :class:`!BinaryValue`\\ s\n--------------------------------------\n\nThe above examples all pass the ``n_bits`` argument to the :class:`!BinaryValue` constructor.\nHowever, it is possible to construct a :class:`!BinaryValue` without a set size.\nDoing so would allow the size of the :class:`!BinaryValue` to change whenever the value was set.\n\n:class:`!LogicArray`\\ s are fixed size.\nInstead of modifying the :class:`!LogicArray` in-place with a different sized value,\nmodify the variable holding the :class:`!LogicArray` to point to a different value.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    val = BinaryValue(0, binaryRepresentation=BinaryRepresentation.TWOS_COMPLEMENT)\n    assert len(val) == 0\n    val.binstr = \"1100\"\n    assert len(val) == 4\n    val.integer = 100\n    assert len(val) == 8  # minimum size in two's complement representation\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`\n    :class: new\n\n    val = LogicArray(0, 0)  # must provide size!\n    assert len(val) == 0\n    val = LogicArray(\"1100\")\n    assert len(val) == 4\n    val = LogicArray.from_signed(100, 8)  # must provide size!\n    assert len(val) == 8\n\n\nAssigning with partial values and \"bit-endianness\"\n--------------------------------------------------\n\nPreviously, when modifying a :class:`!BinaryValue` in-place using :external+cocotb19:py:meth:`BinaryValue.assign <cocotb.binary.BinaryValue.assign>`\nor the :external+cocotb19:py:attr:`BinaryValue.buff <cocotb.binary.BinaryValue.buff>`,\n:external+cocotb19:py:attr:`BinaryValue.binstr <cocotb.binary.BinaryValue.binstr>`,\n:external+cocotb19:py:attr:`BinaryValue.integer <cocotb.binary.BinaryValue.signed_integer>`,\nor :external+cocotb19:py:attr:`BinaryValue.signed_integer <cocotb.binary.BinaryValue.signed_integer>` setters,\nif the provided value was smaller than the :class:`!BinaryValue`,\nthe value would be zero-extended based on the endianness of :class:`!BinaryValue`.\n\n:class:`!LogicArray` has no concept of \"bit-endianness\" as the indexing scheme is arbitrary.\nWhen partially setting a :class:`!LogicArray`, you are expected to explicitly provide the slice you want to set,\nand it must match the size of the value it's being set with.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    b = BinaryValue(0, 4, bigEndian=True)\n    b.binstr = \"1\"\n    assert b == \"1000\"\n    b.integer = 2\n    assert b == \"1000\"  # Surprise!\n\n    c = BinaryValue(0, 4, bigEndian=False)\n    c.binstr = \"1\"\n    assert c == \"0001\"\n    c.integer = 2\n    assert c == \"0010\"\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`\n    :class: new\n\n    val = LogicArray(0, Range(0, 3))\n    val[0] = \"1\"\n    assert val == \"1000\"\n    val[0:1] = 0b01\n    assert val == \"0100\"\n\n.. note::\n    :class:`!LogicArray` supports setting its value with the deprecated :attr:`.LogicArray.buff`,\n    :attr:`.LogicArray.binstr`, :attr:`.LogicArray.integer` and :attr:`.LogicArray.signed_integer` setters,\n    but assumes the value matches the width of the whole :class:`!LogicArray`.\n    Values that are too big or too small will result in a :exc:`ValueError`.\n\n\nImplicit truncation\n-------------------\n\nConversely, when modifying a :class:`!BinaryValue` in-place,\nif the provided value is too large, it would be implicitly truncated and issue a :exc:`RuntimeWarning`.\nIn certain circumstances, the :exc:`!RuntimeWarning` wouldn't be issued.\n\n:class:`LogicArray`, as stated in the previous section,\nrequires the user to provide a value the same size as the slice to be set.\nFailure to do so will result in a :exc:`ValueError`.\n\n.. code-block:: python\n    :caption: Old way with :class:`!BinaryValue`\n    :class: removed\n\n    b = BinaryValue(0, 4, bigEndian=True)\n    b.binstr = \"00001111\"\n    # RuntimeWarning: 4-bit value requested, truncating value '00001111' (8 bits) to '1111'\n    assert b == \"1111\"\n    b.integer = 100\n    # RuntimeWarning: 4-bit value requested, truncating value '1100100' (7 bits) to '0100'\n    assert b == \"0100\"\n\n    c = BinaryValue(0, 4, bigEndian=False)\n    c.binstr = \"00001111\"\n    # No RuntimeWarning?\n    assert c == \"1111\"  # Surprise!\n    c.integer = 100\n    # RuntimeWarning: 4-bit value requested, truncating value '1100100' (7 bits) to '110'\n    assert c == \"110\"  # ???\n\n.. code-block:: python\n    :caption: New way with :class:`!LogicArray`\n    :class: new\n\n    val = LogicArray(0, 4)\n    # val[:] = \"00001111\"  # ValueError: Value of length 8 will not fit in Range(3, 'downto', 0)\n    # val[:] = 100         # ValueError: 100 will not fit in a LogicArray with bounds: Range(3, 'downto', 0)\n    val[3:0] = \"00001111\"[:4]\n    assert val == \"0000\"\n    val[3:0] = LogicArray.from_unsigned(100, 8)[3:0]\n    assert val == \"0100\"\n\n.. note::\n    :class:`!LogicArray` supports setting its value with the deprecated :attr:`.LogicArray.buff`,\n    :attr:`.LogicArray.binstr`, :attr:`.LogicArray.integer` and :attr:`.LogicArray.signed_integer` setters,\n    but assumes the value matches the width of the whole :class:`!LogicArray`.\n    Values that are too big or too small will result in a :exc:`ValueError`.\n\n\nInteger representation\n----------------------\n\n:class:`!BinaryValue` could be constructed with a ``binaryRepresentation`` argument of the type :external+cocotb19:py:class:`~cocotb.binary.BinaryRepresentation`\nwhich would select how that :class:`!BinaryValue` would interpret any integer being used to set its value.\n:external+cocotb19:py:meth:`BinaryValue.assign <cocotb.binary.BinaryValue.assign>`\nand the :external+cocotb19:py:attr:`BinaryValue.integer <cocotb.binary.BinaryValue.signed_integer>`\nand :external+cocotb19:py:attr:`BinaryValue.signed_integer <cocotb.binary.BinaryValue.signed_integer>` setters all behaved the same when given an integer.\nUnlike endianness, this could not be changed after construction (setting :attr:`!BinaryValue.binaryRepresentation` has no effect).\n\n:class:`!LogicArray` does not have a concept of integer representation as a part of its value,\nits value is just an array of :class:`!Logic`.\nInteger representation is provided when converting to and from an integer.\n\n.. note::\n    :class:`!LogicArray` interfaces that can take integers are expected to take them as \"bit array literals\", e.g. ``0b110101`` or ``0xFACE``.\n    That is, they are interpreted as if they are unsigned integer values.\n\n.. note::\n    :class:`!LogicArray` supports setting its value with the deprecated :attr:`.LogicArray.integer` and :attr:`.LogicArray.signed_integer` setters,\n    but assumes an unsigned and two's complement representation, respectively.\n\n\n.. _logic-handle-value-changes:\n\n**************************************************************************************************************************************\nExpect :class:`!LogicArray` and :class:`!Logic` instead of :class:`!BinaryValue` when getting values from logic-like simulator objects\n**************************************************************************************************************************************\n\nChange\n======\n\nHandles to logic-like simulator objects now return :class:`.LogicArray` or :class:`.Logic` instead of :external+cocotb19:py:class:`~cocotb.binary.BinaryValue`\nwhen getting their value with the :attr:`value <cocotb.handle.ValueObjectBase.value>` getter.\nScalar logic-like simulator objects return :class:`!Logic`, and array-of-logic-like simulator objects return :class:`!LogicArray`.\n\nHow to Upgrade\n==============\n\n:ref:`logic-array-over-binary-value` when dealing with array-of-logic-like simulator objects.\nChange code when dealing with scalar logic-like simulator objects to work with :class:`!Logic`.\n\nChange indexing assumptions from always being ``0`` to ``length-1`` left-to-right, to following the arbitrary indexing scheme of the logic array as defined in HDL.\nSee :ref:`update-indexing` for more details on how to update indexing and slicing.\n\nRationale\n=========\n\nSee the rationale for switching from :class:`!BinaryValue` to :class:`!LogicArray`.\nThe change to use the HDL indexing scheme makes usage more intuitive for new users and eases debugging.\nScalars and arrays of logic handles were split into two types with different value types so that handles to arrays could support\ngetting :func:`length <len>` and indexing information: :meth:`.LogicArrayObject.left`, :meth:`.LogicArrayObject.right`, :meth:`.LogicArrayObject.direction`, and :meth:`.LogicArrayObject.range`,\nwhich cause errors when applied to scalar objects.\n\nAdditional Details\n==================\n\nOperations such as equality with and conversion to :class:`int`, :class:`str`, and :class:`bool`,\nas well as getting the :func:`length <len>`,\nwork the same for :class:`!Logic`, :class:`!LogicArray`, and :class:`!BinaryValue`.\nThis was done deliberately to reduce the number of changes required,\nwhile also providing a common API to enable writing backwards-compatible and higher-order APIs.\n\n.. code-block:: python\n    :caption: Works with :class:`!BinaryValue` in cocotb 1.x and both :class:`!Logic` and :class:`!LogicArray` in cocotb 2.x.\n\n    assert len(dut.signal.value) == 1\n    assert dut.signal.value == 1\n    assert dut.signal.value == \"1\"\n    assert dut.signal.value == True\n    assert int(dut.signal.value) == 1\n    assert str(dut.signal.value) == \"1\"\n    assert bool(dut.signal.value) is True\n    dut.signal.value = 1\n    dut.signal.value = \"1\"\n    dut.signal.value = True\n\n\n.. _array-handle-value-changes:\n\n***************************************************************************************************\nExpect :class:`!Array` instead of :class:`!list` when getting values from arrayed simulator objects\n***************************************************************************************************\n\nChange\n======\n\nHandles to arrayed simulator objects now return :class:`.Array` instead of :class:`list` when getting values with the :attr:`value <cocotb.handle.ValueObjectBase.value>` getter.\n\nHow to Upgrade\n==============\n\nChange indexing assumptions from always being ``0`` to ``length-1`` left-to-right, to following the arbitrary indexing scheme of the array as defined in HDL.\nSee :ref:`update-indexing` for more details on how to update indexing and slicing.\n\nRationale\n=========\n\n:class:`!Array` provides most features of :class:`!list` besides the fact that it is immutable in size and uses arbitrary indexing, like :class:`.LogicArray`.\nThe change to use the HDL indexing scheme makes usage more intuitive for new users and eases debugging.\n\nAdditional Details\n==================\n\nEquality with and conversion to :class:`!list`,\ngetting the :func:`length <len>`,\nand iteration,\nworks the same for both the old way and the new way using :class:`!Array`.\nThis was done deliberately to reduce the number of changes required.\n\n.. code-block:: python\n    :caption: Works with both :class:`!list` in cocotb 1.x and :class:`!Array` in cocotb 2.x.\n\n    assert dut.array.value == [1, 2, 3, 4]\n    as_list = list(dut.array.value)\n    assert as_list[0] == 1\n    assert len(dut.array.value) == 4\n    for actual, expected in zip(dut.array.value, [1, 2, 3, 4]):\n        assert actual == expected\n\n\n****************************************************************\nUse :deco:`!cocotb.parametrize` instead of :class:`!TestFactory`\n****************************************************************\n\nChange\n======\n\n:deco:`cocotb.parametrize` was added to replace :class:`.TestFactory`, which was deprecated.\n\nHow to Upgrade\n==============\n\nReplace all instances of :class:`!TestFactory` with a :deco:`!cocotb.parametrize` decorator on the function being parameterized.\n\nReplace calls to :meth:`.TestFactory.add_option` with arguments to :deco:`!cocotb.parametrize`.\n\nRemove all calls to :meth:`.TestFactory.generate_tests` and move any arguments to the :deco:`cocotb.test` decorator.\n\n.. code-block:: python\n    :caption: Old way with :class:`!TestFactory`\n    :class: removed\n\n    async def my_test(param_a, param_b):\n        ...\n\n    tf = TestFactory(my_test)\n    tf.add_option(\"param_a\", [1, 2, 3])\n    tf.add_option(\"param_b\", [\"sample\", \"text\"])\n    tf.generate_tests(timeout_time=10, timeout_unit=\"us\")\n\n.. code-block:: python\n    :caption: New way with :deco:`!cocotb.parametrize`\n    :class: new\n\n    @cocotb.test(timeout_time=10, timeout_unit=\"us\")\n    @cocotb.parametrize(\n        param_a=[1, 2, 3],\n        param_b=[\"sample\", \"text\"]\n    )\n    async def my_test(param_a, param_b):\n        ...\n\n.. note::\n\n    If you are using the ``prefix`` or ``postfix`` arguments to :meth:`!TestFactory.generate_tests`,\n    replace them with the use of the new ``name`` argument.\n\nRationale\n=========\n\n:class:`!TestFactory` was defined separately from the test declaration, hurting readability,\nand making it prone to issues such as parameters being out of sync\nand :deco:`cocotb.test` inadvertently being applied to the parameterized function.\nAdditionally it worked by injecting test objects into the module of the calling scope,\nwhich led to feature creep (``stacklevel`` arg to :meth:`!TestFactory.generate_tests`)\nand made issues hard to diagnose.\nNext, the test names generated were *not* descriptive and did not lend themselves to being filtered with a regular expression.\nFinally, it doesn't compose well with future test marking features.\n\n:deco:`!cocotb.parametrize` has none of those issues and should be familiar to users of :mod:`pytest`.\nGenerated test names are descriptive and can be easily filtered with a regular expression.\n\n**********************************************************\nMove away from :data:`!Event.data` and :data:`!Event.name`\n**********************************************************\n\nChange\n======\n\nThe :data:`.Event.data` attribute and ``data`` argument to the :meth:`.Event.set` method,\nand the :data:`.Event.name` attribute and ``name`` argument to the :class:`.Event` constructor were deprecated.\n\nHow to Upgrade\n==============\n\nRemove all passing of the ``name`` argument to the :class:`!Event` constructor.\n\nRemove all passing of the ``data`` argument to the :meth:`!Event.set` method and uses of the :data:`!Event.data` attribute.\nReplace with an adjacent variable or class attribute.\n\n.. code-block:: python\n    :caption: Old way using :data:`!Event.data`\n    :class: removed\n\n    monitor_event = Event()\n\n    ...  # in monitor\n    monitor_event.set(b\"\\xBA\\xD0\\xCA\\xFE\")\n\n    ...  # in user code\n    await monitor_event.wait()\n    recv = monitor_event.data\n\n.. code-block:: python\n    :caption: New way using an adjacent variable\n    :class: new\n\n    monitor_event = Event()\n    monitor_data = None\n\n    ...  # in monitor\n    monitor_data = b\"\\xBA\\xD0\\xCA\\xFE\"\n    monitor_event.set()\n\n    ...  # in user code\n    await monitor_event.wait()\n    recv = monitor_data\n\nRationale\n=========\n\nThese features were removed to better align cocotb's :class:`!Event` with :class:`asyncio.Event`.\n\n\n****************************************************\nRemove uses of :class:`!Join` and :meth:`!Task.join`\n****************************************************\n\nChange\n======\n\n:class:`.Join` and :meth:`.Task.join` have been deprecated.\n\nHow to Upgrade\n==============\n\nRemove :class:`!Join` and :meth:`!Task.join` and simply :keyword:`await` the :class:`!Task` being joined,\nor pass the :class:`!Task` directly into the function that will :keyword:`await` it.\n\n.. code-block:: python\n    :caption: Example Task\n\n    async def example():\n        ...\n\n    task = cocotb.start_soon()\n\n.. code-block:: python\n    :caption: Old way using :class:`!Join`\n    :class: removed\n\n    await Join(task)\n    # or\n    await First(Join(task), RisingEdge(cocotb.top.clk))\n\n.. code-block:: python\n    :caption: Old way using :meth:`!Task.join`\n    :class: removed\n\n    await task.join()\n    # or\n    await First(task.join(), RisingEdge(cocotb.top.clk))\n\n.. code-block:: python\n    :caption: New way using :class:`!Task` directly\n    :class: new\n\n    await task\n    # or\n    await First(task, RisingEdge(cocotb.top.clk))\n\nRationale\n=========\n\nThere were multiple synonyms for the same functionality, so we deprecated all but the least verbose.\nThis also better aligns cocotb's :class:`!Task`\\ s with :class:`asyncio.Task`.\n\nAdditional Details\n==================\n\n:keyword:`await`\\ ing a :class:`!Task` (or previously a :class:`!Join` trigger) returns the result of the :class:`!Task`, not the task/trigger.\nThis can make it difficult to determine which :class:`!Task` finished when waiting on multiple, such as with a :class:`.First` trigger.\n:class:`.TaskComplete` was added to solve this.\nUse :attr:`.Task.complete` to get the :class:`!TaskComplete` trigger associated with each :class:`!Task`.\n\n.. code-block:: python\n    :caption: Using :class:`!TaskComplete` to disambiguate which :class:`!Task` finished.\n    :class: new\n\n    async def coro1():\n        await Timer(1, 'us')\n\n    async def coro2():\n        await RisingEdge(cocotb.top.done)\n\n    task1 = cocotb.start_soon(coro1())\n    task2 = cocotb.start_soon(coro2())\n\n    # res = await First(task1, task2)\n    # res is `None` is either case, which fired?\n\n    res = await First(task1.complete, task2.complete)\n\n    if res is task1.complete:\n        cocotb.log.info(\"Reached deadline!\")\n    else:\n        cocotb.log.info(\"Processing finished!\")\n\n\n****************************************************\nReplace :meth:`!Task.kill` with :meth:`!Task.cancel`\n****************************************************\n\nChange\n======\n\n:meth:`.Task.kill` was replaced with :meth:`.Task.cancel`.\n\nHow to Upgrade\n==============\n\nReplace calls of :meth:`!Task.kill` with :meth:`!Task.cancel`.\n\n.. code-block:: python\n    :caption: Old way using :meth:`!Task.kill`\n    :class: removed\n\n    task.kill()\n\n.. code-block:: python\n    :caption: New way using :meth:`!Task.cancel`\n    :class: new\n\n    task.cancel()\n\nRationale\n=========\n\n:meth:`!Task.kill` stopped a :class:`.Task` from executing immediately,\nwhich required re-entering the scheduler from a user context.\nScheduler re-entrance has been the cause of several hard to diagnose bugs.\n:meth:`!Task.cancel` *schedules* stopping a :class:`!Task`,\npreventing scheduler re-entrancy and sidestepping an entire class of bugs.\n\nAdditionally, :meth:`!Task.cancel` throws a :exc:`!CancelledError` into the task during cancellation,\nallowing cleanup code to be executed, which was not the case with :meth:`Task.kill`.\n\nAdditional Details\n==================\n\n:class:`!Task`\\ s don't become \"done\" immediately\n-------------------------------------------------\n\nThere is a slight change in behavior when moving to :meth:`!Task.cancel` since it *schedules* a cancellation.\n:class:`!Task`\\ s don't become \"done\" immediately, but only after control is returned to the scheduler.\n\n.. code-block:: python\n    :caption: Old way using :meth:`!Task.kill`\n    :class: removed\n\n    task.kill()\n    assert task.done()\n\n.. code-block:: python\n    :caption: New way using :meth:`!Task.cancel`\n    :class: new\n\n    task.cancel()\n    assert not task.done()\n    await NullTrigger()\n    assert task.done()\n\nThis can cause a change in scheduling when :keyword:`await`\\ ing a :class:`!Task` to finish if it is cancelled instead of killed.\n\n:exc:`!CancelledError` is thrown into cancelled :class:`Task`\\ s\n----------------------------------------------------------------\n\nWhen a :class:`!Task` is cancelled by calling :meth:`!Task.cancel`,\na :exc:`asyncio.CancelledError` is thrown into the task.\nThis ensures cleanup is performed.\n:term:`context manager`\\ s doing cleanup on exit and any :keyword:`finally` blocks in your tasks\nwill now be executed when the task is cancelled.\nOtherwise, the exception will bubble up through your code and be handled appropriately by :class:`!Task` internals,\nso there is nothing else you have to do.\n\nAll :class:`!Task`\\ s created with :func:`cocotb.start_soon`, :func:`cocotb.start`, or :func:`cocotb.create_task`\nthat are still running at the end of the test will be cancelled to ensure end-of-test cleanup.\n\n.. code-block:: python\n    :caption: Example of how :exc:`!CancelledError` ensures cleanup\n\n    async def stimulus():\n        try:\n            with open(\"transactions.log\", \"w\") as f:\n                transaction = 123\n                f.write(transaction)\n            # The context manager exited here, so the file was closed. This happens\n            # whether it exited normally, threw an exception, the task was cancelled,\n            # or the test ended.\n        finally:\n            # The finally block is always executed. This happens whether the try block\n            # exited normally, an exception was thrown, the task was cancelled, or the test ended.\n            cocotb.log.info(\"Ending stimulus!\")\n\n:exc:`!CancelledError` thrown during cancellation cannot be squashed\n--------------------------------------------------------------------\n\nUnlike :mod:`asyncio`, task cancellation *cannot* be ignored.\nWhen a test ends all tasks *must* be cancelled,\notherwise they would continue running into the next test.\nTo ensure that users don't inadvertently ignore cancellation,\ncocotb forces the task to end with :exc:`RuntimeError` if it detects a :exc:`!CancelledError` is squashed.\n\nWhen upgrading code to 2.0, there may be existing code which causes this condition to fire.\nThe most common offender is user code catching :exc:`BaseException`.\n\n.. code-block:: python\n    :caption: Code which will accidentally squash :exc:`!CancelledError`\n    :class: removed\n\n    async def example():\n        try:\n            ...\n        except BaseException as e:\n            cocotb.log.info(\"Saw error!\", exc_info=e)\n\n:exc:`!BaseException` is generally reserved for runtime implementation details.\nInstead catch only :exc:`Exception`.\n\n.. code-block:: python\n    :caption: Resolving issue by catching only :exc:`!Exception`\n    :class: new\n\n    async def example():\n        try:\n            ...\n        except Exception as e:\n            cocotb.log.info(\"Saw error!\", exc_info=e)\n\nIf narrowing your exception handling to :exc:`Exception` isn't possible,\nexplicitly catch :exc:`!CancelledError` and re-raise it in an except clause placed *before* the :exc:`!BaseException` clause.\n\n.. code-block:: python\n    :caption: Resolving issue by explicitly catching :exc:`!CancelledError`\n    :class: new\n\n    async def example():\n        try:\n            ...\n        except asyncio.CancelledError:\n            raise\n        except BaseException as e:\n            cocotb.log.info(\"Saw error!\", exc_info=e)\n\n\n*************************************************************\nReplace :func:`!cocotb.start` with :func:`!cocotb.start_soon`\n*************************************************************\n\nChange\n======\n\n:func:`cocotb.start` was deprecated.\n\nHow to Upgrade\n==============\n\nReplace :func:`!cocotb.start` with :func:`cocotb.start_soon` and remove the :keyword:`await` before it.\n\n.. code-block:: python\n    :caption: Old way using :func:`!cocotb.start`\n    :class: removed\n\n    async def my_coro():\n        ...  # do stuff\n\n    my_task = await cocotb.start(my_coro())\n\n.. code-block:: python\n    :caption: New way using :func:`!cocotb.start_soon`\n    :class: new\n\n    async def my_coro():\n        ...  # do stuff\n\n    my_task = cocotb.start_soon(my_coro())\n\n.. note::\n\n    If you need the started Task to run *immediately* rather than *soon*,\n    :keyword:`!await` a :class:`.NullTrigger` immediately after calling :func:`!cocotb.start_soon`.\n    This is not common.\n\n    .. code-block:: python\n        :caption: Using :class:`!NullTrigger` to force a new Task to run\n\n        async def my_coro():\n            ...  # do stuff\n\n        my_task = cocotb.start_soon(my_coro())\n        # my_task isn't running\n        await NullTrigger()\n        # my_task is now running\n\nRationale\n=========\n\nMany new users were confused on when to use one vs the other,\nso :func:`!cocotb.start` will be removed to prevent any confusion.\n\n\n**********************************************************\nOperate on full values of packed structs and packed arrays\n**********************************************************\n\nChange\n======\n\nAccessing fields of packed structs and elements of packed arrays was removed.\nPacked objects now act as a single composite logic vector.\n\nHow to Upgrade\n==============\n\nInstead of accessing fields of packed structs or elements of packed arrays,\nget the full value of the object and index into the resulting :class:`!LogicArray`.\n\n.. code-block:: verilog\n    :caption: Verilog definitions of packed objects\n\n    struct packed {\n        logic [3:0] a;\n        logic [7:0] b;\n    } my_struct;\n\n    logic my_array [0:3];\n\nWhen trying to get the value of a packed struct field or packed array element:\n1. Read the whole packed object value.\n2. Slice it to get the field you are interested in.\n\n.. code-block:: python\n    :caption: Old way accessing packed object fields\n    :class: removed\n\n    _ = dut.my_struct.a.value\n    _ = dut.my_array[2].value\n\n.. code-block:: python\n    :caption: New way accessing packed object fields\n    :class: new\n\n    def get_packed_field(handle, start, stop=None):\n        full_value = handle.value\n        if stop is None:\n            return full_value[start]\n        else:\n            return full_value[start:stop]\n\n    get_packed_field(dut.my_struct, 11, 8)\n    get_packed_field(dut.my_array, 2)\n\nWhen setting the value of a packed object:\n1. Read the whole packed value.\n2. Set the bits corresponding to the field you want to change.\n3. Write the whole modified packed value back.\n\n.. code-block:: python\n    :caption: Old way setting packed object fields\n    :class: removed\n\n    dut.my_struct.a.value = 0b1010\n    dut.my_array[2].value = 1\n\n.. code-block:: python\n    :caption: New way setting packed object fields\n\n    def set_packed_field(handle, start, stop=None, *, value):\n        full_value = handle.value\n        if stop is None:\n            full_value[start] = value\n        else:\n            full_value[start:stop] = value\n        handle.value = full_value\n\n    set_packed_field(dut.my_struct, 11, 8, value=0b1010)\n    set_packed_field(dut.my_array, 2, value=1)\n\nWhen waiting for a value change on a packed object:\n1. Get the current value of the field you care about.\n2. Wait for a value change on the whole packed object.\n3. Read the whole packed object and slice it to get the field you are interested in.\n4. Compare it against the saved value from step 1 to see if the field changed.\n\n.. code-block:: python\n    :caption: Old way waiting for packed object field to change\n    :class: removed\n\n    await ValueChange(dut.my_struct.a)\n    await ValueChange(dut.my_array[2])\n\n.. code-block:: python\n    :caption: New way waiting for packed object field to change\n    :class: new\n\n    async def value_change_packed_field(handle, start, stop=None):\n        value_changed = False\n        while not value_changed:\n            old_value = get_packed_field(handle, start, stop)\n            await ValueChange(handle)\n            new_value = get_packed_field(handle, start, stop)\n            value_changed = new_value != old_value\n\n    await value_change_packed_field(dut.my_struct, 11, 8)\n    await value_change_packed_field(dut.my_array, 2)\n\n.. note::\n    A library like `packtype <https://github.com/Intuity/packtype>`_ could help define Python types that mimic HDL packed structures and arrays,\n    allowing you to use struct field names and array indexes rather than bit offsets.\n\n.. note::\n    Alternatively, you might be able to remove the Verilog `packed` specifier.\n\nRationale\n=========\n\nAccessing packed struct fields or packed array elements was not well supported across all simulators.\nEven in simulators that appeared to support it, there were many edge cases that didn't work as expected.\nFinally, this functionality leveraged VPI calls which appeared to violate the VPI spec.\nTo prevent users from running into these issues, this feature was removed.\n\n\n*********************************************************************************\nReplace ``handle.setimmediatevalue(value)`` with ``handle.set(Immediate(value))``\n*********************************************************************************\n\nChange\n======\n\n:meth:`handle.setimmediatevalue() <cocotb.handle.ValueObjectBase.setimmediatevalue>` was deprecated.\n\nHow To Upgrade\n==============\n\nReplace the call to :meth:`!handle.setimmediatevalue` with a value set using the :meth:`~cocotb.handle.Immediate` action wrapper.\n\n.. code-block:: python\n    :caption: Old way with ``handle.setimmediatevalue(value)``\n    :class: removed\n\n    cocotb.top.iface.valid.setimmediatevalue(0)\n\n.. code-block:: python\n    :caption: New way with ``handle.set(Immediate(value))``\n    :class: new\n\n    cocotb.top.iface.valid.set(Immediate(0))\n\nRationale\n=========\n\n:meth:`!handle.setimmediatevalue` does not actually set the object's value immediately.\nIt sets the value inertially, but immediately,\nwithout it being scheduled for the next :ref:`ReadWrite sync phase <values-settle>`.\nThis means signals get their value at delta N+1 (N being where you currently are in the time step).\nThis is unexpected and generally not useful.\n\n:class:`!Immediate` applies values immediately, such that they can be read back after writing.\n\n.. code-block:: python\n    :caption: Read back value written immediately\n    :class: new\n\n    assert cocotb.top.data.value == 100\n    cocotb.top.data.set(Immediate(0))\n    # new value can be read back immediately\n    assert cocotb.top.data.value == 0\n\n\n*******************************************************************************************\nUse :func:`!cocotb.end_test` or :func:`!pytest.skip` instead of raising :exc:`!TestSuccess`\n*******************************************************************************************\n\nChange\n======\n\n:external+cocotb19:py:exc:`~cocotb.result.TestSuccess` was deprecated and replaced with :func:`cocotb.end_test` and :func:`pytest.skip`.\n\nHow To Upgrade\n==============\n\nReplace ``raise TestSuccess(msg)`` with a call to :func:`!cocotb.end_test` when you need to end the test immediately.\nReplace ``raise TestSuccess(msg)`` with a call to :func:`!pytest.skip` when you need to end the test immediately and force the outcome to 'skipped'.\n\n.. code-block:: python\n    :caption: Old way with :exc:`!TestSuccess`\n    :class: removed\n\n    if cocotb.top.error.value == 0:\n        raise TestSuccess(\"Test finished without DUT erroring\")\n\n.. code-block:: python\n    :caption: New way with :func:`!cocotb.end_test`\n    :class: new\n\n    if cocotb.top.error.value == 0:\n        cocotb.end_test(\"Test finished without DUT erroring\")\n\n.. code-block:: python\n    :caption: New way with :func:`!pytest.skip`\n    :class: new\n\n    if cocotb.top.param.value == 0:\n        pytest.skip(\"Test skipped because param is 0\")\n\nRationale\n=========\n\ncocotb needs a way to end a test from any Task, not just the main test Task.\n:exc:`!TestSuccess` was created for that purpose.\nBut being an exception, it has an additional implied interface:\n\n- It is acceptable to catch it.\n- It will propagate through Tasks like other exceptions do.\n\nHowever, neither of these implied behaviors is actually supported.\n\n:func:`!cocotb.end_test` and :func:`!pytest.skip` being function calls avoids these implicit interfaces.\nThey also parallel the design of :func:`sys.exit`.\n\n\n*******************************************************************\nFail tests using :keyword:`!assert` rather than :exc:`!TestFailure`\n*******************************************************************\n\nChange\n======\n\n:external+cocotb19:py:exc:`~cocotb.result.TestFailure` was removed.\n\nHow to Upgrade\n==============\n\nReplace ``raise TestFailure(msg)`` with an :keyword:`assert` statement.\nMove any exception message to the optional message clause of the :keyword:`!assert` statement.\n\n.. code-block:: python\n    :caption: Old way with :exc:`!TestFailure`\n    :class: removed\n\n    if cocotb.top.error.value != 0:\n        raise TestFailure(\"DUT errored\")\n\n.. code-block:: python\n    :caption: New way with :keyword:`!assert`\n    :class: new\n\n    assert cocotb.top.error.value == 0, \"DUT errored\"\n\nRationale\n=========\n\ncocotb had far too many competing ways to fail a test, so they were reduced to one.\n:keyword:`assert` is already familiar to those who have ever used :mod:`pytest`,\nand :mod:`!pytest` functionality can be leveraged to rewrite the :exc:`AssertionError`\\ s coming from failing :keyword:`!assert`\\ s\nwith more contextual information as to why the :keyword:`!assert` failed.\n\n\n*********************************\nReplace uses of :exc:`!TestError`\n*********************************\n\nChange\n======\n\n:external+cocotb19:py:exc:`~cocotb.result.TestError` was removed.\n\nHow to Upgrade\n==============\n\nReplace :exc:`!TestError` with a `more appropriate exception type <https://docs.python.org/3/library/exceptions.html#concrete-exceptions>`_.\n\n.. code-block:: python\n    :caption: Old way with :exc:`!TestError`\n    :class: removed\n\n    def drive(pkt):\n        if not isinstance(pkt, bytes):\n            raise TestError(\"packet must be bytes\")\n        ...\n\n.. code-block:: python\n    :caption: New way with more appropriate exception type\n    :class: new\n\n    def drive(pkt):\n        if not isinstance(pkt, bytes):\n            raise TypeError(\"packet must be bytes\")\n        ...\n\nRationale\n=========\n\n:exc:`TestError` is unnecessarily cocotb-specific and another redundant way to fail the test with an error,\nso it was removed.\n\n\n****************************************************************************************************\nUse ``sources`` argument in :meth:`Runner.build` instead of ``vhdl_sources`` and ``verilog_sources``\n****************************************************************************************************\n\nChange\n======\n\nThe ``vhdl_sources`` and ``verilog_sources`` arguments to :meth:`.Runner.build` have been deprecated and replaced with the ``sources`` argument.\n\nHow to Upgrade\n==============\n\nInstead of splitting your sources between the ``vhdl_sources`` and ``verilog_sources`` arguments,\npass all sources via the ``sources`` argument.\nSources will be compiled in the given order, left-to-right.\n\n.. code-block:: python\n    :caption: Old way with ``vhdl_sources`` and ``verilog_sources``\n    :class: removed\n\n    runner = get_runner()\n    runner.build(\n        vhdl_sources=[\"top.vhdl\"],\n        verilog_sources=[\"ip_core.sv\"],\n    )\n\n.. code-block:: python\n    :caption: New way with ``sources``\n    :class: new\n\n    runner = get_runner()\n    runner.build(\n        sources=[\"ip_core.sv\", \"top.vhdl\"],\n    )\n\n.. note::\n    If you are unsure about the order the sources should be compiled in with mixed-language simulators,\n    prefer compiling all VHDL sources, then all Verilog sources.\n    This is the order of compilation when using separate ``vhdl_sources`` and ``verilog_sources`` arguments.\n\nRationale\n=========\n\nSplitting the two types of sources made arbitrary build ordering of VHDL and Verilog sources impossible.\nThis approach also reduces verbosity and hidden assumptions about compilation order.\n\nAdditional Details\n==================\n\nSource files are judged to be either VHDL or Verilog sources and compiled appropriately for your simulator.\nThe runner uses the file extension to determine whether the source file is VHDL or Verilog\n(see :meth:`.Runner.build` for details).\nIf you use custom file extensions,\nyou can use the :class:`~cocotb_tools.runner.VHDL` and :class:`~cocotb_tools.runner.Verilog` tag classes\nto mark the sources as either VHDL or Verilog, respectively.\n\n.. code-block:: python\n\n    runner = get_runner()\n    runner.build(\n        sources=[Verilog(\"ip_core.gen\"), \"top.vhdl\"],\n    )\n\n\n********************************************************************\nUse :data:`!cocotb.log` over loggers on handles, tasks, and triggers\n********************************************************************\n\nChange\n======\n\n``handle._log``,\n``Task.log``,\nand ``Trigger.log`` were made private.\nAll loggers in the ``\"cocotb\"`` namespace were reserved for internal use only.\n:data:`cocotb.log` was changed to be the ``\"test\"`` logger.\n\nHow To Upgrade\n==============\n\nReplace all uses of the loggers on cocotb objects with :data:`!cocotb.log`.\nUse the :func:`repr` of the object in the message if desired.\n\n.. code-block:: python\n    :caption: Old way with ``\"cocotb\"`` namespace loggers.\n    :class: removed\n\n    cocotb.top.signal._log.info(\"logging from a handle\")\n\n    task = cocotb.start_soon(example())\n    task.log.info(\"logging from a task\")\n\n    trigger = Timer(10, 'ns')\n    trigger.log.info(\"logging from a trigger\")\n\n.. code-block:: python\n    :caption: New way with :data:`!cocotb.log`\n    :class: new\n\n    cocotb.log.info(\"%r: logging from a handle\", cocotb.top.signal)\n\n    task = cocotb.start_soon(example())\n    cocotb.log.info(\"%r: logging from a task\", task)\n\n    trigger = Timer(10, 'ns')\n    cocotb.log.info(\"%r: logging from a trigger\", trigger)\n\nRationale\n=========\n\nThe ``\"cocotb\"`` logging namespace was reserved for cocotb internal use\nso that it can offer users better control over the verbosity of those messages.\nAs a result, the :data:`!cocotb.log` logger name was changed from ``\"cocotb\"``\nand all loggers on cocotb internal objects were made private (these loggers were in the ``\"cocotb\"`` namespace).\n\n\n****************************************************************\nUse :meth:`!handle.is_const` instead of :class:`!ConstantObject`\n****************************************************************\n\nChange\n======\n\n:external+cocotb19:py:class:`~cocotb.handle.ConstantObject` was removed.\n:attr:`handle.is_const <cocotb.handle.ValueObjectBase.is_const>` was added to replace it.\n\nHow to Upgrade\n==============\n\nReplace uses of ``isinstance(handle, ConstantObject)`` as a way to check the constant-ness of a simulator object\nwith checking the handle's :attr:`is_const` attribute.\n\n.. code-block:: python\n    :caption: Old way with :class:`!ConstantObject`\n    :class: removed\n\n    if isinstance(cocotb.top.PARAM, ConstantObject):\n        ...\n\n.. code-block:: python\n    :caption: New way with :attr:`is_const`\n    :class: new\n\n    if cocotb.top.PARAM.is_const:\n        ...\n\n\nRationale\n=========\n\n:class:`!ConstantObject` was a single type that serviced all constant objects regardless of their data type.\nThis made it fragile to users getting the data type incorrect and values being applied incorrectly or causing crashes.\nNow constant objects are mapped to the appropriate handle type and these issues can't occur.\n\n\n*************************************************\nUse getitem syntax instead of :meth:`!handle._id`\n*************************************************\n\nChange\n======\n\n:external+cocotb19:py:meth:`handle._id() <cocotb.handle.HierarchyObject._id>` was deprecated.\n\nHow to Upgrade\n==============\n\nReplace calls to :meth:`!handle._id` with ``handle[\"child\"]`` syntax.\nIf the ``extended`` argument is ``True``, ensure to add a ``\\`` character before and after the name.\n\n.. code-block:: python\n    :caption: Old way with :meth:`handle._id`\n    :class: removed\n\n    cocotb.top._id(\"!special-name\", extended=True)\n\n    cocotb.top._id(\"_name_starts_with_underscore\", extended=False)\n\n.. code-block:: python\n    :caption: New way with getitem syntax\n    :class: new\n\n    cocotb.top[\"\\\\!special-name\\\\\"]\n\n    cocotb.top[\"_name_starts_with_underscore\"]\n\nRationale\n=========\n\nThe getitem syntax is a more Pythonic way to index into maps,\nsuch as named collections of child simulator objects.\n"
  },
  {
    "path": "docs/source/writing_testbenches.rst",
    "content": ".. _writing_tbs:\n\n*******************\nWriting Testbenches\n*******************\n\n\nLogging\n=======\n\ncocotb uses Python's :mod:`logging` library, with the configuration described in :ref:`logging-reference-section` to provide some sensible defaults.\n``cocotb.log.info`` is a good stand-in for :func:`print`,\nbut user are encouraged to create their own loggers and logger hierarchy by calling :func:`logging.getLogger` and/or :meth:`.Logger.getChild`.\n\nLogging functions `only` log messages, they do not cause the test to fail.\nSee :ref:`passing_and_failing_tests` for more information on how to fail a test.\n\n.. code-block:: python\n\n    import logging\n    import cocotb\n\n    @cocotb.test()\n    async def test(dut):\n        # Create a logger for this testbench\n        logger = logging.getLogger(\"my_testbench\")\n\n        logger.debug(\"This is a debug message\")\n        logger.info(\"This is an info message\")\n        logger.warning(\"This is a warning message\")\n        logger.error(\"This is an error message\")\n        logger.critical(\"This is a critical message\")\n\n.. note::\n\n    Writing messages to the log/console using the built-in function :func:`print` is not recommended in cocotb testbenches.\n    :func:`print` defaults to writing to ``stdout``, which is often buffered;\n    not only by the Python runtime, but sometimes by the simulator as well.\n    This can make messages appear out-of-order compared to messages coming from the simulator or the :term:`DUT`.\n\n.. warning::\n\n    The ``\"cocotb\"`` and ``\"gpi\"`` logger namespaces and all :class:`~logging.Logger`\\ s on cocotb-created objects are reserved for internal use only.\n\n\n.. _writing_tbs_accessing_design:\n\nAccessing the design\n====================\n\nWhen cocotb initializes it finds the toplevel instantiation in the simulator\nand creates a *handle* called ``dut``. Toplevel signals can be accessed using the\n\"dot\" notation used for accessing object attributes in Python. The same mechanism\ncan be used to access signals inside the design.\n\n.. code-block:: python\n\n    # Get a reference to the \"clk\" signal on the toplevel\n    clk = dut.clk\n\n    # Get a reference to a register \"count\"\n    # in a sub-block \"inst_sub_block\"\n    # (the instance name of a Verilog module or VHDL entity/component)\n    count = dut.inst_sub_block.count\n\n\n.. _writing_tbs_finding_elements:\n\nFinding elements in the design\n==============================\n\nTo find elements of the DUT\n(for example, instances, signals, constants or Verilog packages)\nat a certain hierarchy level,\nyou can use the :func:`dir` function on a handle.\n\n.. code-block:: python\n\n    # Print the instances and signals (which includes the ports) of the design's toplevel\n    cocotb.log.info(dir(dut))\n\n    # Print the instances and signals of \"inst_sub_block\" under the toplevel\n    # which is the instance name of a Verilog module or VHDL entity/component\n    cocotb.log.info(dir(dut.inst_sub_block))\n\n    # Print the packages\n    cocotb.log.info(dir(cocotb.packages))\n\n\n.. _writing_tbs_assigning_values:\n\nAssigning values to signals\n===========================\n\nValues can be assigned to signals using either the\n:attr:`~cocotb.handle.ValueObjectBase.value` property of a handle object\nor :meth:`~cocotb.handle.ValueObjectBase.set` method of a handle object.\n\n.. code-block:: python\n\n    # Get a reference to the \"clk\" signal and assign a value\n    clk = dut.clk\n    clk.value = 1\n\n    # Direct assignment through the hierarchy\n    dut.input_signal.value = 12\n\n    # Assign a value to a memory deeper in the hierarchy\n    # (\"inst_sub_block\" and \"inst_memory\" are instance names of the\n    # respective Verilog modules or VHDL entity/components in the DUT)\n    dut.inst_sub_block.inst_memory.mem_array[4].value = 2\n\n\nThe assignment syntax ``sig.value = new_value`` has the same semantics as :term:`HDL`:\nwrites are not applied immediately, but delayed until the next write cycle.\nUse :class:`~cocotb.handle.Immediate` to set a new value immediately.\n\n.. _writing_tbs_assigning_values_signed_unsigned:\n\nSigned and unsigned values\n--------------------------\n\nBoth signed and unsigned values can be assigned to signals using a Python int.\ncocotb makes no assumptions regarding the signedness of the signal. It only\nconsiders the width of the signal, so it will allow values in the range from\nthe minimum negative value for a signed number up to the maximum positive\nvalue for an unsigned number: ``-2**(Nbits - 1) <= value <= 2**Nbits - 1``\nNote: assigning out-of-range values will raise an :exc:`ValueError`.\n\nA :class:`~cocotb.types.LogicArray` object can be used instead of a Python int to assign a\nvalue to signals with more fine-grained control (e.g. signed values only).\n\n.. code-block:: verilog\n\n    module my_module (\n        input   logic       clk,\n        input   logic       rst,\n        input   logic [2:0] data_in,\n        output  logic [2:0] data_out\n        );\n\n.. code-block:: python\n\n    # assignment of negative value\n    dut.data_in.value = -4\n\n    # assignment of positive value\n    dut.data_in.value = 7\n\n    # assignment of out-of-range values\n    dut.data_in.value = 8   # raises ValueError\n    dut.data_in.value = -5  # raises ValueError\n\n\n.. _writing_tbs_reading_values:\n\nReading values from signals\n===========================\n\nValues in the DUT can be accessed with the :attr:`~cocotb.handle.ValueObjectBase.value`\nproperty of a handle object.\nA common mistake is forgetting the ``.value`` which just gives you a reference to a handle\n(useful for defining an alias name), not the value.\n\nThe Python type of a value depends on the handle's HDL type:\n\n* Arrays of ``logic`` and subtypes of that (``sfixed``, ``unsigned``, etc.)\n  are of type :class:`~cocotb.types.LogicArray`.\n* Integer nets and constants (``integer``, ``natural``, etc.) return :class:`int`.\n* Floating point nets and constants (``real``) return :class:`float`.\n* Boolean nets and constants (``boolean``) return :class:`bool`.\n* String nets and constants (``string``) return :class:`bytes`.\n\n.. todo::\n    Add simple example of how to use LogicArray\n\n\n.. _writing_tbs_identifying_tests:\n\nIdentifying tests\n=================\n\ncocotb tests are identified using the :deco:`cocotb.test` decorator.\nUsing this decorator will tell cocotb that this function is a special type of coroutine that is meant\nto either pass or fail.\nThe :deco:`cocotb.test` decorator supports several keyword arguments (see section :ref:`writing-tests`).\nIn most cases no arguments are passed to the decorator so cocotb tests can be written as:\n\n.. code-block:: python\n\n    # A valid cocotb test\n    @cocotb.test\n    async def test(dut):\n        ...\n\n    # Also a valid cocotb test\n    @cocotb.test()  # added ()\n    async def test(dut):\n        ...\n\n    # Another valid cocotb test\n    @cocotb.test(\n        skip=cocotb.top.feature.value != 1  # skip if feature disabled\n    )\n    async def test(dut):\n        ...\n\n.. _writing_tbs_concurrent_sequential:\n\nConcurrent and sequential execution\n===================================\n\nAn :keyword:`await` will run an :keyword:`async` coroutine and wait for it to complete.\nThe called coroutine \"blocks\" the execution of the current coroutine.\nWrapping the call in :func:`~cocotb.start_soon` runs the coroutine concurrently,\nallowing the current coroutine to continue executing.\nAt any time you can await the result of a :class:`~cocotb.task.Task`,\nwhich will block the current coroutine's execution until the task finishes.\n\nThe following example shows these in action:\n\n.. code-block:: python\n\n    # A coroutine\n    async def reset_dut(reset_n, duration_ns):\n        reset_n.value = 0\n        await Timer(duration_ns, unit=\"ns\")\n        reset_n.value = 1\n        cocotb.log.debug(\"Reset complete\")\n\n    @cocotb.test()\n    async def parallel_example(dut):\n        reset_n = dut.reset\n\n        # Execution will block until reset_dut has completed\n        await reset_dut(reset_n, 500)\n        cocotb.log.debug(\"After reset\")\n\n        # Run reset_dut concurrently\n        reset_thread = cocotb.start_soon(reset_dut(reset_n, duration_ns=500))\n\n        # This timer will complete before the timer in the concurrently executing \"reset_thread\"\n        await Timer(250, unit=\"ns\")\n        cocotb.log.debug(\"During reset (reset_n = %s)\" % reset_n.value)\n\n        # Wait for the other thread to complete\n        await reset_thread\n        cocotb.log.debug(\"After reset\")\n\nSee :ref:`coroutines` for more examples of what can be done with coroutines.\n\n\n.. _writing_tbs_assigning_values_forcing_freezing:\n\nForcing and freezing signals\n============================\n\nIn addition to regular value assignments (deposits), signals can be forced\nto a predetermined value or frozen at their current value. To achieve this,\nthe various actions described in :ref:`assignment-methods` can be used.\n\n.. autolink-preface:: from cocotb.handle import Deposit, Force, Freeze, Release\n.. code-block:: python\n\n    # Deposit action\n    dut.my_signal.value = 12\n    dut.my_signal.value = Deposit(12)  # equivalent syntax\n\n    # Force action\n    dut.my_signal.value = Force(12)    # my_signal stays 12 until released\n\n    # Release action\n    dut.my_signal.value = Release()    # Reverts any force/freeze assignments\n\n    # Freeze action\n    dut.my_signal.value = Freeze()     # my_signal stays at current value until released\n\n.. warning::\n\n    Not all simulators support these features; refer to the :ref:`simulator-support` section for details or to `issues with label \"upstream\" <https://github.com/cocotb/cocotb/issues?q=is%3Aissue+-label%3Astatus%3Aduplicate+label%3Aupstream>`_\n\n\n.. _writing_tbs_accessing_underscore_identifiers:\n\nAccessing identifiers starting with an underscore or invalid Python names\n=========================================================================\n\nThe attribute syntax of ``dut._some_signal`` cannot be used to access\nan identifier that starts with an underscore (``_``, as is valid in Verilog)\nbecause we reserve such names for cocotb-internals,\nthus the access will raise an :exc:`AttributeError`.\n\nBoth SystemVerilog and VHDL allow developers to create signals or nets with non-standard characters by using special syntax.\nThese objects are generally not accessible using attribute syntax since attributes in Python must follow a strict form.\n\nAll named objects, including those with the aforementioned limitations, can be accessed using index syntax.\n\n.. code-block:: python\n\n    dut[\"_some_signal\"]  # begins with underscore\n    dut[\"\\\\!WOOOOW!\\\\\"]  # escaped identifier (Verilog), extended identifier (VHDL)\n\n\n.. _writing_tbs_accessing_verilog_packages:\n\nAccessing Verilog packages\n==========================\n\nVerilog packages are accessible via :data:`cocotb.packages`.\nDepending on the simulator, packages may need to be imported in\nthe compilation unit scope or inside a module in order to be discoverable.\nAlso note, the ``$unit`` pseudo-package is implemented differently between simulators.\nIt may appear as one or more attributes here depending on the number of compilation units.\n\n.. code-block:: verilog\n\n    package my_package;\n        parameter int foo = 7\n    endpackage\n\n.. code-block:: python\n\n    # prints \"7\"\n    cocotb.log.info(cocotb.packages.my_package.foo.value)\n\n\nForcing a test to end with a given result\n=========================================\n\nIn addition to the normal ways a test can pass or fail (see :ref:`passing_and_failing_tests`),\na test can be forced to end with a given result using the following functions:\n\n* :func:`pytest.xfail` to end the test with an expected fail (considered a pass)\n* :func:`pytest.skip` to end the test with a skip\n\nThese functions can be called from any Task and will end the test immediately with the given result.\nThey are typically used when you cannot use the :deco:`cocotb.skipif` or :deco:`cocotb.xfail` decorators\nto describe the exact conditions under which a test should be skipped or have reached an expected fail state.\n\n.. code-block:: python\n\n    @cocotb.test()\n    async def test(dut):\n        if load_stimulus_from_a_file(dut.paramA, dut.paramB) is None:\n            pytest.skip(\"The test stimulus is not available, assuming this combination of parameters is not supported\")\n\n    @cocotb.test()\n    async def test(dut):\n        ...\n        if dut.read_empty.value == 0:\n            pytest.xfail(\"The read interface is not empty, but this test is expected to fail in this case\")\n\n\n.. _passing_and_failing_tests:\n\nPassing and failing tests\n=========================\n\nWhen cocotb tests complete execution, they have either `passed` or `failed`.\n\nIn general, if the main test coroutine completes without raising an :exc:`!Exception`,\nor if the test coroutine or any running :class:`~cocotb.task.Task` calls :func:`cocotb.pass_test`,\nthe test is considered to have `passed`.\nAlso, if the main test coroutine raises a :exc:`~asyncio.CancelledError`,\nor is :keyword:`await`\\ ing a :class:`!Task` that is cancelled and does not handle it (or re-raises it),\nthe test will end immediately but it will have `passed`.\n\nBelow are examples of `passing` tests.\n\n.. code-block:: python\n\n    @cocotb.test()\n    async def test(dut):\n        assert 2 > 1  # assertion is correct, then the coroutine ends\n\n    @cocotb.test()\n    async def test(dut):\n        cocotb.pass_test(\"Reason\")  # ends test with success early\n        assert 1 > 2  # this would fail, but it isn't run because the test was ended early\n\n    @cocotb.test()\n    async def test(dut):\n        async def ends_test_with_pass():\n            cocotb.pass_test(\"Reason\")\n        cocotb.start_soon(ends_test_with_pass())\n        await Timer(10, 'ns')\n\n    @cocotb.test()\n    async def test(dut):\n        async def cancelled_after_time():\n            await Timer(1, unit='ns')\n            raise CancelledError\n        t = cocotb.start_soon(cancelled_after_time())\n        await t\n\nA passing test will print the following output.\n\n.. code-block::\n\n    0.00ns INFO     Test Passed: test\n\nA cocotb test is considered to have `failed` if the test coroutine or any running :class:`~cocotb.task.Task`\nfails an :keyword:`assert` statement, fails :func:`pytest.raises` or :func:`pytest.warns` checks,\nor raises any other :exc:`!Exception` besides :exc:`!CancelledError`.\n\nBelow are examples of `failed` tests that failed assertion statements.\n\n.. code-block:: python\n\n    @cocotb.test()\n    async def test(dut):\n        assert 1 > 2, \"Testing the obvious\"\n\n    @cocotb.test()\n    async def test(dut):\n        async def fails_test():\n            assert 1 > 2\n        cocotb.start_soon(fails_test())\n        await Timer(10, 'ns')\n\nWhen a test fails, a stacktrace is printed.\n\nIf :mod:`pytest` is installed and assert statements are used,\na more informative stacktrace is printed which includes the values that caused the assert to fail.\nFor example, see the output for the first test from above.\n\n.. code-block::\n\n    0.00ns ERROR    Test Failed: test (result was AssertionError)\n                    Traceback (most recent call last):\n                      File \"test.py\", line 3, in test\n                        assert 1 > 2, \"Testing the obvious\"\n                    AssertionError: Testing the obvious\n\nBelow are examples of `failed` tests that raised an :exc:`!Exception`.\n\n.. code-block:: python\n\n    @cocotb.test()\n    async def test(dut):\n        await coro_that_does_not_exist()  # NameError\n\n    @cocotb.test()\n    async def test(dut):\n        async def coro_with_an_error():\n            dut.signal_that_does_not_exist.value = 1  # AttributeError\n        cocotb.start_soon(coro_with_an_error())\n        await Timer(10, 'ns')\n\nWhen a test ends with an :exc:`!Exception`, a stacktrace is printed.\nFor example, see the below output for the first test from above.\n\n.. code-block::\n\n    0.00ns ERROR    Test Failed: test (result was NameError)\n                    Traceback (most recent call last):\n                      File \"test.py\", line 3, in test\n                        await coro_that_does_not_exist()  # NameError\n                    NameError: name 'coro_that_does_not_exist' is not defined\n\nIn summary:\n\n+--------------+--------------------------------------------------------------------------+\n|| Test Passed || Test ends without raising :exc:`!Exception`.                            |\n||             || Test or Task calls :func:`cocotb.pass_test`.                            |\n||             || Test raises :exc:`~asyncio.CancelledError`.                             |\n+--------------+--------------------------------------------------------------------------+\n|| Test Failed || Test fails an :keyword:`assert` statement.                              |\n||             || Test or Task raises :exc:`AssertionError`.                              |\n||             || Test or Task fails :func:`pytest.raises` or :func:`pytest.warns` check. |\n||             || Test or Task raises any other :exc:`!Exception`.                        |\n+--------------+--------------------------------------------------------------------------+\n\n.. note::\n    For the purpose of denoting expected test failures that should be marked as passed,\n    and differentiating between specific types of failures,\n    see the ``expect_fail`` and ``expect_error`` arguments of the :func:`cocotb.test` decorator.\n\n\nCleaning up resources\n=====================\n\nWhen you call :meth:`.Task.cancel` on a Task,\na :exc:`~asyncio.CancelledError` will be raised which can be caught to run cleanup or end-of-test code.\nThis will also trigger the finalization routine of any :term:`context manager`.\n\nWhen a test ends, the cocotb runtime will call :meth:`.Task.cancel` on all running tasks started with :func:`cocotb.start_soon`,\nallowing for end-of-test cleanup.\n\n.. code-block:: python\n\n    @cocotb.test()\n    async def test(dut):\n\n        async def drive_data_valid(intf, sequence):\n            try:\n                intf.valid.value = 1\n                for data in sequence:\n                    intf.data.value = data\n            finally:\n                # Ensure that valid is brought back to 0 when the test ends,\n                # the Task is explicitly cancelled, or if the Task ends normally.\n                intf.valid.value = 0\n\n        # Generate sequence\n        sequence = ...\n\n        # Run driver Task concurrently\n        cocotb.start_soon(drive_data_valid(dut.data_in, sequence))\n\n        # Do other stuff\n\n.. note::\n    If a :exc:`!CancelledError` is handled in a Task and not re-raised, the test will be considered to have :ref:`errored <passing_and_failing_tests>`.\n    This is to prevent Tasks from attempting to ignore cancellation.\n    For that reason, it is recommended to use :keyword:`finally` rather than specifically catching :exc:`!CancelledError`.\n"
  },
  {
    "path": "examples/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nEXAMPLES := adder/tests \\\n            simple_dff \\\n            matrix_multiplier/tests \\\n            mixed_language/tests \\\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    ifeq ($(SIM),$(filter $(SIM),ius xcelium))\n        ifeq (,$(shell which spectre))\n            $(info Skipping example mixed_signal since Spectre is not available)\n        else\n            EXAMPLES += mixed_signal/tests\n        endif\n    else\n        $(info Skipping example mixed_signal since only Xcelium is supported)\n    endif\n    EXAMPLES += doc_examples/quickstart\nendif\n\n.PHONY: $(EXAMPLES)\n\n.PHONY: all\nall: $(EXAMPLES)\n\n$(EXAMPLES):\n\t@cd $@ && $(MAKE)\n\n.PHONY: clean\nclean:\n\t$(foreach TEST, $(EXAMPLES), $(MAKE) -C $(TEST) clean;)\n\nregression:\n\t$(foreach TEST, $(EXAMPLES), $(MAKE) -C $(TEST) regression;)\n"
  },
  {
    "path": "examples/adder/hdl/adder.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n// Adder DUT\n`timescale 1ns/1ps\n\nmodule adder #(\n  parameter integer DATA_WIDTH = 4\n) (\n  input  logic unsigned [DATA_WIDTH-1:0] A,\n  input  logic unsigned [DATA_WIDTH-1:0] B,\n  output logic unsigned [DATA_WIDTH:0]   X\n);\n\n  assign X = A + B;\n\nendmodule\n"
  },
  {
    "path": "examples/adder/hdl/adder.vhdl",
    "content": "-- This file is public domain, it can be freely copied without restrictions.\n-- SPDX-License-Identifier: CC0-1.0\n-- Adder DUT\nlibrary ieee;\n  use ieee.std_logic_1164.all;\n  use ieee.numeric_std.all;\n\nentity adder is\n  generic (\n    DATA_WIDTH : positive := 4);\n  port (\n    A : in    unsigned(DATA_WIDTH-1 downto 0);\n    B : in    unsigned(DATA_WIDTH-1 downto 0);\n    X : out   unsigned(DATA_WIDTH downto 0));\nend entity adder;\n\narchitecture rtl of adder is\nbegin\n\n  add_proc : process (A, B) is\n  begin\n    X <= resize(A, X'length) + B;\n  end process add_proc;\n\nend architecture rtl;\n"
  },
  {
    "path": "examples/adder/model/__init__.py",
    "content": ""
  },
  {
    "path": "examples/adder/model/adder_model.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\n\ndef adder_model(a: int, b: int) -> int:\n    \"\"\"model of adder\"\"\"\n    return a + b\n"
  },
  {
    "path": "examples/adder/tests/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nPWD=$(shell pwd)\n\nexport PYTHONPATH := $(PWD)/../model:$(PYTHONPATH)\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    VERILOG_SOURCES = $(PWD)/../hdl/adder.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    VHDL_SOURCES = $(PWD)/../hdl/adder.vhdl\n    ifneq ($(filter $(SIM),ius xcelium),)\n        COMPILE_ARGS += -v93\n    endif\nelse\n    $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\nCOCOTB_TOPLEVEL     := adder\nCOCOTB_TEST_MODULES := test_adder\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "examples/adder/tests/test_adder.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\n# Simple tests for an adder module\nfrom __future__ import annotations\n\nimport os\nimport random\nimport sys\nfrom pathlib import Path\n\nimport cocotb\nfrom cocotb.triggers import Timer\nfrom cocotb_tools.runner import get_runner\n\nif cocotb.simulator.is_running():\n    from adder_model import adder_model\n\n\n@cocotb.test()\nasync def adder_basic_test(dut):\n    \"\"\"Test for 5 + 10\"\"\"\n\n    A = 5\n    B = 10\n\n    dut.A.value = A\n    dut.B.value = B\n\n    await Timer(2, unit=\"ns\")\n\n    assert dut.X.value == adder_model(A, B), (\n        f\"Adder result is incorrect: {dut.X.value} != 15\"\n    )\n\n\n@cocotb.test()\nasync def adder_randomised_test(dut):\n    \"\"\"Test for adding 2 random numbers multiple times\"\"\"\n\n    for _ in range(10):\n        A = random.randint(0, 15)\n        B = random.randint(0, 15)\n\n        dut.A.value = A\n        dut.B.value = B\n\n        await Timer(2, unit=\"ns\")\n\n        assert dut.X.value == adder_model(A, B), (\n            f\"Randomised test failed with: {dut.A.value} + {dut.B.value} = {dut.X.value}\"\n        )\n\n\ndef test_adder_runner():\n    \"\"\"Simulate the adder example using the Python runner.\n\n    This file can be run directly or via pytest discovery.\n    \"\"\"\n    hdl_toplevel_lang = os.getenv(\"TOPLEVEL_LANG\", \"verilog\")\n    sim = os.getenv(\"SIM\", \"icarus\")\n\n    proj_path = Path(__file__).resolve().parent.parent\n    # equivalent to setting the PYTHONPATH environment variable\n    sys.path.append(str(proj_path / \"model\"))\n\n    if hdl_toplevel_lang == \"verilog\":\n        sources = [proj_path / \"hdl\" / \"adder.sv\"]\n    else:\n        sources = [proj_path / \"hdl\" / \"adder.vhdl\"]\n\n    build_test_args = []\n    if hdl_toplevel_lang == \"vhdl\" and sim == \"xcelium\":\n        build_test_args = [\"-v93\"]\n\n    # equivalent to setting the PYTHONPATH environment variable\n    sys.path.append(str(proj_path / \"tests\"))\n\n    runner = get_runner(sim)\n    runner.build(\n        sources=sources,\n        hdl_toplevel=\"adder\",\n        always=True,\n        build_args=build_test_args,\n    )\n    runner.test(\n        hdl_toplevel=\"adder\", test_module=\"test_adder\", test_args=build_test_args\n    )\n\n\nif __name__ == \"__main__\":\n    test_adder_runner()\n"
  },
  {
    "path": "examples/analog_model/Makefile",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\n\nTOPLEVEL_LANG = verilog\nVERILOG_SOURCES = $(shell pwd)/digital.sv\nCOCOTB_TOPLEVEL = digital\n\nCOCOTB_TEST_MODULES = test_analog_model\n\nifneq ($(filter $(SIM),ius xcelium),)\n    SIM_ARGS += -unbuffered\nendif\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "examples/analog_model/afe.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.queue import Queue\nfrom cocotb.triggers import Timer\n\n\"\"\"\nThis is a Python model of an Analog Front-End (AFE) containing\na Programmable Gain Amplifier (PGA) with a selectable gain of 5.0 and 10.0\nand a 13-bit Analog-to-Digital Converter (ADC) with a reference voltage of 2.0 V.\n\nThese analog models hand over data via a blocking :class:`cocotb.queue.Queue`.\n\"\"\"\n\n\nclass PGA:\n    \"\"\"\n    Model of a Programmable Gain Amplifier.\n\n    *gain* is the amplification factor.\n    \"\"\"\n\n    def __init__(\n        self,\n        gain: float = 5.0,\n        in_queue: Queue | None = None,\n        out_queue: Queue | None = None,\n    ) -> None:\n        self._gain = gain\n        self.in_queue = in_queue\n        self.out_queue = out_queue\n\n        cocotb.start_soon(self.run())\n\n    @property\n    def gain(self) -> float:\n        return self._gain\n\n    @gain.setter\n    def gain(self, val: float) -> None:\n        self._gain = val\n\n    async def run(self) -> None:\n        while True:\n            in_val_V = await self.in_queue.get()\n            await Timer(1.0, \"ns\")  # delay\n            await self.out_queue.put(in_val_V * self._gain)\n\n\nclass ADC:\n    \"\"\"\n    Model of an Analog-to-Digital Converter.\n\n    *ref_val_V* is the reference voltage in V, *n_bits* is the resolution in bits.\n    \"\"\"\n\n    def __init__(\n        self,\n        ref_val_V: float = 2.0,\n        n_bits: int = 13,\n        in_queue: Queue | None = None,\n        out_queue: Queue | None = None,\n    ) -> None:\n        self.ref_val_V = ref_val_V\n        self.min_val = 0\n        self.max_val = 2**n_bits - 1\n        self.in_queue = in_queue\n        self.out_queue = out_queue\n\n        cocotb.start_soon(self.run())\n\n    async def run(self) -> None:\n        while True:\n            in_val_V = await self.in_queue.get()  # sample immediately\n            await Timer(1, \"us\")  # wait for conversion time\n            out = int((in_val_V / self.ref_val_V) * self.max_val)\n            if not (self.min_val <= out <= self.max_val):\n                print(\n                    f\"Saturating measurement value {out} to [{self.min_val}:{self.max_val}]!\"\n                )\n            await self.out_queue.put(min(max(self.min_val, out), self.max_val))\n\n\nclass AFE:\n    \"\"\"\n    Model of an Analog Front-End.\n\n    This model instantiates the sub-models PGA and ADC.\n    \"\"\"\n\n    def __init__(\n        self, in_queue: Queue | None = None, out_queue: Queue | None = None\n    ) -> None:\n        self.in_queue = in_queue\n        self.out_queue = out_queue\n        self.pga_to_adc_queue = Queue()\n\n        self.pga = PGA(in_queue=self.in_queue, out_queue=self.pga_to_adc_queue)\n        self.adc = ADC(in_queue=self.pga_to_adc_queue, out_queue=self.out_queue)\n"
  },
  {
    "path": "examples/analog_model/digital.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\nmodule digital (\n                input logic          clk,\n                input logic [13-1:0] meas_val,\n                input logic          meas_val_valid,\n                output logic         pga_high_gain\n                );\n\n  timeunit 1s;\n  timeprecision 1ns;\n\n  real max_val = 2**$bits(meas_val)-1;\n  real ref_val_V = 2.0;\n\n  initial begin\n    pga_high_gain = 0;  // start with low gain\n\n    // prints %t scaled in ns (-9), with 2 precision digits,\n    // and the \"ns\" string, last number is the minimum field width\n    $timeformat(-9, 2, \"ns\", 11);\n  end\n\n  always @(posedge clk) begin\n    if (meas_val_valid == 1) begin\n      $display(\"%t (%M) HDL got meas_val=%0d (0x%x)\", $realtime, meas_val, meas_val);\n\n      if (pga_high_gain == 0) begin\n        $display(\"%t (%M) PGA gain select was %0d --> calculated AFE input value back to %0f\",\n                 $realtime, pga_high_gain, meas_val/max_val/ 5.0 * ref_val_V);\n      end else begin\n        $display(\"%t (%M) PGA gain select was %0d --> calculated AFE input value back to %0f\",\n                 $realtime, pga_high_gain, meas_val/max_val/10.0 * ref_val_V);\n      end\n\n      // Automatic gain select:\n      // set new gain for the next measurement\n      if (meas_val > 0.7 * max_val) begin\n        if (pga_high_gain == 1) begin\n          $display(\"%t (%M) Measurement value is more than 70%% of max, switching PGA gain from 10.0 to 5.0\", $realtime);\n        end\n        pga_high_gain = 0;\n      end else if (meas_val < 0.3 * max_val) begin\n        if (pga_high_gain == 0) begin\n          $display(\"%t (%M) Measurement value is less than 30%% of max, switching PGA gain from 5.0 to 10.0\", $realtime);\n        end\n        pga_high_gain = 1;\n      end else begin\n        ;  // NOP; leave gain unchanged\n      end\n    end // if (meas_val_valid == 1)\n  end\n\nendmodule\n"
  },
  {
    "path": "examples/analog_model/test_analog_model.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\nfrom afe import AFE\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.queue import Queue\nfrom cocotb.triggers import RisingEdge, Timer, ValueChange\n\n\"\"\"\nThis example uses the Python model of an Analog Front-End (AFE)\nwhich contains a Programmable Gain Amplifier (PGA)\nand an Analog-to-Digital Converter (ADC).\n\nThe digital part (in HDL) monitors the measurement value converted by the ADC\nand selects the gain of the PGA based on the received value.\n\"\"\"\n\n\nasync def gain_select(digital, afe) -> None:\n    \"\"\"Set gain factor of PGA when gain select from the HDL changes.\"\"\"\n\n    while True:\n        await ValueChange(digital.pga_high_gain)\n        if digital.pga_high_gain.value == 0:\n            afe.pga.gain = 5.0\n        else:\n            afe.pga.gain = 10.0\n\n\n@cocotb.test()\nasync def test_analog_model(digital) -> None:\n    \"\"\"Exercise an Analog Front-end and its digital controller.\"\"\"\n\n    clock = Clock(digital.clk, 1, unit=\"us\")  # create a 1us period clock on port clk\n    cocotb.start_soon(clock.start())  # start the clock\n\n    afe_in_queue = Queue()\n    afe_out_queue = Queue()\n    afe = AFE(\n        in_queue=afe_in_queue, out_queue=afe_out_queue\n    )  # instantiate the analog front-end\n\n    cocotb.start_soon(gain_select(digital, afe))\n\n    for in_V in [0.1, 0.1, 0.0, 0.25, 0.25]:\n        # set the input voltage\n        await afe_in_queue.put(in_V)\n\n        # get the converted digital value\n        afe_out = await afe_out_queue.get()\n\n        cocotb.log.info(f\"AFE converted input value {in_V}V to {int(afe_out)}\")\n\n        # hand digital value over as \"meas_val\" to digital part (HDL)\n        # \"meas_val_valid\" pulses for one clock cycle\n        await RisingEdge(digital.clk)\n        digital.meas_val.value = afe_out\n        digital.meas_val_valid.value = 1\n        await RisingEdge(digital.clk)\n        digital.meas_val_valid.value = 0\n        await Timer(3.3, \"us\")\n"
  },
  {
    "path": "examples/doc_examples/quickstart/Makefile",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\n\n# Makefile\n\n# Defaults\nSIM ?= icarus\nTOPLEVEL_LANG ?= verilog\n\nVERILOG_SOURCES += $(PWD)/simple_counter.sv\n# use: VHDL_SOURCES for VHDL files\n\n# COCOTB_TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file\nCOCOTB_TOPLEVEL = simple_counter\n\n# COCOTB_TEST_MODULES is the basename of the Python test file(s)\nCOCOTB_TEST_MODULES = simple_counter_testcases\n\n# Enable waveform generation\nWAVES = 1\n\n# include cocotb's make rules to take care of the simulator setup\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "examples/doc_examples/quickstart/simple_counter.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\nmodule simple_counter (\n  input  logic clk,\n  input  logic rst,\n  input  logic ena,\n  input  logic set,\n  input  logic [7:0] din,\n  output logic [7:0] counter\n);\n\n  timeunit 1ns;\n  timeprecision 1ns;\n\n  always_ff @(posedge clk) begin\n    if (rst) begin\n      counter <= 8'd0;\n    end else begin\n      if (set) begin\n        counter <= din;\n      end else if (ena) begin\n        counter <= counter + 1;\n      end else begin\n        counter <= counter;\n      end\n    end\n  end\n\nendmodule\n"
  },
  {
    "path": "examples/doc_examples/quickstart/simple_counter_testcases.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\n\n\"\"\"This module contains testcases for the simple_counter\"\"\"\n\n# Imports for all Quickstart examples\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb import start_soon\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import FallingEdge, NextTimeStep, ReadOnly, RisingEdge, Timer\n\n# QUICKSTART 1\n\n\n@cocotb.test()\nasync def quickstart_1(dut):\n    \"\"\"Quickstart Example 1 - Showcasing a single sequential routine\n\n    Args:\n        dut: The HDL toplevel.\n    \"\"\"\n\n    # Initial value.\n    dut.ena.value = 0\n\n    # Reset sequence and clock start.\n    dut.rst.value = 1\n    input_clock = Clock(dut.clk, 10, unit=\"ns\")\n    input_clock.start()\n    await Timer(5, \"ns\")\n\n    # Re-synchronize with the clock\n    await RisingEdge(dut.clk)\n    dut.rst.value = 0\n\n    # Activating the dut.ena input signal, to enable the counter.\n    dut.ena.value = 1\n\n    count_cycles = 10\n    for _ in range(count_cycles):\n        await RisingEdge(dut.clk)\n\n    # Deactivating the dut.ena input signal, to disable the counter.\n    dut.ena.value = 0\n    await RisingEdge(dut.clk)\n    # Checking that the counter output.\n    assert dut.counter.value == count_cycles\n\n    # Wait some time, to let a few clock cycles pass.\n    await Timer(100, \"ns\")\n\n    # Checking that the \"counter\" output did not increment when ena was inactive.\n    assert dut.counter.value == count_cycles\n\n\n# END QUICKSTART 1\n\n# QUICKSTART 2\n\n\nasync def reset_and_start_clock(reset, clock, cycles=10):\n    \"\"\"Coroutine to active reset, and start a clock\n\n    Activate reset for a few cycles before deactivating and returning\n    Signals can be passed as arguments.\n\n    Args:\n        reset: The reset signal in the DUT.\n        clock: The clock signal in the DUT.\n        cycles: How many cycles to activate reset (default 10).\n    \"\"\"\n    reset.value = 1\n    input_clock = Clock(clock, 10, unit=\"ns\")\n    input_clock.start()\n    for _ in range(cycles):\n        await RisingEdge(clock)\n    reset.value = 0\n\n\nasync def enable_counter(dut, cycles=10):\n    \"\"\"Activate ``dut.ena`` for some clock cycles, before deactivating.\n\n    Signals do not have to be passed as arguments.\n\n    Args:\n        dut: the hdl toplevel\n        cycles: number of cycles to keep dut.ena high (default 10)\n    \"\"\"\n    await FallingEdge(dut.clk)\n    dut.ena.value = 1\n    for _ in range(cycles):\n        await RisingEdge(dut.clk)\n\n    dut.ena.value = 0\n    await RisingEdge(dut.clk)\n\n\nasync def check_counter(dut, start_value):\n    \"\"\"A run forever coroutine,  continuously checks the counter on every rising edge of the clock.\n\n    Args:\n        dut: the hdl toplevel\n        start_value: the expected value of the counter when this coroutine is started.\n    \"\"\"\n    expected_counter_value = start_value\n    assert dut.counter.value == expected_counter_value\n\n    while True:\n        await RisingEdge(dut.clk)\n        if dut.set.value == 1:\n            expected_counter_value = dut.din.value\n        elif dut.ena.value == 1:\n            expected_counter_value += 1\n\n        # Wait for the ReadOnly phase to let delta cycles complete.\n        await ReadOnly()  # More about this in Quickstart 3\n        assert dut.counter.value == expected_counter_value\n\n\n@cocotb.test()\nasync def quickstart_2(dut):\n    \"\"\"Quickstart Example 2 - Showcasing coroutines.\n\n    Args:\n        dut: the hdl toplevel\n    \"\"\"\n\n    # Signals in the dut can be assigned to variables for easier use.\n    # Can be useful for more complicated signal names.\n    rst = dut.rst\n    clk = dut.clk\n    # Starting reset sequence and clock\n    start_soon(reset_and_start_clock(rst, clk))\n\n    # Wait until the reset is inactive.\n    await FallingEdge(rst)\n\n    # Quick check after reset.\n    assert dut.counter.value == 0\n\n    # Start the check_counter().\n    start_soon(check_counter(dut, start_value=0))\n\n    # Start and wait for completion.\n    await start_soon(enable_counter(dut, cycles=10))\n\n    # Wait some time, the dut.ena is inactive at this point.\n    await Timer(100, \"ns\")\n\n    # Enable counting again, the check is still going.\n    await start_soon(enable_counter(dut, cycles=10))\n\n\n# END QUICKSTART 2\n\n# QUICKSTART 3\n\n\n@cocotb.test()\nasync def quickstart_3(dut):\n    \"\"\"Quickstart Example 3 - Showcasing reading a signal before assertion.\n\n    Args:\n        dut: the hdl toplevel\n    \"\"\"\n\n    # Same starting sequence as in Quickstart 2.\n    rst = dut.rst\n    clk = dut.clk\n    start_soon(reset_and_start_clock(rst, clk))\n    await FallingEdge(rst)\n\n    # Quick check after reset.\n    assert dut.counter.value == 0\n\n    # Setting some stimuli on the falling edge.\n    input_value = 10\n    await FallingEdge(clk)\n    dut.set.value = 1\n    dut.din.value = input_value\n\n    # Waiting for a rising edge before checking the output.\n    await RisingEdge(clk)\n    try:\n        assert dut.counter.value == input_value, (\n            \"This looks fine in the waveform, why does this fail?\\n\"\n            \"It is asserted to the exact same value that was assigned. Makes no sense?!\"\n        )\n    except AssertionError as e:\n        cocotb.log.error(e)\n        cocotb.log.warning(\n            \"It fails because the delta cycles of the simulator did not complete, \"\n            \"use ReadOnly() to let the signals 'stabilize'\"\n        )\n    await ReadOnly()\n    assert dut.counter.value == input_value, \"Now this should not fail!\"\n    await NextTimeStep()\n\n\n# END QUICKSTART 3\n"
  },
  {
    "path": "examples/doc_examples/quickstart/test_runner.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\n\n\"\"\"This module contains the cocotb Python test runner used to test ``simple_counter``.\"\"\"\n\n# test_runner.py\nfrom __future__ import annotations\n\nimport os\nfrom pathlib import Path\n\nfrom cocotb_tools.runner import get_runner\n\n\ndef test_simple_counter():\n    \"\"\"Test for the simple counter.\n\n    Creates sources list, gets a cocotb Python Runner,\n    builds HDL, runs cocotb testcases.\n    \"\"\"\n    proj_path = Path(__file__).resolve().parent\n\n    sources = [proj_path / \"simple_counter.sv\"]\n\n    sim = os.getenv(\"SIM\", \"icarus\")\n    runner = get_runner(sim)\n\n    runner.build(\n        sources=sources,\n        hdl_toplevel=\"simple_counter\",\n        waves=True,\n    )\n\n    runner.test(\n        hdl_toplevel=\"simple_counter\",\n        test_module=\"simple_counter_testcases,\",\n        waves=True,\n    )\n\n\nif __name__ == \"__main__\":\n    test_simple_counter()\n"
  },
  {
    "path": "examples/matrix_multiplier/hdl/matrix_multiplier.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\n// Matrix Multiplier DUT\n`timescale 1ns/1ps\n\n`ifdef VERILATOR  // make parameter readable from VPI\n  `define VL_RD /*verilator public_flat_rd*/\n`else  // `ifdef VERILATOR\n  `define VL_RD\n`endif  // `ifdef VERILATOR\n\nmodule matrix_multiplier #(\n  parameter int DATA_WIDTH `VL_RD = 8,\n  parameter int A_ROWS `VL_RD = 8,\n  parameter int B_COLUMNS `VL_RD = 5,\n  parameter int A_COLUMNS_B_ROWS `VL_RD = 4,\n  parameter int C_DATA_WIDTH = (2 * DATA_WIDTH) + $clog2(A_COLUMNS_B_ROWS)\n) (\n  input                           clk_i,\n  input                           reset_i,\n  input                           valid_i,\n  output logic                    valid_o,\n  input        [DATA_WIDTH-1:0]   a_i[0:A_ROWS*A_COLUMNS_B_ROWS-1],\n  input        [DATA_WIDTH-1:0]   b_i[0:A_COLUMNS_B_ROWS*B_COLUMNS-1],\n  output logic [C_DATA_WIDTH-1:0] c_o[0:A_ROWS*B_COLUMNS-1]\n);\n\n  logic [C_DATA_WIDTH-1:0] c_calc[A_ROWS * B_COLUMNS];\n\n  always @(*) begin : multiply\n    logic [C_DATA_WIDTH-1:0] c_element;\n    for (int i = 0; i < A_ROWS; i = i + 1) begin : C_ROWS\n      for (int j = 0; j < B_COLUMNS; j = j + 1) begin : C_COLUMNS\n        c_element = 0;\n        for (int k = 0; k < A_COLUMNS_B_ROWS; k = k + 1) begin : DOT_PRODUCT\n          c_element = c_element + (a_i[(i * A_COLUMNS_B_ROWS) + k] * b_i[(k * B_COLUMNS) + j]);\n        end\n        c_calc[(i * B_COLUMNS) + j] = c_element;\n      end\n    end\n  end\n\n  always @(posedge clk_i) begin : proc_reg\n    if (reset_i) begin\n      valid_o <= 1'b0;\n\n      for (int idx = 0; idx < (A_ROWS * B_COLUMNS); idx++) begin\n        c_o[idx] <= '0;\n      end\n    end else begin\n      valid_o <= valid_i;\n\n      for (int idx = 0; idx < (A_ROWS * B_COLUMNS); idx++) begin\n        c_o[idx] <= c_calc[idx];\n      end\n    end\n  end\n\nendmodule\n"
  },
  {
    "path": "examples/matrix_multiplier/hdl/matrix_multiplier.vhd",
    "content": "-- This file is public domain, it can be freely copied without restrictions.\n-- SPDX-License-Identifier: CC0-1.0\n\n-- Matrix Multiplier DUT\nlibrary ieee ;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\nuse work.matrix_multiplier_pkg.all;\n\nentity matrix_multiplier is\n  generic (\n    DATA_WIDTH : positive := 8;\n    A_ROWS : positive := 8;\n    B_COLUMNS : positive := 5;\n    A_COLUMNS_B_ROWS : positive := 4\n  );\n  port (\n    clk_i   : in    std_logic;\n    reset_i : in    std_logic;\n    valid_i : in    std_logic;\n    valid_o : out   std_logic;\n    a_i     : in    flat_matrix_type(0 to (A_ROWS * A_COLUMNS_B_ROWS) - 1)(DATA_WIDTH - 1 downto 0);\n    b_i     : in    flat_matrix_type(0 to (A_COLUMNS_B_ROWS * B_COLUMNS) - 1)(DATA_WIDTH - 1 downto 0);\n    c_o     : out   flat_matrix_type(0 to (A_ROWS * B_COLUMNS) - 1)((2 * DATA_WIDTH) + clog2(A_COLUMNS_B_ROWS) - 1 downto 0)\n  );\nend entity matrix_multiplier;\n\narchitecture rtl of matrix_multiplier is\n\n  signal c_calc : flat_matrix_type(c_o'RANGE)(c_o(0)'RANGE);\n\nbegin\n\n  multiply : process (all) is\n\n    variable c_var : flat_matrix_type(c_o'RANGE)(c_o(0)'RANGE);\n\n  begin\n\n    c_var := (others => (others => '0'));\n\n    C_ROWS : for i in 0 to A_ROWS-1 loop\n      C_COLUMNS : for j in 0 to B_COLUMNS-1 loop\n        DOT_PRODUCT : for k in 0 to A_COLUMNS_B_ROWS-1 loop\n          c_var((i * B_COLUMNS) + j) := c_var((i * B_COLUMNS) + j) + (a_i((i * A_COLUMNS_B_ROWS) + k) * b_i((k * B_COLUMNS) + j));\n        end loop;\n      end loop;\n    end loop;\n\n    c_calc <= c_var;\n\n  end process multiply;\n\n  proc_reg : process (clk_i) is\n  begin\n\n    if (rising_edge(clk_i)) then\n      if (reset_i = '1') then\n        valid_o <= '0';\n        c_o <= (others => (others => '0'));\n      else\n        valid_o <= valid_i;\n\n        if (valid_i = '1') then\n          c_o <= c_calc;\n        else\n          c_o <= (others => (others => 'X'));\n        end if;\n      end if;\n    end if;\n\n  end process proc_reg;\n\nend architecture rtl;\n"
  },
  {
    "path": "examples/matrix_multiplier/hdl/matrix_multiplier_pkg.vhd",
    "content": "-- This file is public domain, it can be freely copied without restrictions.\n-- SPDX-License-Identifier: CC0-1.0\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\nuse ieee.math_real.all;\n\npackage matrix_multiplier_pkg is\n\n    -- VHDL-2008 required for unconstrained array types\n    type flat_matrix_type is array (integer range <>) of unsigned;\n\n    function clog2(n : positive) return natural;\n\nend package;\n\npackage body matrix_multiplier_pkg is\n\n    function clog2(n : positive) return natural is\n    begin\n        return integer(ceil(log2(real(n))));\n    end function;\n\nend package body;\n"
  },
  {
    "path": "examples/matrix_multiplier/tests/Makefile",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\n\nTOPLEVEL_LANG ?= verilog\nSIM ?= icarus\n\nPWD=$(shell pwd)\n\n# Matrix parameters\nDATA_WIDTH ?= 32\nA_ROWS ?= 10\nB_COLUMNS ?= 4\nA_COLUMNS_B_ROWS ?= 6\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    VERILOG_SOURCES = $(PWD)/../hdl/matrix_multiplier.sv\n\n    # Set module parameters\n    ifeq ($(SIM),icarus)\n        COMPILE_ARGS += -Pmatrix_multiplier.DATA_WIDTH=$(DATA_WIDTH) -Pmatrix_multiplier.A_ROWS=$(A_ROWS) -Pmatrix_multiplier.B_COLUMNS=$(B_COLUMNS) -Pmatrix_multiplier.A_COLUMNS_B_ROWS=$(A_COLUMNS_B_ROWS)\n    else ifneq ($(filter $(SIM),questa modelsim riviera activehdl nvc),)\n        SIM_ARGS += -gDATA_WIDTH=$(DATA_WIDTH) -gA_ROWS=$(A_ROWS) -gB_COLUMNS=$(B_COLUMNS) -gA_COLUMNS_B_ROWS=$(A_COLUMNS_B_ROWS)\n    else ifeq ($(SIM),vcs)\n        COMPILE_ARGS += -pvalue+matrix_multiplier/DATA_WIDTH=$(DATA_WIDTH) -pvalue+matrix_multiplier/A_ROWS=$(A_ROWS) -pvalue+matrix_multiplier/B_COLUMNS=$(B_COLUMNS) -pvalue+matrix_multiplier/A_COLUMNS_B_ROWS=$(A_COLUMNS_B_ROWS)\n    else ifeq ($(SIM),verilator)\n        COMPILE_ARGS += -GDATA_WIDTH=$(DATA_WIDTH) -GA_ROWS=$(A_ROWS) -GB_COLUMNS=$(B_COLUMNS) -GA_COLUMNS_B_ROWS=$(A_COLUMNS_B_ROWS)\n    else ifneq ($(filter $(SIM),ius xcelium),)\n        EXTRA_ARGS += -defparam \"matrix_multiplier.DATA_WIDTH=$(DATA_WIDTH)\" -defparam \"matrix_multiplier.A_ROWS=$(A_ROWS)\" -defparam \"matrix_multiplier.B_COLUMNS=$(B_COLUMNS)\" -defparam \"matrix_multiplier.A_COLUMNS_B_ROWS=$(A_COLUMNS_B_ROWS)\"\n    endif\n\n    ifneq ($(filter $(SIM),riviera activehdl),)\n        COMPILE_ARGS += -sv2k12\n    endif\n\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    VHDL_SOURCES = $(PWD)/../hdl/matrix_multiplier_pkg.vhd $(PWD)/../hdl/matrix_multiplier.vhd\n\n    ifneq ($(filter $(SIM),ghdl questa modelsim riviera activehdl nvc),)\n        # ghdl, questa, and aldec all use SIM_ARGS with '-g' for setting generics\n        SIM_ARGS += -gDATA_WIDTH=$(DATA_WIDTH) -gA_ROWS=$(A_ROWS) -gB_COLUMNS=$(B_COLUMNS) -gA_COLUMNS_B_ROWS=$(A_COLUMNS_B_ROWS)\n    else ifneq ($(filter $(SIM),ius xcelium),)\n        SIM_ARGS += -generic \"matrix_multiplier:DATA_WIDTH=>$(DATA_WIDTH)\" -generic \"matrix_multiplier:A_ROWS=>$(A_ROWS)\" -generic \"matrix_multiplier:B_COLUMNS=>$(B_COLUMNS)\" -generic \"matrix_multiplier:A_COLUMNS_B_ROWS=>$(A_COLUMNS_B_ROWS)\"\n    endif\n\n    ifeq ($(SIM),ghdl)\n        EXTRA_ARGS += --std=08\n        SIM_ARGS += --wave=wave.ghw\n    else ifeq ($(SIM),nvc)\n        EXTRA_ARGS += --std=08\n        SIM_ARGS += --wave=wave.fst\n    else ifneq ($(filter $(SIM),ius xcelium),)\n        COMPILE_ARGS += -v200x\n    else ifneq ($(filter $(SIM),questa modelsim riviera activehdl),)\n        COMPILE_ARGS += -2008\n    endif\nelse\n    $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\nCOCOTB_TOPLEVEL     := matrix_multiplier\nCOCOTB_TEST_MODULES := matrix_multiplier_tests\n\nifeq ($(SIM),ghdl)\n\nall:\n\t@echo \"Skipping since GHDL doesn't support constants effectively\"\n\nclean::\n\nelse\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n\n# Profiling\n\nDOT_BINARY ?= dot\n\ntest_profile.pstat: sim\n\ncallgraph.svg: test_profile.pstat\n\t$(shell cocotb-config --python-bin) -m gprof2dot -f pstats ./$< | $(DOT_BINARY) -Tsvg -o $@\n\n.PHONY: profile\nprofile:\n\tCOCOTB_ENABLE_PROFILING=1 $(MAKE) callgraph.svg\n"
  },
  {
    "path": "examples/matrix_multiplier/tests/matrix_multiplier_tests.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\nimport logging\nimport math\nimport os\nimport random\nfrom collections import deque\nfrom collections.abc import Sequence\nfrom typing import (\n    Any,\n    Callable,\n    Generic,\n    Protocol,\n    TypeVar,\n)\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.handle import LogicObject, ValueObjectBase\nfrom cocotb.task import Task\nfrom cocotb.triggers import Event, FallingEdge, ReadOnly, RisingEdge, Trigger\nfrom cocotb.types import Array, LogicArray, Range\n\nT = TypeVar(\"T\")\n\n\nclass Mailbox(Generic[T]):\n    \"\"\"A deque with signals for use in testbench components.\"\"\"\n\n    def __init__(self) -> None:\n        self._queue: deque[T] = deque()\n        self._event = Event()\n\n    def put(self, item: T) -> None:\n        \"\"\"Put an item in the mailbox.\"\"\"\n        self._queue.append(item)\n        self._event.set()\n\n    def get(self) -> T:\n        \"\"\"Get an item from the mailbox.\"\"\"\n        if self._queue:\n            return self._queue.popleft()\n        else:\n            raise RuntimeError(\"Mailbox is empty\")\n\n    def wait(self) -> Trigger:\n        \"\"\"Wait for an item to be put in the mailbox.\"\"\"\n        if not self._queue:\n            self._event.clear()\n        return self._event.wait()\n\n    def empty(self) -> bool:\n        \"\"\"Check if the mailbox is empty.\"\"\"\n        return not self._queue\n\n\nclass DataValidMonitor(Generic[T]):\n    \"\"\"Reusable Monitor of data/valid streaming interface.\n\n    Assumes *rst*, *valid*, and *datas* registered signals on rising edge of *clk*.\n    Glitches will cause incorrect values to be recorded.\n    Assumes *valid* is active at `1`, and *rst* is active at `!0`.\n    Assumes *valid* and *rst* cannot have weak values.\n\n    Args:\n        clk: clock signal\n        rst: reset signal\n        valid: control signal noting a transaction occurred\n        datas: named handles to be sampled when transaction occurs\n    \"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        clk: LogicObject,\n        rst: LogicObject,\n        datas: dict[str, ValueObjectBase[T, Any]],\n        valid: LogicObject,\n    ) -> None:\n        self.name = name\n        self.log = logging.getLogger(name)\n        self._clk = clk\n        self._rst = rst\n        self._datas = datas\n        self._valid = valid\n        self._callbacks: list[Callable[[dict[str, T]], Any]] = []\n        self._task: Task[None] | None = None\n\n    def add_callback(self, callback: Callable[[dict], Any]) -> None:\n        \"\"\"Add callback to be called with transaction data when a transaction is observed.\"\"\"\n        self._callbacks.append(callback)\n\n    def start(self) -> None:\n        \"\"\"Start monitor.\"\"\"\n        if self._task is not None:\n            raise RuntimeError(\"Monitor already started\")\n        self._task = cocotb.start_soon(self._run())\n\n    def stop(self) -> None:\n        \"\"\"Stop monitor.\"\"\"\n        if self._task is None:\n            raise RuntimeError(\"Monitor never started\")\n        self._task.cancel()\n        self._task = None\n\n    async def _run(self) -> None:\n        while True:\n            await RisingEdge(self._clk)\n            await ReadOnly()\n            if self._rst.value != \"0\":\n                self.log.debug(\"Waiting for reset to finish...\")\n                await FallingEdge(self._rst)\n                self.log.debug(\"Reset finished\")\n                continue\n            elif self._valid.value != \"1\":\n                await RisingEdge(self._valid)\n                await ReadOnly()\n                # Fallthrough and sample data since we assume valid is registered.\n\n            # send sample to all registered callbacks\n            transaction = self._sample()\n            self.log.debug(\"Observed: %r\", transaction)\n            for cb in self._callbacks:\n                cb(transaction)\n\n    def _sample(self) -> dict[str, T]:\n        \"\"\"Samples the data signals and builds a transaction object.\"\"\"\n        return {name: handle.value for name, handle in self._datas.items()}\n\n\nclass DataValidDriver(Generic[T]):\n    \"\"\"Reusable Driver of data/valid streaming interface.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        clk: LogicObject,\n        rst: LogicObject,\n        datas: dict[str, ValueObjectBase[Any, T]],\n        valid: LogicObject,\n        initial_values: dict[str, T] | None = None,\n    ) -> None:\n        self.name = name\n        self.log = logging.getLogger(name)\n        self._clk = clk\n        self._rst = rst\n        self._datas = datas\n        self._valid = valid\n        self._initial_values = initial_values\n        self._task: Task[None] | None = None\n        self._mb = Mailbox[tuple[dict[str, T], Event]]()\n\n    def send(self, data: dict[str, T]) -> Trigger:\n        \"\"\"Send data to driver.\n\n        Args:\n            data: Data to be applied to the interface.\n\n        Returns\n            A Trigger which will fire after the data is applied to the interface.\n        \"\"\"\n        e = Event()\n        self.log.debug(\"Queued: %r\", data)\n        self._mb.put((data, e))\n        return e.wait()\n\n    def start(self) -> None:\n        \"\"\"Start driver.\"\"\"\n        if self._task is not None:\n            raise RuntimeError(\"Driver already started\")\n        self._task = cocotb.start_soon(self._run())\n\n    def stop(self) -> None:\n        \"\"\"Stop driver.\"\"\"\n        if self._task is None:\n            raise RuntimeError(\"Driver never started\")\n        self._task.cancel()\n        self._task = None\n\n    async def _run(self) -> None:\n        while True:\n            await RisingEdge(self._clk)\n            self._valid.value = 0\n\n            if self._rst.value != \"0\":\n                self.log.debug(\"Resetting...\")\n                # drive reset values\n                if self._initial_values is not None:\n                    for name, handle in self._datas.items():\n                        if name in self._initial_values:\n                            handle.value = self._initial_values[name]\n                # wait for reset to finish\n                await FallingEdge(self._rst)\n                self.log.debug(\"Finished reset\")\n                continue\n\n            elif self._mb.empty():\n                self.log.debug(\"Waiting for input\")\n                await self._mb.wait()\n                continue\n\n            self._valid.value = 1\n            data, e = self._mb.get()\n            self._apply(data)\n            self.log.debug(\"Applied: %r\", data)\n            e.set()\n\n    def _apply(self, data: dict[str, T]) -> None:\n        \"\"\"Apply data to the interface.\"\"\"\n        for name, handle in self._datas.items():\n            handle.value = data[name]\n\n\nclass MatrixMultiplierModel:\n    \"\"\"Transaction-level model of a matrix multiplier.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        A_ROWS: int,\n        A_COLUMNS_B_ROWS: int,\n        B_COLUMNS: int,\n        DATA_WIDTH: int,\n    ) -> None:\n        self.name = name\n        self.log = logging.getLogger(name)\n        self.A_ROWS = A_ROWS\n        self.A_COLUMNS_B_ROWS = A_COLUMNS_B_ROWS\n        self.B_COLUMNS = B_COLUMNS\n        self.DATA_WIDTH = DATA_WIDTH\n\n        self._OUTPUT_RANGE = Range(\n            (DATA_WIDTH * 2) + math.ceil(math.log2(A_COLUMNS_B_ROWS)) - 1,\n            \"downto\",\n            0,\n        )\n\n        self._output_callbacks: list[Callable[[list[LogicArray]], None]] = []\n\n    def add_output_callback(self, callback: Callable[[list[LogicArray]], None]) -> None:\n        \"\"\"Add callback to be called with output data when a transaction is produced.\"\"\"\n        self._output_callbacks.append(callback)\n\n    def send_input(\n        self, a_matrix: Array[LogicArray], b_matrix: Array[LogicArray]\n    ) -> None:\n        \"\"\"Send data to the output and evaluate the model.\"\"\"\n        self.log.debug(\"Received input:\\n  A: %r\\n  B: %r\", a_matrix, b_matrix)\n\n        result = [\n            LogicArray(\n                sum(\n                    a_matrix[(i * self.A_COLUMNS_B_ROWS) + n].to_unsigned()\n                    * b_matrix[(n * self.B_COLUMNS) + j].to_unsigned()\n                    for n in range(self.A_COLUMNS_B_ROWS)\n                ),\n                self._OUTPUT_RANGE,\n            )\n            for i in range(self.A_ROWS)\n            for j in range(self.B_COLUMNS)\n        ]\n\n        self.log.debug(\"Sending output: %r\", result)\n        for cb in self._output_callbacks:\n            cb(result)\n\n\nT_contra = TypeVar(\"T_contra\", contravariant=True)\n\n\nclass CompareFunc(Protocol[T_contra]):\n    \"\"\"Type for a function that compares two values of the same type.\n\n    *expected* and *actual* are passed as keyword arguments.\n    \"\"\"\n\n    def __call__(self, *, expected: T_contra, actual: T_contra) -> bool:\n        pass\n\n\nclass InOrderChecker(Generic[T]):\n    \"\"\"Checker of expected vs actual results.\n\n    Checks results in order of arrival.\n    Expects *expected* data to arrive before *actual* data.\n    If *actual* data arrives before *expected* data, an error is recorded.\n    \"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        fail_on_error: bool = True,\n        cmp: CompareFunc = lambda expected, actual: expected == actual,\n    ) -> None:\n        self.name = name\n        self.log = logging.getLogger(name)\n        self._fail_on_error = fail_on_error\n        self._cmp = cmp\n        self._expected_queue: deque[T] = deque()\n        self.errors: int = 0\n\n    def addExpected(self, expected: T) -> None:\n        \"\"\"Add expected data to the checker.\"\"\"\n        self.log.debug(\"Added expected: %r\", expected)\n        self._expected_queue.append(expected)\n\n    def addActual(self, actual: T) -> None:\n        \"\"\"Add actual data to the checker.\"\"\"\n        self.log.debug(\"Added actual: %r\", actual)\n        if not self._expected_queue:\n            raise RuntimeError(\"Unexpected actual data received\")\n        expected = self._expected_queue.popleft()\n        if self._fail_on_error:\n            assert self._cmp(expected=expected, actual=actual)\n        elif not self._cmp(expected=expected, actual=actual):\n            self.log.error(\"MISMATCH!\\n  Expected: %r\\n  Actual: %r\", expected, actual)\n            self.errors += 1\n        else:\n            self.log.debug(\"Matched:\\n  Expected: %r\\n  Actual: %r\", expected, actual)\n\n\nclass MatrixMultiplierTestbench:\n    \"\"\"\n    Reusable checker of a matrix_multiplier instance\n\n    Args:\n        matrix_multiplier_entity: handle to an instance of matrix_multiplier\n    \"\"\"\n\n    def __init__(self, dut: Any, name: str | None = None) -> None:\n        self.dut = dut\n        self.name = name if name is not None else type(self).__qualname__\n        self.log = logging.getLogger(self.name)\n        self.log.setLevel(logging.INFO)\n\n        self.A_ROWS = int(self.dut.A_ROWS.value)\n        self.A_COLUMNS_B_ROWS = int(self.dut.A_COLUMNS_B_ROWS.value)\n        self.B_COLUMNS = int(self.dut.B_COLUMNS.value)\n        self.DATA_WIDTH = int(self.dut.DATA_WIDTH.value)\n\n        self.clk_drv = Clock(self.dut.clk_i, 10, unit=\"ns\")\n\n        self.input_drv = DataValidDriver(\n            name=f\"{self.name}.input_drv\",\n            clk=self.dut.clk_i,\n            rst=self.dut.reset_i,\n            valid=self.dut.valid_i,\n            datas={\"A\": self.dut.a_i, \"B\": self.dut.b_i},\n            initial_values={\n                \"A\": self.create_a_matrix(lambda: 0),\n                \"B\": self.create_b_matrix(lambda: 0),\n            },\n        )\n\n        self.input_mon = DataValidMonitor(\n            name=f\"{self.name}.input_mon\",\n            clk=self.dut.clk_i,\n            rst=self.dut.reset_i,\n            valid=self.dut.valid_i,\n            datas={\"A\": self.dut.a_i, \"B\": self.dut.b_i},\n        )\n\n        self.output_mon = DataValidMonitor(\n            name=f\"{self.name}.output_mon\",\n            clk=self.dut.clk_i,\n            rst=self.dut.reset_i,\n            valid=self.dut.valid_o,\n            datas={\"C\": self.dut.c_o},\n        )\n\n        self.model = MatrixMultiplierModel(\n            name=f\"{self.name}.model\",\n            A_ROWS=self.A_ROWS,\n            A_COLUMNS_B_ROWS=self.A_COLUMNS_B_ROWS,\n            B_COLUMNS=self.B_COLUMNS,\n            DATA_WIDTH=self.DATA_WIDTH,\n        )\n\n        self.checker = InOrderChecker[Sequence[LogicArray]](\n            name=f\"{self.name}.checker\",\n        )\n\n        # connect monitors to model and checker\n        self.input_mon.add_callback(\n            lambda datas: self.model.send_input(\n                a_matrix=datas[\"A\"], b_matrix=datas[\"B\"]\n            )\n        )\n        self.model.add_output_callback(self.checker.addExpected)\n        self.output_mon.add_callback(lambda datas: self.checker.addActual(datas[\"C\"]))\n\n    def create_a_matrix(self, func: Callable[[], int]) -> list[LogicArray]:\n        \"\"\"Create a matrix of the size of input A.\n\n        Takes a function to generate values.\n        Literal values can be used by passing `lambda: {value}`.\n        \"\"\"\n        return [\n            LogicArray(func(), self.DATA_WIDTH)\n            for _ in range(self.A_ROWS * self.A_COLUMNS_B_ROWS)\n        ]\n\n    def create_b_matrix(self, func: Callable[[], int]) -> list[LogicArray]:\n        \"\"\"Create a matrix of the size of input B.\n\n        Takes a function to generate values.\n        Literal values can be used by passing `lambda: {value}`.\n        \"\"\"\n        return [\n            LogicArray(func(), self.DATA_WIDTH)\n            for _ in range(self.A_COLUMNS_B_ROWS * self.B_COLUMNS)\n        ]\n\n    def start(self) -> None:\n        \"\"\"Starts sub-components.\"\"\"\n        self.clk_drv.start()\n        self.input_drv.start()\n        self.input_mon.start()\n        self.output_mon.start()\n\n    def stop(self) -> None:\n        \"\"\"Stops sub-components.\"\"\"\n        self.clk_drv.stop()\n        self.input_drv.stop()\n        self.input_mon.stop()\n        self.output_mon.stop()\n\n    async def reset(self, cycles: int = 3) -> None:\n        \"\"\"Reset the design under test.\"\"\"\n        self.dut.reset_i.value = 1\n        for _ in range(cycles):\n            await RisingEdge(self.dut.clk_i)\n        self.dut.reset_i.value = 0\n\n\n@cocotb.test()\nasync def test_random(dut: Any) -> None:\n    \"\"\"Test matrix multiplier with random data.\"\"\"\n\n    # Create the testbench, start it and go through reset\n    tb = MatrixMultiplierTestbench(dut)\n    tb.start()\n    await tb.reset()\n\n    # Run design with random data and gaps\n    NUM_SAMPLES = int(os.environ.get(\"NUM_SAMPLES\", \"3000\"))\n    for i in range(NUM_SAMPLES):\n        # Send random data to the driver\n        tb.input_drv.send(\n            {\n                \"A\": tb.create_a_matrix(lambda: random.getrandbits(tb.DATA_WIDTH)),\n                \"B\": tb.create_b_matrix(lambda: random.getrandbits(tb.DATA_WIDTH)),\n            }\n        )\n\n        # Wait random clock cycles before sending another\n        await tb.clk_drv.cycles(random.randint(1, 5))\n\n        # Log progress\n        if i % 100 == 0:\n            tb.log.info(\"%d / %d\", i, NUM_SAMPLES)\n\n    # Wait for all transactions to be processed and stop the testbench\n    await tb.clk_drv.cycles(5)\n    tb.stop()\n\n    # Check for errors if the checkers weren't set to fail on error\n    assert tb.checker.errors == 0\n"
  },
  {
    "path": "examples/matrix_multiplier/tests/test_matrix_multiplier.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\nimport os\nimport sys\nfrom pathlib import Path\n\nimport pytest\n\nfrom cocotb_tools.runner import get_runner\n\n\n@pytest.mark.skipif(\n    os.getenv(\"SIM\", \"icarus\") == \"ghdl\",\n    reason=\"Skipping since GHDL doesn't support constants effectively\",\n)\ndef test_matrix_multiplier_runner():\n    \"\"\"Simulate the matrix_multiplier example using the Python runner.\n\n    This file can be run directly or via pytest discovery.\n    \"\"\"\n    hdl_toplevel_lang = os.getenv(\"TOPLEVEL_LANG\", \"verilog\")\n    sim = os.getenv(\"SIM\", \"icarus\")\n\n    proj_path = Path(__file__).resolve().parent.parent\n\n    build_args = []\n\n    if hdl_toplevel_lang == \"verilog\":\n        sources = [proj_path / \"hdl\" / \"matrix_multiplier.sv\"]\n\n        if sim in [\"riviera\", \"activehdl\"]:\n            build_args = [\"-sv2k12\"]\n\n    elif hdl_toplevel_lang == \"vhdl\":\n        sources = [\n            proj_path / \"hdl\" / \"matrix_multiplier_pkg.vhd\",\n            proj_path / \"hdl\" / \"matrix_multiplier.vhd\",\n        ]\n\n        if sim in [\"questa\", \"modelsim\", \"riviera\", \"activehdl\"]:\n            build_args = [\"-2008\"]\n        elif sim == \"nvc\":\n            build_args = [\"--std=08\"]\n    else:\n        raise ValueError(\n            f\"A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG={hdl_toplevel_lang}\"\n        )\n\n    extra_args = []\n    if sim == \"ghdl\":\n        extra_args = [\"--std=08\"]\n    elif sim == \"xcelium\":\n        extra_args = [\"-v200x\"]\n\n    parameters = {\n        \"DATA_WIDTH\": \"32\",\n        \"A_ROWS\": 10,\n        \"B_COLUMNS\": 4,\n        \"A_COLUMNS_B_ROWS\": 6,\n    }\n\n    # equivalent to setting the PYTHONPATH environment variable\n    sys.path.append(str(proj_path / \"tests\"))\n\n    runner = get_runner(sim)\n\n    runner.build(\n        hdl_toplevel=\"matrix_multiplier\",\n        sources=sources,\n        build_args=build_args + extra_args,\n        parameters=parameters,\n        always=True,\n    )\n\n    runner.test(\n        hdl_toplevel=\"matrix_multiplier\",\n        hdl_toplevel_lang=hdl_toplevel_lang,\n        test_module=\"matrix_multiplier_tests\",\n        test_args=extra_args,\n    )\n\n\nif __name__ == \"__main__\":\n    test_matrix_multiplier_runner()\n"
  },
  {
    "path": "examples/mixed_language/hdl/endian_swapper.sv",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n/*\n\nEndian swapping module.\n\nSimple example with Avalon streaming interfaces and a CSR bus\n\nAvalon-ST has readyLatency of 0\nAvalon-MM has fixed readLatency of 1\n\nExposes 2 32-bit registers via the Avalon-MM interface\n\n   Address 0:  bit     0  [R/W] byteswap enable\n               bits 31-1: [N/A] reserved\n   Address 1:  bits 31-0: [RO]  packet count\n\n*/\n\n`timescale 1ns/1ps\n\nmodule endian_swapper_sv #(\n    parameter                              DATA_BYTES = 8\n) (\n    input                                  clk,\n    input                                  reset_n,\n\n    input [DATA_BYTES*8-1:0]               stream_in_data,\n    input [$clog2(DATA_BYTES)-1:0]         stream_in_empty,\n    input                                  stream_in_valid,\n    input                                  stream_in_startofpacket,\n    input                                  stream_in_endofpacket,\n    output reg                             stream_in_ready,\n\n    output reg [DATA_BYTES*8-1:0]          stream_out_data,\n    output reg [$clog2(DATA_BYTES)-1:0]    stream_out_empty,\n    output reg                             stream_out_valid,\n    output reg                             stream_out_startofpacket,\n    output reg                             stream_out_endofpacket,\n    input                                  stream_out_ready,\n\n    input  [1:0]                           csr_address,\n    output reg [31:0]                      csr_readdata,\n    output reg                             csr_readdatavalid,\n    input                                  csr_read,\n    input                                  csr_write,\n    output reg                             csr_waitrequest,\n    input [31:0]                           csr_writedata\n);\n\n\n\nfunction [DATA_BYTES*8-1:0] byteswap(input [DATA_BYTES*8-1:0] data);\n/*\n    // FIXME Icarus doesn't seem to like this....\n    reg [$clog2(DATA_BYTES)-1:0] i;\n\n    for (i=0; i<DATA_BYTES; i=i+1)\n        byteswap[i*8+7 -:8] = data[(DATA_BYTES-i)*8-1 -:8];\n*/\n\n    // Hardwire for now\n    byteswap = { data[7:0],\n                 data[15:8],\n                 data[23:16],\n                 data[31:24],\n                 data[39:32],\n                 data[47:40],\n                 data[55:48],\n                 data[63:56]};\nendfunction\n\n\nreg flush_pipe;\nreg in_packet;\nreg byteswapping;\nreg [31:0] packet_count;\n\n\nalways @(posedge clk or negedge reset_n) begin\n    if (!reset_n) begin\n        flush_pipe       <= 1'b0;\n        in_packet        <= 1'b0;\n        packet_count     <= 32'd0;\n\n        stream_out_startofpacket <= 1'b1;\n        stream_out_endofpacket   <= 1'b1;\n    end else begin\n\n        if (flush_pipe & stream_out_ready)\n            flush_pipe <= stream_in_endofpacket & stream_in_valid & stream_out_ready;\n        else if (!flush_pipe)\n            flush_pipe <= stream_in_endofpacket & stream_in_valid & stream_out_ready;\n\n        if (stream_out_ready & stream_in_valid) begin\n            stream_out_empty         <= stream_in_empty;\n            stream_out_startofpacket <= stream_in_startofpacket;\n            stream_out_endofpacket   <= stream_in_endofpacket;\n\n            if (!byteswapping)\n                stream_out_data      <= stream_in_data;\n            else\n                stream_out_data      <= byteswap(stream_in_data);\n\n            if (stream_in_startofpacket && stream_in_valid) begin\n                packet_count <= packet_count + 1;\n                in_packet    <= 1'b1;\n            end\n\n            if (stream_in_endofpacket && stream_in_valid)\n                in_packet    <= 1'b0;\n\n        end\n    end\nend\n\nalways @(*)\n    stream_out_valid = (stream_in_valid & ~stream_out_endofpacket) | flush_pipe;\n\n\n// Hold off CSR accesses during packet transfers to prevent changing of\n// endian configuration mid-packet\nalways @(*)\n    csr_waitrequest = !reset_n || in_packet || (stream_in_startofpacket & stream_in_valid) || flush_pipe;\n\n\n// Workaround Icarus bug where a simple assign doesn't work\nalways @(stream_out_ready)\n    stream_in_ready = stream_out_ready;\n\n\nalways @(posedge clk or negedge reset_n) begin\n    if (!reset_n) begin\n        byteswapping      <= 1'b0;\n        csr_readdatavalid <= 1'b0;\n    end else begin\n        csr_readdatavalid <= 1'b0;\n        if (csr_read) begin\n            csr_readdatavalid <= !csr_waitrequest;\n            case (csr_address)\n                0:    csr_readdata <= {31'b0, byteswapping};\n                1:    csr_readdata <= packet_count;\n            endcase\n        end else if (csr_write & !csr_waitrequest) begin\n            case (csr_address)\n                0:    byteswapping <= csr_writedata[0];\n            endcase\n        end\n    end\nend\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_language/hdl/endian_swapper.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Copyright (c) 2014 Potential Ventures Ltd\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n--\n--\n-- Endian swapping module.\n--\n-- Simple example with Avalon streaming interfaces and a CSR bus\n--\n-- Avalon-ST has readyLatency of 0\n-- Avalon-MM has fixed readLatency of 1\n--\n-- Exposes 2 32-bit registers via the Avalon-MM interface\n--\n--    Address 0:  bit     0  [R/W] byteswap enable\n--                bits 31-1: [N/A] reserved\n--    Address 1:  bits 31-0: [RO]  packet count\n--\nlibrary ieee;\n\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nentity endian_swapper_vhdl is\n    generic (\n        DATA_BYTES              : integer := 8);\n    port (\n        clk                     : in    std_ulogic;\n        reset_n                 : in    std_ulogic;\n\n        stream_in_data          : in    std_ulogic_vector(DATA_BYTES*8-1 downto 0);\n        stream_in_empty         : in    std_ulogic_vector(2 downto 0);\n        stream_in_valid         : in    std_ulogic;\n        stream_in_startofpacket : in    std_ulogic;\n        stream_in_endofpacket   : in    std_ulogic;\n        stream_in_ready         : out   std_ulogic;\n\n        stream_out_data         : out   std_ulogic_vector(DATA_BYTES*8-1 downto 0);\n        stream_out_empty        : out   std_ulogic_vector(2 downto 0);\n        stream_out_valid        : out   std_ulogic;\n        stream_out_startofpacket: out   std_ulogic;\n        stream_out_endofpacket  : out   std_ulogic;\n        stream_out_ready        : in    std_ulogic;\n\n        csr_address             : in    std_ulogic_vector(1 downto 0);\n        csr_readdata            : out   std_ulogic_vector(31 downto 0);\n        csr_readdatavalid       : out   std_ulogic;\n        csr_read                : in    std_ulogic;\n        csr_write               : in    std_ulogic;\n        csr_waitrequest         : out   std_ulogic;\n        csr_writedata           : in    std_ulogic_vector(31 downto 0)\n    );\nend;\n\narchitecture impl of endian_swapper_vhdl is\n\n\nfunction byteswap(data : in std_ulogic_vector(63 downto 0)) return std_ulogic_vector is begin\n    return  data(7  downto  0) &\n            data(15 downto  8) &\n            data(23 downto 16) &\n            data(31 downto 24) &\n            data(39 downto 32) &\n            data(47 downto 40) &\n            data(55 downto 48) &\n            data(63 downto 56);\nend;\n\nsignal csr_waitrequest_int      : std_ulogic;\nsignal stream_out_endofpacket_int: std_ulogic;\nsignal flush_pipe       :       std_ulogic;\nsignal in_packet        :       std_ulogic;\nsignal byteswapping     :       std_ulogic;\nsignal packet_count     :       unsigned(31 downto 0);\n\nbegin\n\n\nprocess (clk, reset_n) begin\n    if (reset_n = '0') then\n        flush_pipe      <= '0';\n        in_packet       <= '0';\n        packet_count    <= to_unsigned(0, 32);\n    elsif rising_edge(clk) then\n\n\n        if (flush_pipe = '1' and stream_out_ready = '1') then\n\n            flush_pipe <= stream_in_endofpacket and stream_in_valid and stream_out_ready;\n\n        elsif (flush_pipe = '0') then\n            flush_pipe <= stream_in_endofpacket and stream_in_valid and stream_out_ready;\n        end if;\n\n        if (stream_out_ready = '1' and stream_in_valid = '1') then\n            stream_out_empty            <= stream_in_empty;\n            stream_out_startofpacket    <= stream_in_startofpacket;\n            stream_out_endofpacket_int  <= stream_in_endofpacket;\n\n            if (byteswapping = '0') then\n                stream_out_data      <= stream_in_data;\n            else\n                stream_out_data      <= byteswap(stream_in_data);\n            end if;\n\n            if (stream_in_startofpacket = '1' and stream_in_valid = '1') then\n                packet_count <= packet_count + 1;\n                in_packet    <= '1';\n            end if;\n\n            if (stream_in_endofpacket = '1' and stream_in_valid = '1') then\n                in_packet    <= '0';\n            end if;\n        end if;\n    end if;\nend process;\n\n\nstream_in_ready         <= stream_out_ready;\nstream_out_endofpacket  <= stream_out_endofpacket_int;\n\nstream_out_valid        <= '1' when (stream_in_valid = '1' and stream_out_endofpacket_int = '0') or flush_pipe = '1' else '0';\n\n-- Hold off CSR accesses during packet transfers to prevent changing of endian configuration mid-packet\ncsr_waitrequest_int     <= '1' when reset_n = '0' or in_packet = '1' or (stream_in_startofpacket = '1' and stream_in_valid = '1') or flush_pipe = '1' else '0';\ncsr_waitrequest         <= csr_waitrequest_int;\n\nprocess (clk, reset_n) begin\n    if (reset_n = '0') then\n        byteswapping      <= '0';\n        csr_readdatavalid <= '0';\n    elsif rising_edge(clk) then\n\n        if (csr_read = '1') then\n            csr_readdatavalid <= not csr_waitrequest_int;\n\n            case csr_address is\n                when \"00\"       => csr_readdata <= (31 downto 1 => '0') & byteswapping;\n                when \"01\"       => csr_readdata <= std_ulogic_vector(packet_count);\n                when others     => csr_readdata <= (31 downto 0 => 'X');\n            end case;\n\n        elsif (csr_write = '1' and csr_waitrequest_int = '0') then\n            case csr_address is\n                when \"00\"       => byteswapping <= csr_writedata(0);\n                when others     => null;\n            end case;\n        end if;\n    end if;\nend process;\n\n\n-- Unfortunately this workaround is required for Aldec: Need to schedule an event\nfake_process :process\nbegin\n    wait for 50 ns;\nend process;\n\n\nend architecture;\n"
  },
  {
    "path": "examples/mixed_language/hdl/toplevel.sv",
    "content": "// Example using mixed-language simulation\n//\n// Here we have a SystemVerilog toplevel that instantiates both SV and VHDL\n// sub entities\nmodule endian_swapper_mixed #(\n    parameter                               DATA_BYTES = 8\n) (\n    input                                   clk,\n    input                                   reset_n,\n\n    input [DATA_BYTES*8-1:0]                stream_in_data,\n    input [$clog2(DATA_BYTES)-1:0]          stream_in_empty,\n    input                                   stream_in_valid,\n    input                                   stream_in_startofpacket,\n    input                                   stream_in_endofpacket,\n    output reg                              stream_in_ready,\n\n    output reg [DATA_BYTES*8-1:0]           stream_out_data,\n    output reg [$clog2(DATA_BYTES)-1:0]     stream_out_empty,\n    output reg                              stream_out_valid,\n    output reg                              stream_out_startofpacket,\n    output reg                              stream_out_endofpacket,\n    input                                   stream_out_ready,\n\n    input  [1:0]                            csr_address,\n    output reg [31:0]                       csr_readdata,\n    output reg                              csr_readdatavalid,\n    input                                   csr_read,\n    input                                   csr_write,\n    output reg                              csr_waitrequest,\n    input [31:0]                            csr_writedata\n);\n\nlogic [DATA_BYTES*8-1:0]                    sv_to_vhdl_data;\nlogic [$clog2(DATA_BYTES)-1:0]              sv_to_vhdl_empty;\nlogic                                       sv_to_vhdl_valid;\nlogic                                       sv_to_vhdl_startofpacket;\nlogic                                       sv_to_vhdl_endofpacket;\nlogic                                       sv_to_vhdl_ready;\n\nlogic                                       csr_waitrequest_sv;\nlogic                                       csr_waitrequest_vhdl;\n\n\nendian_swapper_sv #(\n    .DATA_BYTES                             (DATA_BYTES)\n) i_swapper_sv (\n    .clk                                    (clk),\n    .reset_n                                (reset_n),\n\n    .stream_in_empty                        (stream_in_empty),\n    .stream_in_data                         (stream_in_data),\n    .stream_in_endofpacket                  (stream_in_endofpacket),\n    .stream_in_startofpacket                (stream_in_startofpacket),\n    .stream_in_valid                        (stream_in_valid),\n    .stream_in_ready                        (stream_in_ready),\n\n    .stream_out_empty                       (sv_to_vhdl_empty),\n    .stream_out_data                        (sv_to_vhdl_data),\n    .stream_out_endofpacket                 (sv_to_vhdl_endofpacket),\n    .stream_out_startofpacket               (sv_to_vhdl_startofpacket),\n    .stream_out_valid                       (sv_to_vhdl_valid),\n    .stream_out_ready                       (sv_to_vhdl_ready),\n\n    .csr_address                            (csr_address),\n    .csr_readdata                           (csr_readdata),\n    .csr_readdatavalid                      (csr_readdatavalid),\n    .csr_read                               (csr_read),\n    .csr_write                              (csr_write),\n    .csr_waitrequest                        (csr_waitrequest_sv),\n    .csr_writedata                          (csr_writedata)\n);\n\n\nendian_swapper_vhdl #(\n    .DATA_BYTES                             (DATA_BYTES)\n) i_swapper_vhdl (\n    .clk                                    (clk),\n    .reset_n                                (reset_n),\n\n    .stream_in_empty                        (sv_to_vhdl_empty),\n    .stream_in_data                         (sv_to_vhdl_data),\n    .stream_in_endofpacket                  (sv_to_vhdl_endofpacket),\n    .stream_in_startofpacket                (sv_to_vhdl_startofpacket),\n    .stream_in_valid                        (sv_to_vhdl_valid),\n    .stream_in_ready                        (sv_to_vhdl_ready),\n\n    .stream_out_empty                       (stream_out_empty),\n    .stream_out_data                        (stream_out_data),\n    .stream_out_endofpacket                 (stream_out_endofpacket),\n    .stream_out_startofpacket               (stream_out_startofpacket),\n    .stream_out_valid                       (stream_out_valid),\n    .stream_out_ready                       (stream_out_ready),\n\n    .csr_address                            (csr_address),\n    .csr_readdata                           (),\n    .csr_readdatavalid                      (),\n    .csr_read                               (csr_read),\n    .csr_write                              (csr_write),\n    .csr_waitrequest                        (csr_waitrequest_vhdl),\n    .csr_writedata                          (~csr_writedata)\n\n);\n\nassign csr_waitrequest = csr_waitrequest_sv | csr_waitrequest_vhdl;\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_language/hdl/toplevel.vhdl",
    "content": "-- Example using mixed-language simulation\n--\n-- Here we have a VHDL toplevel that instantiates both SV and VHDL\n-- sub entities\nlibrary ieee;\n\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nentity endian_swapper_mixed is\n    generic (\n        DATA_BYTES              : integer := 8);\n    port (\n        clk                     : in    std_ulogic;\n        reset_n                 : in    std_ulogic;\n\n        stream_in_data          : in    std_ulogic_vector(DATA_BYTES*8-1 downto 0);\n        stream_in_empty         : in    std_ulogic_vector(2 downto 0);\n        stream_in_valid         : in    std_ulogic;\n        stream_in_startofpacket : in    std_ulogic;\n        stream_in_endofpacket   : in    std_ulogic;\n        stream_in_ready         : out   std_ulogic;\n\n        stream_out_data         : out   std_ulogic_vector(DATA_BYTES*8-1 downto 0);\n        stream_out_empty        : out   std_ulogic_vector(2 downto 0);\n        stream_out_valid        : out   std_ulogic;\n        stream_out_startofpacket: out   std_ulogic;\n        stream_out_endofpacket  : out   std_ulogic;\n        stream_out_ready        : in    std_ulogic;\n\n        csr_address             : in    std_ulogic_vector(1 downto 0);\n        csr_readdata            : out   std_ulogic_vector(31 downto 0);\n        csr_readdatavalid       : out   std_ulogic;\n        csr_read                : in    std_ulogic;\n        csr_write               : in    std_ulogic;\n        csr_waitrequest         : out   std_ulogic;\n        csr_writedata           : in    std_ulogic_vector(31 downto 0)\n    );\nend;\n\narchitecture impl of endian_swapper_mixed is\n\n    -- The SV entity is instantiated as a component because cocotb is\n    -- executing vcom before vlog. Hence the toplevel VHDL file is compiled\n    -- before the SV module. Therefore, an entity instantiation is not possible here.\n    component endian_swapper_sv\n        generic (\n            DATA_BYTES              : integer := 8);\n        port (\n            clk                     : in    std_ulogic;\n            reset_n                 : in    std_ulogic;\n\n            stream_in_data          : in    std_ulogic_vector(DATA_BYTES*8-1 downto 0);\n            stream_in_empty         : in    std_ulogic_vector(2 downto 0);\n            stream_in_valid         : in    std_ulogic;\n            stream_in_startofpacket : in    std_ulogic;\n            stream_in_endofpacket   : in    std_ulogic;\n            stream_in_ready         : out   std_ulogic;\n\n            stream_out_data         : out   std_ulogic_vector(DATA_BYTES*8-1 downto 0);\n            stream_out_empty        : out   std_ulogic_vector(2 downto 0);\n            stream_out_valid        : out   std_ulogic;\n            stream_out_startofpacket: out   std_ulogic;\n            stream_out_endofpacket  : out   std_ulogic;\n            stream_out_ready        : in    std_ulogic;\n\n            csr_address             : in    std_ulogic_vector(1 downto 0);\n            csr_readdata            : out   std_ulogic_vector(31 downto 0);\n            csr_readdatavalid       : out   std_ulogic;\n            csr_read                : in    std_ulogic;\n            csr_write               : in    std_ulogic;\n            csr_waitrequest         : out   std_ulogic;\n            csr_writedata           : in    std_ulogic_vector(31 downto 0)\n        );\n  end component;\n\n\n    signal sv_to_vhdl_data:             std_ulogic_vector(DATA_BYTES*8-1 downto 0) ;\n    signal sv_to_vhdl_empty:            std_ulogic_vector(2 downto 0);\n    signal sv_to_vhdl_valid:            std_ulogic;\n    signal sv_to_vhdl_startofpacket:    std_ulogic;\n    signal sv_to_vhdl_endofpacket:      std_ulogic;\n    signal sv_to_vhdl_ready:            std_ulogic;\n\n    signal csr_waitrequest_vhdl, csr_waitrequest_sv : std_ulogic;\n\nbegin\ni_swapper_sv : endian_swapper_sv\n    generic map (\n        DATA_BYTES              =>      DATA_BYTES\n    ) port map (\n        clk                     =>      clk,\n        reset_n                 =>      reset_n,\n\n        stream_in_empty         =>      stream_in_empty,\n        stream_in_data          =>      stream_in_data,\n        stream_in_endofpacket   =>      stream_in_endofpacket,\n        stream_in_startofpacket =>      stream_in_startofpacket,\n        stream_in_valid         =>      stream_in_valid,\n        stream_in_ready         =>      stream_in_ready,\n\n        stream_out_empty        =>      sv_to_vhdl_empty,\n        stream_out_data         =>      sv_to_vhdl_data,\n        stream_out_endofpacket  =>      sv_to_vhdl_endofpacket,\n        stream_out_startofpacket=>      sv_to_vhdl_startofpacket,\n        stream_out_valid        =>      sv_to_vhdl_valid,\n        stream_out_ready        =>      sv_to_vhdl_ready,\n\n        csr_address             =>      csr_address,\n        csr_readdata            =>      csr_readdata,\n        csr_readdatavalid       =>      csr_readdatavalid,\n        csr_read                =>      csr_read,\n        csr_write               =>      csr_write,\n        csr_waitrequest         =>      csr_waitrequest_sv,\n        csr_writedata           =>      csr_writedata\n    );\n\n\n\ni_swapper_vhdl : entity work.endian_swapper_vhdl\ngeneric map (\n    DATA_BYTES              =>      DATA_BYTES\n) port map (\n    clk                     =>      clk,\n    reset_n                 =>      reset_n,\n\n    stream_in_empty         =>      sv_to_vhdl_empty,\n    stream_in_data          =>      sv_to_vhdl_data,\n    stream_in_endofpacket   =>      sv_to_vhdl_endofpacket,\n    stream_in_startofpacket =>      sv_to_vhdl_startofpacket,\n    stream_in_valid         =>      sv_to_vhdl_valid,\n    stream_in_ready         =>      sv_to_vhdl_ready,\n\n    stream_out_empty        =>      stream_out_empty,\n    stream_out_data         =>      stream_out_data,\n    stream_out_endofpacket  =>      stream_out_endofpacket,\n    stream_out_startofpacket=>      stream_out_startofpacket,\n    stream_out_valid        =>      stream_out_valid,\n    stream_out_ready        =>      stream_out_ready,\n\n    csr_address             =>      csr_address,\n    csr_readdata            =>      open,\n    csr_readdatavalid       =>      open,\n    csr_read                =>      csr_read,\n    csr_write               =>      csr_write,\n    csr_waitrequest         =>      csr_waitrequest_vhdl,\n    csr_writedata           =>      csr_writedata\n);\n\n\n    csr_waitrequest <= csr_waitrequest_sv or csr_waitrequest_vhdl;\nend architecture;\n"
  },
  {
    "path": "examples/mixed_language/tests/Makefile",
    "content": "# Override this variable to use a VHDL toplevel instead of SystemVerilog\nTOPLEVEL_LANG ?= verilog\n\nifeq ($(SIM),)\nall:\n\t@echo \"Skipping example mixed_language since Icarus doesn't support this\"\nclean::\nelse ifeq ($(shell echo $(SIM) | tr A-Z a-z),icarus)\nall:\n\t@echo \"Skipping example mixed_language since Icarus doesn't support this\"\nclean::\nelse\n\nCOCOTB_TOPLEVEL = endian_swapper_mixed\n\nPWD=$(shell pwd)\n\nVERILOG_SOURCES = $(PWD)/../hdl/endian_swapper.sv\nVHDL_SOURCES    = $(PWD)/../hdl/endian_swapper.vhdl\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    VERILOG_SOURCES += $(PWD)/../hdl/toplevel.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    VHDL_SOURCES += $(PWD)/../hdl/toplevel.vhdl\nelse\n    $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\n\nCOCOTB_TEST_MODULES=test_mixed_language\n\nifneq ($(filter $(SIM),ius xcelium),)\n    COMPILE_ARGS += -v93\nendif\n\nifneq ($(filter $(SIM),questa modelsim),)\n    SIM_ARGS += -t 1ps\nendif\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "examples/mixed_language/tests/test_mixed_language.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport sys\nfrom pathlib import Path\n\nimport pytest\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import RisingEdge, Timer\nfrom cocotb_tools.runner import get_runner\nfrom cocotb_tools.sim_versions import RivieraVersion\n\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\n\n# Riviera < 2024.10 fails to find dut.i_swapper_sv (gh-2921)\n@cocotb.test(\n    expect_error=AttributeError\n    if cocotb.simulator.is_running()\n    and cocotb.SIM_NAME.lower().startswith(\"riviera\")\n    and RivieraVersion(cocotb.SIM_VERSION) < \"2024.10\"\n    and LANGUAGE == \"vhdl\"\n    else ()\n)\nasync def mixed_language_accessing_test(dut):\n    \"\"\"Try accessing handles and setting values in a mixed language environment.\"\"\"\n    await Timer(100, unit=\"ns\")\n\n    verilog = dut.i_swapper_sv\n    cocotb.log.info(f\"Got: {verilog._name!r}\")\n\n    # discover all attributes of the SV component\n    # This is a workaround since SV modules are not discovered automatically\n    # when using Modelsim/Questa and a VHDL toplevel file.\n    verilog._discover_all()\n\n    vhdl = dut.i_swapper_vhdl\n    cocotb.log.info(f\"Got: {vhdl._name!r}\")\n\n    verilog.reset_n.value = 1\n    await Timer(100, unit=\"ns\")\n\n    vhdl.reset_n.value = 1\n    await Timer(100, unit=\"ns\")\n\n    assert verilog.reset_n.value == vhdl.reset_n.value, \"reset_n signals were different\"\n\n    # Try accessing an object other than a port...\n    verilog.flush_pipe.value\n    vhdl.flush_pipe.value\n\n\n# Riviera < 2024.10 fails to find dut.i_swapper_sv (gh-2921)\n@cocotb.test(\n    expect_error=AttributeError\n    if cocotb.simulator.is_running()\n    and cocotb.SIM_NAME.lower().startswith(\"riviera\")\n    and RivieraVersion(cocotb.SIM_VERSION) < \"2024.10\"\n    and LANGUAGE == \"vhdl\"\n    else ()\n)\nasync def mixed_language_functional_test(dut):\n    \"\"\"Try concurrent simulation of VHDL and Verilog and check the output.\"\"\"\n    await Timer(100, unit=\"ns\")\n\n    verilog = dut.i_swapper_sv\n    cocotb.log.info(f\"Got: {verilog._name!r}\")\n\n    vhdl = dut.i_swapper_vhdl\n    cocotb.log.info(f\"Got: {vhdl._name!r}\")\n\n    # setup default values\n    dut.reset_n.value = 0\n    dut.stream_out_ready.value = 1\n\n    dut.stream_in_startofpacket.value = 0\n    dut.stream_in_endofpacket.value = 0\n    dut.stream_in_data.value = 0\n    dut.stream_in_valid.value = 1\n    dut.stream_in_empty.value = 0\n\n    dut.csr_address.value = 0\n    dut.csr_read.value = 0\n    dut.csr_write.value = 0\n    dut.csr_writedata.value = 0\n\n    # reset cycle\n    await Timer(100, unit=\"ns\")\n    dut.reset_n.value = 1\n    await Timer(100, unit=\"ns\")\n\n    # start clock\n    cocotb.start_soon(Clock(dut.clk, 10, unit=\"ns\").start())\n    await Timer(500, unit=\"ns\")\n\n    previous_indata = 0\n    # transmit some packets\n    for _ in range(1, 5):\n        for i in range(1, 11):\n            await RisingEdge(dut.clk)\n            previous_indata = dut.stream_in_data.value.to_unsigned()\n\n            # write stream in data\n            dut.stream_in_data.value = i + 0x81FFFFFF2B00  # generate a magic number\n            dut.stream_in_valid.value = 1\n            await RisingEdge(dut.clk)\n            dut.stream_in_valid.value = 0\n\n            # await stream out data\n            await RisingEdge(dut.clk)\n            await RisingEdge(dut.clk)\n\n            # compare in and out data\n            assert previous_indata == dut.stream_out_data.value.to_unsigned(), (\n                f\"stream in data and stream out data were different in round {i}\"\n            )\n\n\nsim = os.getenv(\"SIM\", \"icarus\")\n\n\n@pytest.mark.skipif(\n    sim not in [\"questa\", \"riviera\", \"xcelium\"],\n    reason=f\"Skipping example mixed_language since {sim} doesn't support this\",\n)\ndef test_mixed_language_runner():\n    \"\"\"Simulate the mixed_language example using the Python runner.\n\n    This file can be run directly or via pytest discovery.\n    \"\"\"\n    hdl_toplevel_lang = os.getenv(\"TOPLEVEL_LANG\", \"verilog\")\n\n    proj_path = Path(__file__).resolve().parent.parent\n\n    sources = [\n        proj_path / \"hdl\" / \"endian_swapper.sv\",\n        proj_path / \"hdl\" / \"endian_swapper.vhdl\",\n    ]\n\n    if hdl_toplevel_lang == \"verilog\":\n        sources += [proj_path / \"hdl\" / \"toplevel.sv\"]\n    elif hdl_toplevel_lang == \"vhdl\":\n        sources += [proj_path / \"hdl\" / \"toplevel.vhdl\"]\n    else:\n        raise ValueError(\n            f\"A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG={hdl_toplevel_lang}\"\n        )\n\n    build_args = []\n    test_args = []\n    if sim == \"xcelium\":\n        build_args = [\"-v93\"]\n    elif sim == \"questa\":\n        test_args = [\"-t\", \"1ps\"]\n\n    # equivalent to setting the PYTHONPATH environment variable\n    sys.path.append(str(proj_path / \"tests\"))\n\n    runner = get_runner(sim)\n\n    runner.build(\n        hdl_toplevel=\"endian_swapper_mixed\",\n        sources=sources,\n        always=True,\n        build_args=build_args,\n    )\n\n    runner.test(\n        hdl_toplevel=\"endian_swapper_mixed\",\n        hdl_toplevel_lang=hdl_toplevel_lang,\n        test_module=\"test_mixed_language\",\n        test_args=test_args,\n    )\n\n\nif __name__ == \"__main__\":\n    test_mixed_language_runner()\n"
  },
  {
    "path": "examples/mixed_signal/.gitignore",
    "content": "run.raw\n"
  },
  {
    "path": "examples/mixed_signal/hdl/analog_probe_cadence.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\n// see also https://www.eetimes.com/document.asp?doc_id=1279150\n\nmodule analog_probe;\n\n  var string node_to_probe = \"<unassigned>\";\n\n  logic probe_voltage_toggle = 0;\n  real voltage;\n\n  always @(probe_voltage_toggle) begin: probe_voltage\n    if ($cds_analog_is_valid(node_to_probe, \"potential\")) begin\n      voltage = $cds_get_analog_value(node_to_probe, \"potential\");\n      // $display(\"%m: node_to_probe=%s has voltage of %e V\", node_to_probe, voltage);\n    end else begin\n      voltage = 1.234567;\n      $display(\"%m: Warning: node_to_probe=%s is not valid for $cds_get_analog_value, returning %f V\",\n               node_to_probe, voltage);\n    end\n  end  // probe_voltage\n\n  logic probe_current_toggle = 0;\n  real current;\n\n  always @(probe_current_toggle) begin: probe_current\n    if ($cds_analog_is_valid(node_to_probe, \"flow\")) begin\n      current = $cds_get_analog_value(node_to_probe, \"flow\");\n      // $display(\"%m: node_to_probe=%s has current of %e A\", node_to_probe, current);\n    end else begin\n      current = 0.123456;\n      $display(\"%m: Warning: node_to_probe=%s is not valid for $cds_get_analog_value, returning %f A\",\n               node_to_probe, current);\n    end\n  end  // probe_current\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/hdl/analog_probe_synopsys.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\nmodule analog_probe;\n\n  var string node_to_probe = \"<unassigned>\";\n\n  logic probe_voltage_toggle = 0;\n  real voltage;\n\n  always @(probe_voltage_toggle) begin: probe_voltage\n    voltage = $snps_get_volt(node_to_probe);\n  end\n\n  logic probe_current_toggle = 0;\n  real current;\n\n  always @(probe_current_toggle) begin: probe_current\n    current = $snps_get_port_current(node_to_probe);\n  end\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/hdl/capacitor.vams",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\n`include \"disciplines.vams\"\n`include \"constants.vams\"\n\nmodule capacitor(p, n);\n\n  inout p; electrical p;\n  inout n; electrical n;\n\n  parameter real capacitance=1 from [0:inf);  // capacitance value, must be >= 0\n\n  branch (p, n) cap;\n\n  analog begin\n    I(cap) <+ capacitance * ddt(V(cap));\n  end\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/hdl/nettypes_pkg_cadence.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\nimport cds_rnm_pkg::*;\n\npackage nettypes_pkg;\n\n  nettype wreal1driver voltage_net;\n\nendpackage\n"
  },
  {
    "path": "examples/mixed_signal/hdl/nettypes_pkg_synopsys.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\npackage nettypes_pkg;\n\n  nettype real voltage_net with r_res;\n\n  function automatic real r_res(input real drivers []);\n    r_res = 0.0;\n    foreach(drivers[k]) r_res += drivers[k];\n  endfunction\n\nendpackage\n"
  },
  {
    "path": "examples/mixed_signal/hdl/regulator.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\nmodule regulator(input       vdd,\n                 input [3:0] trim,\n                 output      vout,\n                 input       vss);\n\n  regulator_block\n    #(.vout_abs  (3.3),\n      .trim_step (0.2))\n  i_regulator_block\n    (\n     .vdd  (vdd),\n     .trim (trim),\n     .vout (vout),\n     .vss  (vss)\n     );\n\n  resistor\n    #(.resistance (100))\n  i_resistor\n    (\n     .p (vout),\n     .n (vss)\n     );\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/hdl/regulator.vams",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\n`include \"disciplines.vams\"\n`include \"constants.vams\"\n\nmodule regulator(vdd, trim, vout, vss);\n\n  input signed [3:0] trim; logic trim;\n  inout vdd; electrical vdd;\n  inout vout; electrical vout;\n  inout vss; electrical vss;\n\n  parameter real vout_abs=3.3 from (0:inf);  // must be > 0\n  parameter real trim_step=0.2 from (0:inf);  // must be > 0\n\n  real trim_volt;\n\n  always @(trim) begin\n    trim_volt = trim * trim_step;\n    // $display(\"%m: trim=%0d --> trim_volt=%f\", trim, trim_volt);\n  end\n\n  analog begin\n    // FIXME: must limit voltage at vdd/vss\n    V(vout, vss) <+ transition(vout_abs + trim_volt, 0, 20p);\n  end\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/hdl/regulator_block.vams",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\n`include \"disciplines.vams\"\n`include \"constants.vams\"\n\nmodule regulator_block(vdd, trim, vout, vss);\n\n  input signed [3:0] trim; logic trim;\n  inout vdd; electrical vdd;\n  inout vout; electrical vout;\n  inout vss; electrical vss;\n\n  parameter real vout_abs=3.3 from (0:inf);  // must be > 0\n  parameter real trim_step=0.2 from (0:inf);  // must be > 0\n\n  real trim_volt;\n\n  always @(trim) begin\n    trim_volt = trim * trim_step;\n    // $display(\"%m: trim=%0d --> trim_volt=%f\", trim, trim_volt);\n  end\n\n  analog begin\n    // TODO: limit voltage to vdd/vss\n    V(vout, vss) <+ transition(vout_abs + trim_volt, 0, 20p);\n  end\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/hdl/rescap.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\n// the design-under-test\nmodule rescap(input  interconnect vdd,\n              output interconnect vout,\n              input  interconnect vss);\n\n  resistor\n    #(.resistance (1e5))\n  i_resistor\n    (\n     .p (vdd),\n     .n (vout)\n     );\n\n  capacitor\n    #(.capacitance (1e-12))\n  i_capacitor\n    (\n     .p (vout),\n     .n (vss)\n     );\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/hdl/resistor.vams",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\n`include \"disciplines.vams\"\n`include \"constants.vams\"\n\nmodule resistor(p, n);\n\n  inout p; electrical p;\n  inout n; electrical n;\n\n  parameter real resistance=1 from (0:inf);  // resistance value, must be > 0\n\n  analog begin\n    V(p,n) <+ I(p,n) * resistance;\n  end\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/hdl/tb_regulator.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\nimport nettypes_pkg::*;\n\nmodule tb_regulator;\n\n  voltage_net vdd, vss, vout;\n  real vdd_val, vss_val = 0.0;\n  logic signed [3:0] trim_val = 0;\n\n  assign vdd = vdd_val;\n  assign vss = vss_val;\n\n  // the design\n  regulator i_regulator (.vdd  (vdd),\n                         .trim (trim_val),\n                         .vout (vout),\n                         .vss  (vss)\n                         );\n\n  // the \"multimeter\"\n  analog_probe i_analog_probe ();\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/hdl/tb_rescap.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\nimport nettypes_pkg::*;\n\nmodule tb_rescap;\n\n  voltage_net vdd, vss;\n  real vdd_val, vss_val = 0.0;\n\n  assign vdd = vdd_val;\n  assign vss = vss_val;\n\n  interconnect vout;\n\n  // the design\n  rescap i_rescap (.vdd  (vdd),\n                   .vout (vout),\n                   .vss  (vss)\n                   );\n\n  // the \"multimeter\"\n  analog_probe i_analog_probe ();\n\nendmodule\n"
  },
  {
    "path": "examples/mixed_signal/tests/Makefile",
    "content": "# Override this variable to use a VHDL toplevel instead of (System)Verilog\nTOPLEVEL_LANG ?= verilog\n\nCOCOTB_TOPLEVEL ?= tb_rescap\n\nifeq ($(COCOTB_TOPLEVEL),tb_rescap)\n    ifdef CI\n        COCOTB_TEST_MODULES ?= test_rescap_minimalist\n    else\n        COCOTB_TEST_MODULES ?= test_rescap_minimalist,test_rescap\n    endif\nelse ifeq ($(COCOTB_TOPLEVEL),tb_regulator)\n    ifdef CI\n        COCOTB_TEST_MODULES ?= test_regulator_trim\n    else\n        COCOTB_TEST_MODULES ?= test_regulator_trim,test_regulator_plot\n    endif\nelse\n    $(error Given COCOTB_TOPLEVEL '$(COCOTB_TOPLEVEL)' not supported)\nendif\n\nifeq ($(OS),Msys)\n    WPWD=$(shell sh -c 'pwd -W')\nelse\n    WPWD=$(shell pwd)\nendif\n\n\n# Files\n\nVERILOG_SOURCES += $(WPWD)/../hdl/resistor.vams\nVERILOG_SOURCES += $(WPWD)/../hdl/capacitor.vams\nVERILOG_SOURCES += $(WPWD)/../hdl/regulator_block.vams\n\nifeq ($(SIM),$(filter $(SIM),ius xcelium))\n    VERILOG_SOURCES += $(WPWD)/../hdl/analog_probe_cadence.sv\n    ifeq ($(TOPLEVEL_LANG),verilog)\n        VERILOG_SOURCES += $(WPWD)/../hdl/nettypes_pkg_cadence.sv\n        VERILOG_SOURCES += $(WPWD)/../hdl/rescap.sv\n        VERILOG_SOURCES += $(WPWD)/../hdl/regulator.sv\n        VERILOG_SOURCES += $(WPWD)/../hdl/tb_rescap.sv\n        VERILOG_SOURCES += $(WPWD)/../hdl/tb_regulator.sv\n    else ifeq ($(TOPLEVEL_LANG),vhdl)\n        $(error VHDL toplevel not yet implemented)\n        VHDL_SOURCES += $(WPWD)/../hdl/rescap.vhdl\n        VHDL_SOURCES += $(WPWD)/../hdl/regulator.vhdl\n    else\n        $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\n    endif\nelse ifeq ($(SIM),vcs)\n    VERILOG_SOURCES += $(WPWD)/../hdl/analog_probe_synopsys.sv\n    ifeq ($(TOPLEVEL_LANG),verilog)\n        VERILOG_SOURCES += $(WPWD)/../hdl/nettypes_pkg_synopsys.sv\n        VERILOG_SOURCES += $(WPWD)/../hdl/rescap.sv\n        VERILOG_SOURCES += $(WPWD)/../hdl/regulator.sv\n        VERILOG_SOURCES += $(WPWD)/../hdl/tb_rescap.sv\n        VERILOG_SOURCES += $(WPWD)/../hdl/tb_regulator.sv\n    else ifeq ($(TOPLEVEL_LANG),vhdl)\n        $(error VHDL toplevel not yet implemented)\n        VHDL_SOURCES += $(WPWD)/../hdl/rescap.vhdl\n        VHDL_SOURCES += $(WPWD)/../hdl/regulator.vhdl\n    else\n        $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\n    endif\nelse\n    $(error This example does not have support for SIM=$(SIM))\nendif\n\n\n# Options\n\nCOCOTB_HDL_TIMEUNIT=1ns\nCOCOTB_HDL_TIMEPRECISION=1ps\n\nifeq ($(SIM),$(filter $(SIM),ius xcelium))\n    SIM_ARGS += -discipline logic\n    SIM_ARGS += -amsconnrules ConnRules_full_fast\n    SIM_ARGS += +dr_info\n    SIM_ARGS += -iereport\n    SIM_ARGS += -ieinfo\n    SIM_ARGS += -ieinfo_log $(SIM_BUILD)/ams_ieinfo.log\n    SIM_ARGS += -spectre_args \"+lqtimeout 7200\"\n    SIM_ARGS += run.scs\n    SIM_ARGS += $(EXTRA_SIM_ARGS)\nelse ifeq ($(SIM),vcs)\n    COMPILE_ARGS += -ad=./vcsAD.init\n    COMPILE_ARGS += -ams\n    COMPILE_ARGS += -ams_iereport\n    COMPILE_ARGS += -xlrm coerce_nettype\n#    COMPILE_ARGS += -ams_discipline <discipline_name>\n    SIM_ARGS += $(EXTRA_SIM_ARGS)\nelse\n    $(error This example does not have support for SIM=$(SIM))\nendif\n\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "examples/mixed_signal/tests/run.scs",
    "content": "// Cadence Spectre control file for analog solver\n//tran tran stop=100u step=5n maxstep=5n relref=alllocal checklimitdest=both errpreset=conservative\ntran tran stop=100u maxstep=5n\n\n// connectmodule selection when not done via xrun -amsconnrules\n// amsd {\n//     ie vsup=5.0\n// }\n\n// saveOptions options save=all pwr=all currents=all saveahdlvars=all depth=3\n// save foo:currents\n"
  },
  {
    "path": "examples/mixed_signal/tests/test_regulator_plot.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\nimport math\n\nimport matplotlib.pyplot as plt\n\nimport cocotb\nfrom cocotb.triggers import Timer\n\n\n@cocotb.test()\nasync def test_trim_vals(tb_hdl):\n    \"\"\"Set trim value of regulator and measure resulting voltage.\"\"\"\n\n    probed_node = \"tb_regulator.i_regulator.vout\"\n    tb_hdl.vdd_val.value = 7.7\n    tb_hdl.vss_val.value = 0.0\n\n    probedata = []\n    for trim_val in [0, 3, -5]:\n        tb_hdl.trim_val.value = trim_val\n        await Timer(1, unit=\"ns\")\n        trimmed_volt = await get_voltage(tb_hdl, probed_node)\n        actual_trim_val = tb_hdl.trim_val.value.to_signed()\n        cocotb.log.info(\n            f\"trim_val={actual_trim_val} results in {probed_node}={trimmed_volt:.4} V\"\n        )\n        # sanity check: output voltage can not exceed supply\n        assert tb_hdl.vss_val.value <= trimmed_volt <= tb_hdl.vdd_val.value\n        probedata.append((actual_trim_val, trimmed_volt))\n\n    plot_data(tb_hdl, datasets=probedata, graphfile=\"regulator.png\")\n\n\nasync def get_voltage(tb_hdl, node):\n    \"\"\"Measure voltage on *node*.\"\"\"\n    await Timer(1, unit=\"ps\")  # let trim_val take effect\n    tb_hdl.i_analog_probe.node_to_probe.value = node.encode(\"ascii\")\n    tb_hdl.i_analog_probe.probe_voltage_toggle.value = ~int(\n        tb_hdl.i_analog_probe.probe_voltage_toggle\n    )\n    await Timer(1, unit=\"ps\")  # waiting time needed for the analog values to be updated\n    cocotb.log.debug(\n        f\"Voltage on node {node} is {tb_hdl.i_analog_probe.voltage.value:.4} V\"\n    )\n    return tb_hdl.i_analog_probe.voltage.value\n\n\ndef plot_data(tb_hdl, datasets, graphfile=\"cocotb_plot.png\"):\n    \"\"\"Save a graph to file *graphfile*.\n\n    Trim and voltage value are contained in *datasets*.\n    \"\"\"\n    trim, voltage = zip(*datasets)\n    trim_round = range(1, len(trim) + 1)\n\n    fig = plt.figure()\n    ax = plt.axes()\n    ax.set_title(\n        \"Probed node: {}\".format(\n            tb_hdl.i_analog_probe.node_to_probe.value.decode(\"ascii\")\n        )\n    )\n    ax.set_ylabel(\"Voltage (V)\")\n    ax.set_ylim([0, math.ceil(max(voltage)) + 1])\n    ax.step(trim_round, voltage, where=\"mid\")\n    ax.plot(trim_round, voltage, \"C0o\", alpha=0.5)\n    for i, j, k in zip(trim_round, trim, voltage):\n        ax.annotate(\n            f\"trim={j}\",\n            xy=(i, k),\n            xytext=(0, 5),\n            textcoords=\"offset points\",\n            ha=\"center\",\n        )\n    ax.xaxis.set_major_locator(plt.NullLocator())\n    ax.xaxis.set_major_formatter(plt.NullFormatter())\n    fig.tight_layout()\n    fig.set_size_inches(11, 6)\n\n    cocotb.log.info(f\"Writing file {graphfile}\")\n    fig.savefig(graphfile)\n"
  },
  {
    "path": "examples/mixed_signal/tests/test_regulator_trim.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\nimport itertools\n\nimport cocotb\nfrom cocotb.triggers import Timer\n\n\nclass Regulator_TB:\n    \"\"\"Class for collecting testbench objects.\n\n    Args:\n        tb_hdl: The toplevel of the design-under-test.\n            In this mixed cocotb/HDL testbench environment, it is the HDL testbench.\n        settling_time_ns (int): Time in nanoseconds to wait before sample is taken.\n    \"\"\"\n\n    def __init__(self, tb_hdl, settling_time_ns=1):\n        self.tb_hdl = tb_hdl\n        self.settling_time_ns = settling_time_ns\n        self.analog_probe = (\n            tb_hdl.i_analog_probe\n        )  #: The instance name of the analog probe module.\n        self._bit_toggle_stream = itertools.cycle(\n            [0, 1]\n        )  #: Produce bitstream that toggles between ``0`` and ``1``.\n\n    async def get_voltage(self, node):\n        \"\"\"Measure voltage on *node*.\"\"\"\n        toggle = next(self._bit_toggle_stream)\n        self.tb_hdl.i_analog_probe.node_to_probe.value = node.encode(\"ascii\")\n        self.analog_probe.probe_voltage_toggle.value = toggle\n        await Timer(\n            1, unit=\"ps\"\n        )  # waiting time needed for the analog values to be updated\n        cocotb.log.debug(\n            \"trim value={}: {}={:.4} V\".format(\n                self.tb_hdl.trim_val.value,\n                self.analog_probe.node_to_probe.value.decode(\"ascii\"),\n                self.analog_probe.voltage.value,\n            )\n        )\n        return self.analog_probe.voltage.value\n\n    async def find_trim_val(self, probed_node, target_volt, trim_val_node):\n        \"\"\"Calculate best trimming value for *target_volt*.\n        Algorithm is to measure voltage of *probed_node* at\n        lowest and highest trim value,\n        then calculate the slope and finally the target trim value from slope.\n        Assumes a linear behaviour.\n\n        Args:\n            probed_node: The node to probe for the trimmed voltage.\n            target_volt (float): The target voltage at *probed_node*.\n            trim_val_node: The node to apply the trim value to.\n\n        Yields:\n            float: The calculated best value for *trim_val_node*.\n        \"\"\"\n        # assuming two's complement\n        trim_val_min = -(2 ** (trim_val_node.value.n_bits - 1))\n        trim_val_max = 2 ** (trim_val_node.value.n_bits - 1) - 1\n        # the actual trimming procedure:\n        # minimum values\n        trim_val_node.value = trim_val_min\n        await Timer(self.settling_time_ns, unit=\"ns\")\n        volt_min = await self.get_voltage(probed_node)\n        # maximum values\n        trim_val_node.value = trim_val_max\n        await Timer(self.settling_time_ns, unit=\"ns\")\n        volt_max = await self.get_voltage(probed_node)\n        if target_volt > volt_max:\n            cocotb.log.debug(\n                f\"target_volt={target_volt} > volt_max={volt_max}, returning minimum trim value {trim_val_max}\"\n            )\n            return trim_val_max\n        if target_volt < volt_min:\n            cocotb.log.debug(\n                f\"target_volt={target_volt} < volt_min={volt_min}, returning maximum trim value {trim_val_min}\"\n            )\n            return trim_val_min\n        # do the calculation:\n        slope = (trim_val_max - trim_val_min) / (volt_max - volt_min)\n        target_trim = (target_volt - volt_min) * slope + trim_val_min\n        return target_trim\n\n\n@cocotb.test()\nasync def run_test(tb_hdl):\n    \"\"\"Run test for mixed signal simulation - automatic trimming of a voltage regulator.\"\"\"\n\n    tb_py = Regulator_TB(tb_hdl)\n    node = \"tb_regulator.i_regulator.vout\"\n\n    _ = await tb_py.get_voltage(\n        node\n    )  # NOTE: dummy read apparently needed because of $cds_get_analog_value in analog_probe\n\n    # show automatic trimming\n    target_volt = 3.013\n    cocotb.log.info(f\"Running trimming algorithm for target voltage {target_volt:.4} V\")\n    best_trim_float = await tb_py.find_trim_val(\n        probed_node=node, target_volt=target_volt, trim_val_node=tb_py.tb_hdl.trim_val\n    )\n    best_trim_rounded = round(best_trim_float)\n    tb_py.tb_hdl.trim_val.value = best_trim_rounded\n    await Timer(tb_py.settling_time_ns, unit=\"ns\")\n    trimmed_volt = await tb_py.get_voltage(node)\n    cocotb.log.info(\n        f\"Best trimming value is {best_trim_rounded} \"\n        f\"--> voltage is {trimmed_volt:.4} V (difference to target is {trimmed_volt - target_volt:.4} V)\"\n    )\n    best_trim_rounded_exp = -1\n    assert best_trim_rounded == best_trim_rounded_exp\n"
  },
  {
    "path": "examples/mixed_signal/tests/test_rescap.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\nfrom collections import defaultdict, namedtuple\nfrom itertools import cycle\n\nimport matplotlib.pyplot as plt\n\nimport cocotb\nfrom cocotb.triggers import Timer\nfrom cocotb.utils import get_sim_time\n\nDataset = namedtuple(\"Dataset\", \"time, voltage, current\")\n\n\nclass ResCap_TB:\n    \"\"\"The testbench class for the rescap design.\"\"\"\n\n    def __init__(self, tb_hdl):\n        self.tb_hdl = tb_hdl\n        self.analog_probe = (\n            tb_hdl.i_analog_probe\n        )  #: The instance name of the analog probe module.\n        self.togglestream = cycle(range(2))  # toggle between 0 and 1\n\n    async def _get_single_sample(self, node):\n        toggle = next(self.togglestream)\n        self.tb_hdl.i_analog_probe.node_to_probe.value = node.encode(\"ascii\")\n        self.analog_probe.probe_voltage_toggle.value = toggle\n        self.analog_probe.probe_current_toggle.value = toggle\n        await Timer(\n            1, unit=\"ps\"\n        )  # waiting time needed for the analog values to be updated\n        dataset = Dataset(\n            time=get_sim_time(unit=\"ns\"),\n            voltage=self.analog_probe.voltage.value,\n            current=self.analog_probe.current.value * 1000.0,  # in mA\n        )\n        cocotb.log.debug(\n            \"{}={:.4} V, {:.4} mA\".format(\n                self.analog_probe.node_to_probe.value.decode(\"ascii\"),\n                dataset.voltage,\n                dataset.current,\n            )\n        )\n        return dataset\n\n    async def get_sample_data(self, nodes, num=1, delay_ns=1):\n        \"\"\"For all *nodes*, get *num* samples, spaced *delay_ns* apart.\n\n        Yields:\n            list: List (*num* samples long) of :any:`Dataset` for all *nodes*.\n        \"\"\"\n        if not isinstance(nodes, list):  # single element? make it a list\n            _nodes = [nodes]\n        else:\n            _nodes = nodes\n        datasets = defaultdict(list)\n        for idx in range(num):\n            for node in _nodes:\n                dataset = await self._get_single_sample(node)\n                datasets[node].append(dataset)\n            if idx != num:\n                await Timer(delay_ns, unit=\"ns\")\n        return datasets\n\n    def plot_data(self, datasets, nodes, graphfile=\"cocotb_plot.png\"):\n        \"\"\"Save a charge graph of *nodes* to file *graphfile*.\n\n        Voltage and current value are contained in *datasets*.\n        \"\"\"\n        fig, ax_volt = plt.subplots()\n        color_volt = \"tab:red\"\n        color_curr = \"tab:blue\"\n        ax_volt.set_title(\"rescap\")\n        ax_volt.set_xlabel(\"Time (ns)\")\n        ax_volt.set_ylabel(\"Voltage (V)\", color=color_volt)\n        ax_curr = (\n            ax_volt.twinx()\n        )  # instantiate a second axis that shares the same x-axis\n        ax_curr.set_ylabel(\n            \"Current (mA)\", color=color_curr\n        )  # we already handled the x-label with ax_volt\n\n        for node in nodes:\n            time, voltage, current = zip(*(datasets[node]))\n            if node.endswith(\"vout\"):\n                alpha = 1.0\n            else:\n                alpha = 0.333\n            ax_volt.plot(\n                time,\n                voltage,\n                color=color_volt,\n                alpha=alpha,\n                marker=\".\",\n                markerfacecolor=\"black\",\n                linewidth=1,\n                label=f\"V({node})\",\n            )\n            ax_curr.plot(\n                time,\n                current,\n                color=color_curr,\n                alpha=alpha,\n                marker=\".\",\n                markerfacecolor=\"black\",\n                linewidth=1,\n                label=f\"I({node})\",\n            )\n\n        ax_volt.tick_params(axis=\"y\", labelcolor=color_volt)\n        ax_curr.tick_params(axis=\"y\", labelcolor=color_curr)\n        ax_volt.axhline(linestyle=\":\", color=\"gray\")\n\n        mpl_align_yaxis(ax_volt, 0, ax_curr, 0)\n        fig.tight_layout()  # otherwise the right y-label is slightly clipped\n        fig.set_size_inches(11, 6)\n        fig.legend(loc=\"upper right\", bbox_to_anchor=(0.8, 0.9), frameon=False)\n\n        cocotb.log.info(f\"Writing file {graphfile}\")\n        fig.savefig(graphfile)\n\n\n@cocotb.test()\nasync def run_test(tb_hdl):\n    \"\"\"Run test for mixed signal resistor/capacitor simulation.\"\"\"\n\n    tb_py = ResCap_TB(tb_hdl)\n\n    nodes_to_probe = [\"tb_rescap.i_rescap.vdd\", \"tb_rescap.i_rescap.vout\"]\n    # nodes_to_probe = [\"tb_rescap.i_rescap.vdd\", \"tb_rescap.i_rescap.i_capacitor.p\"]\n\n    probedata = defaultdict(list)\n\n    vdd = 0.0\n    tb_py.tb_hdl.vdd_val.value = vdd\n    tb_py.tb_hdl.vss_val.value = 0.0\n    cocotb.log.info(f\"Setting vdd={vdd:.4} V\")\n    # dummy read appears to be necessary for the analog solver\n    _ = await tb_py.get_sample_data(nodes=nodes_to_probe)\n\n    for vdd in [5.55, -3.33]:\n        tb_py.tb_hdl.vdd_val.value = vdd\n        tb_py.tb_hdl.vss_val.value = 0.0\n        cocotb.log.info(f\"Setting vdd={vdd:.4} V\")\n        data = await tb_py.get_sample_data(num=60, delay_ns=5, nodes=nodes_to_probe)\n        for node in nodes_to_probe:\n            probedata[node].extend(data[node])\n\n    tb_py.plot_data(datasets=probedata, nodes=nodes_to_probe, graphfile=\"rescap.png\")\n\n\ndef mpl_align_yaxis(ax1, v1, ax2, v2):\n    \"\"\"Adjust ax2 ylimit so that v2 in ax2 is aligned to v1 in ax1.\"\"\"\n    _, y1 = ax1.transData.transform((0, v1))\n    _, y2 = ax2.transData.transform((0, v2))\n    mpl_adjust_yaxis(ax2, (y1 - y2) / 2, v2)\n    mpl_adjust_yaxis(ax1, (y2 - y1) / 2, v1)\n\n\ndef mpl_adjust_yaxis(ax, ydif, v):\n    \"\"\"Shift axis ax by ydiff, maintaining point v at the same location.\"\"\"\n    inv = ax.transData.inverted()\n    _, dy = inv.transform((0, 0)) - inv.transform((0, ydif))\n    miny, maxy = ax.get_ylim()\n    miny, maxy = miny - v, maxy - v\n    if -miny > maxy or (-miny == maxy and dy > 0):\n        nminy = miny\n        nmaxy = miny * (maxy + dy) / (miny + dy)\n    else:\n        nmaxy = maxy\n        nminy = maxy * (miny + dy) / (maxy + dy)\n    ax.set_ylim(nminy + v, nmaxy + v)\n"
  },
  {
    "path": "examples/mixed_signal/tests/test_rescap_minimalist.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.triggers import Timer\n\n\n@cocotb.test()\nasync def rescap_minimalist_test(tb_hdl):\n    \"\"\"Mixed signal resistor/capacitor simulation, minimalistic.\"\"\"\n\n    tb_hdl.vdd_val.value = 7.7\n    tb_hdl.vss_val.value = 0.0\n    tb_hdl.i_analog_probe.node_to_probe.value = b\"tb_rescap.i_rescap.vout\"\n\n    for toggle in [1, 0, 1, 0, 1, 0]:\n        await Timer(50, unit=\"ns\")\n        tb_hdl.i_analog_probe.probe_voltage_toggle.value = toggle\n        tb_hdl.i_analog_probe.probe_current_toggle.value = toggle\n        await Timer(\n            1, unit=\"ps\"\n        )  # waiting time needed for the analog values to be updated\n        cocotb.log.info(\n            \"tb_hdl.i_analog_probe@{}={:.4} V  {:.4} A\".format(\n                tb_hdl.i_analog_probe.node_to_probe.value.decode(\"ascii\"),\n                tb_hdl.i_analog_probe.voltage.value,\n                tb_hdl.i_analog_probe.current.value,\n            )\n        )\n"
  },
  {
    "path": "examples/mixed_signal/tests/vcsAD.init",
    "content": "choose hsim spice/foo.cdl;\npartition -cell subckt1 subckt2;\nset bus_format [%d];\n"
  },
  {
    "path": "examples/simple_dff/.gitignore",
    "content": "# Python\n__pycache__\n\n# Waveforms\n*.vcd\n\n# Results\nresults.xml\nsim_build\n\n# VCS files\n*.tab\nucli.key\n\n# Cadence Incisive/Xcelium\n*.elog\nirun.log\nxrun.log\nirun.key\nxrun.key\nirun.history\nxrun.history\nINCA_libs\nxcelium.d\nncelab_*.err\nxmelab_*.err\nncsim_*.err\nxmsim_*.err\nbpad_*.err\n.bpad/\n.simvision/\nwaves.shm/\n\n# Mentor Modelsim/Questa\nmodelsim.ini\ntranscript\n*.wlf\n\n# Riviera\nlibrary.cfg\ndataset.asdb\ncompile\nlibrary.cfg\ndataset.asdb\ncompile\n"
  },
  {
    "path": "examples/simple_dff/Makefile",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\n\nTOPLEVEL_LANG ?= verilog\n\nifeq ($(TOPLEVEL_LANG),verilog)\n  VERILOG_SOURCES = $(shell pwd)/dff.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n  VHDL_SOURCES = $(shell pwd)/dff.vhdl\nendif\n\nCOCOTB_TEST_MODULES = test_dff\nCOCOTB_TOPLEVEL = dff\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "examples/simple_dff/dff.sv",
    "content": "// This file is public domain, it can be freely copied without restrictions.\n// SPDX-License-Identifier: CC0-1.0\n\n`timescale 1us/1us\n\nmodule dff (\n  input logic clk, d,\n  output logic q\n);\n\nalways @(posedge clk) begin\n  q <= d;\nend\n\nendmodule\n"
  },
  {
    "path": "examples/simple_dff/dff.vhdl",
    "content": "-- This file is public domain, it can be freely copied without restrictions.\n-- SPDX-License-Identifier: CC0-1.0\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n\nentity dff is\nport(\n  clk: in std_logic;\n  d: in std_logic;\n  q: out std_logic);\nend dff;\n\narchitecture behavioral of dff is\nbegin\n  process (clk) begin\n    if rising_edge(clk) then\n      q <= d;\n    end if;\n  end process;\nend behavioral;\n"
  },
  {
    "path": "examples/simple_dff/test_dff.py",
    "content": "# This file is public domain, it can be freely copied without restrictions.\n# SPDX-License-Identifier: CC0-1.0\nfrom __future__ import annotations\n\nimport os\nimport random\nfrom pathlib import Path\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import RisingEdge\nfrom cocotb_tools.runner import get_runner\n\nLANGUAGE = os.getenv(\"TOPLEVEL_LANG\", \"verilog\").lower().strip()\n\n\n@cocotb.test()\nasync def dff_simple_test(dut):\n    \"\"\"Test that d propagates to q\"\"\"\n\n    # Set initial input value to prevent it from floating\n    dut.d.value = 0\n\n    # Create a 10us period clock driver on port `clk`\n    clock = Clock(dut.clk, 10, unit=\"us\")\n    # Start the clock. Start it low to avoid issues on the first RisingEdge\n    clock.start(start_high=False)\n\n    # Synchronize with the clock. This will register the initial `d` value\n    await RisingEdge(dut.clk)\n\n    expected_val = 0  # Matches initial input value\n    for i in range(10):\n        val = random.randint(0, 1)\n        dut.d.value = val  # Assign the random value val to the input port d\n        await RisingEdge(dut.clk)\n        assert dut.q.value == expected_val, f\"output q was incorrect on the {i}th cycle\"\n        expected_val = val  # Save random value for next RisingEdge\n\n    # Check the final input on the next clock\n    await RisingEdge(dut.clk)\n    assert dut.q.value == expected_val, \"output q was incorrect on the last cycle\"\n\n\ndef test_simple_dff_runner():\n    sim = os.getenv(\"SIM\", \"icarus\")\n\n    proj_path = Path(__file__).resolve().parent\n\n    if LANGUAGE == \"verilog\":\n        sources = [proj_path / \"dff.sv\"]\n    else:\n        sources = [proj_path / \"dff.vhdl\"]\n\n    runner = get_runner(sim)\n    runner.build(\n        sources=sources,\n        hdl_toplevel=\"dff\",\n        always=True,\n    )\n\n    runner.test(hdl_toplevel=\"dff\", test_module=\"test_dff,\")\n\n\nif __name__ == \"__main__\":\n    test_simple_dff_runner()\n"
  },
  {
    "path": "noxfile.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport glob\nimport os\nimport shutil\nfrom contextlib import suppress\nfrom pathlib import Path\nfrom typing import cast\n\nimport nox\nimport nox_uv\n\nnox.options.default_venv_backend = \"uv\"\n\n# Sessions run by default if nox is called without further arguments.\nnox.options.sessions = [\"dev_test\"]\n\n#\n# Helpers for use within this file.\n#\n\n\ndef simulator_support_matrix() -> list[tuple[str, str, str]]:\n    \"\"\"\n    Get a list of supported simulator/toplevel-language/GPI-interface tuples.\n    \"\"\"\n\n    # Simulators with support for VHDL through VHPI, and Verilog through VPI.\n    standard = [\n        (sim, toplevel_lang, gpi_interface)\n        for sim in (\"activehdl\", \"riviera\", \"xcelium\", \"vcs\", \"questa\")\n        for toplevel_lang, gpi_interface in ((\"verilog\", \"vpi\"), (\"vhdl\", \"vhpi\"))\n    ]\n\n    # Special-case simulators.\n    special = [\n        (\"cvc\", \"verilog\", \"vpi\"),\n        (\"dsim\", \"verilog\", \"vpi\"),\n        (\"ghdl\", \"vhdl\", \"vpi\"),\n        (\"icarus\", \"verilog\", \"vpi\"),\n        (\"nvc\", \"vhdl\", \"vhpi\"),\n        (\"questa\", \"vhdl\", \"fli\"),\n        (\"verilator\", \"verilog\", \"vpi\"),\n    ]\n\n    return standard + special\n\n\ndef env_vars_for_sim_test(\n    sim: str, toplevel_lang: str, gpi_interface: str\n) -> dict[str, str]:\n    \"\"\"Prepare the environment variables controlling the test run.\"\"\"\n    env = {\n        \"SIM\": sim,\n        \"TOPLEVEL_LANG\": toplevel_lang,\n    }\n\n    assert not (toplevel_lang == \"verilog\" and gpi_interface != \"vpi\")\n    if toplevel_lang == \"vhdl\":\n        env[\"VHDL_GPI_INTERFACE\"] = gpi_interface\n\n    return env\n\n\ndef configure_test_env(session: nox.Session) -> None:\n    \"\"\"Set environment variables for any kind of test run.\"\"\"\n\n    # Do not fail on DeprecationWarning caused by virtualenv, which might come from\n    # the site module.\n    session.env[\"PYTHONWARNINGS\"] = \"error,ignore::DeprecationWarning:site\"\n\n    # Test with debug enabled, but log level still set low. That way we can test the code\n    # without slowing everything down by emitting roughly 1 million logs.\n    session.env[\"COCOTB_SCHEDULER_DEBUG\"] = \"1\"\n    session.env[\"GPI_DEBUG\"] = \"1\"\n    session.env[\"PYGPI_DEBUG\"] = \"1\"\n\n\ndef stringify_dict(d: dict[str, str]) -> str:\n    return \", \".join(f\"{k}={v}\" for k, v in d.items())\n\n\n#\n# Development pipeline\n#\n# - Build cocotb with aggressive error checking and coverage flags.\n# - Run doctests in the source tree with pytest.\n# - Run simulator-agnostic tests with pytest.\n# - Run simulator-specific tests and examples with pytest.\n# - Run 'make test' to test Makefile-based tests.\n# - Combine coverage from all test runs into a .coverage file.\n# - Produce coverage reports from the combined .coverage file.\n#\n\n\ndef build_cocotb_for_dev_test(session: nox.Session) -> None:\n    \"\"\"Build local cocotb for a development test.\n\n    - Build with more aggressive error checking.\n    \"\"\"\n\n    env = session.env.copy()\n    flags = \" \".join(\n        [\n            \"-Werror\",\n            \"-Wno-error=deprecated-declarations\",\n            \"-Wsuggest-override\",\n            \"-Og\",\n            \"-g\",\n            \"--coverage\",\n        ]\n    )\n    env[\"CFLAGS\"] = flags\n    env[\"CXXFLAGS\"] = flags\n    env[\"LDFLAGS\"] = \"--coverage\"\n\n    # Editable installs break C/C++ coverage collection; don't use them.\n    # C/C++ coverage collection requires that the object files produced by the\n    # compiler are not moved around, otherwise the gcno and gcda files produced\n    # at compile and runtime, respectively, are located in the wrong\n    # directories. Depending on the version of the Python install machinery\n    # editable builds are done in a directory in /tmp, which is removed after\n    # the build completes, taking all gcno files with them, as well as the path\n    # to place the gcda files.\n    session.install(\"-v\", \".\", env=env)\n\n\n@nox_uv.session(\n    uv_groups=[\"dev_test\"],\n    uv_no_install_project=True,\n    uv_sync_locked=False,\n)\n@nox.parametrize(\"sim,toplevel_lang,gpi_interface\", simulator_support_matrix())\ndef dev_test(\n    session: nox.Session,\n    sim: str,\n    toplevel_lang: str,\n    gpi_interface: str,\n) -> None:\n    \"\"\"Run all development tests and merge coverage.\"\"\"\n    build_cocotb_for_dev_test(session)\n    configure_test_env(session)\n    # Collect coverage of cocotb\n    session.env[\"COCOTB_LIBRARY_COVERAGE\"] = \"1\"\n    dev_test_nosim(session)\n    dev_test_sim(session, sim, toplevel_lang, gpi_interface)\n    dev_coverage_combine(session)\n\n\ndef dev_test_sim(\n    session: nox.Session,\n    sim: str,\n    toplevel_lang: str,\n    gpi_interface: str,\n) -> None:\n    \"\"\"Test a development version of cocotb against a simulator.\"\"\"\n\n    env = env_vars_for_sim_test(sim, toplevel_lang, gpi_interface)\n    config_str = stringify_dict(env)\n\n    # Remove a potentially existing coverage file from a previous run for the\n    # same test configuration. Use a filename *not* starting with `.coverage.`,\n    # as coverage.py assumes ownership over these files and deleted them at\n    # will.\n    coverage_file = Path(f\".cov.test.sim-{sim}-{toplevel_lang}-{gpi_interface}\")\n    with suppress(FileNotFoundError):\n        coverage_file.unlink()\n\n    if \"COCOTB_CI_SKIP_MAKE\" not in os.environ:\n        session.log(f\"Running 'make test' against a simulator {config_str}\")\n        session.run(\"make\", \"-k\", \"test\", external=True, env=env)\n\n    # Run pytest for files which can only be tested in the source tree, not in\n    # the installed binary (otherwise we get an \"import file mismatch\" error\n    # from pytest).\n    session.log(\"Running simulator-agnostic tests in the source tree with pytest\")\n\n    cocotb_pkg_dir = Path(\n        cast(\n            \"str\",\n            session.run(\n                \"python\",\n                \"-c\",\n                \"import cocotb; print(cocotb.__file__)\",\n                env={\"PYTHONWARNINGS\": \"ignore\"},\n                silent=True,\n            ),\n        ).strip()\n    ).parent\n\n    pytest_sourcetree = [\n        str(cocotb_pkg_dir / \"types\"),\n    ]\n    session.run(\n        \"pytest\",\n        \"-v\",\n        \"--doctest-modules\",\n        \"--cov=cocotb\",\n        \"--cov-branch\",\n        # Don't display coverage report here\n        \"--cov-report=\",\n        # Append to the .coverage file created in the previous pytest\n        # invocation in this session.\n        \"--cov-append\",\n        *pytest_sourcetree,\n    )\n\n    session.log(f\"Running simulator-specific tests against a simulator {config_str}\")\n    session.run(\n        \"pytest\",\n        \"-v\",\n        \"--cov=cocotb\",\n        \"--cov-branch\",\n        # Don't display coverage report here\n        \"--cov-report=\",\n        \"-k\",\n        \"simulator_required\",\n        env=env,\n    )\n    Path(\".coverage\").rename(\".coverage.pytest\")\n\n    session.log(f\"Running examples against a simulator {config_str}\")\n    pytest_example_tree = [\n        \"examples/adder\",\n        \"examples/simple_dff\",\n        \"examples/matrix_multiplier\",\n        \"examples/mixed_language\",\n    ]\n    session.run(\n        \"pytest\",\n        \"-v\",\n        *pytest_example_tree,\n        env=env,\n    )\n\n    # We need to run it separately to avoid loading pytest cocotb plugin for other tests\n    session.log(f\"Running tests for pytest plugin against a simulator {config_str}\")\n    session.run(\n        \"pytest\",\n        \"-v\",\n        \"tests/pytest_plugin\",\n        \"--cocotb-simulator\",\n        sim,\n        \"--cocotb-gpi-interfaces\",\n        gpi_interface,\n        \"--cocotb-toplevel-lang\",\n        toplevel_lang,\n        env=env,\n    )\n\n    session.log(f\"All tests and examples passed with configuration {config_str}!\")\n\n    # Combine coverage produced during the test runs, and place it in a file\n    # with a name specific to this invocation of dev_test_sim().\n    coverage_files = glob.glob(\"**/.coverage.cocotb\", recursive=True)\n    if not coverage_files:\n        session.error(\n            \"No coverage files found. Something went wrong during the test execution.\"\n        )\n    coverage_files.append(\".coverage.pytest\")\n    session.run(\"coverage\", \"combine\", \"--append\", *coverage_files)\n    Path(\".coverage\").rename(coverage_file)\n\n    session.log(f\"Stored Python coverage for this test run in {coverage_file}.\")\n\n\ndef dev_test_nosim(session: nox.Session) -> None:\n    \"\"\"Run the simulator-agnostic tests against a cocotb development version.\"\"\"\n\n    # Remove a potentially existing coverage file from a previous run for the\n    # same test configuration. Use a filename *not* starting with `.coverage.`,\n    # as coverage.py assumes ownership over these files and deleted them at\n    # will.\n    coverage_file = Path(\".cov.test.nosim\")\n    with suppress(FileNotFoundError):\n        coverage_file.unlink()\n\n    # Run pytest with the default configuration in setup.cfg.\n    session.log(\"Running simulator-agnostic tests with pytest\")\n    session.run(\n        \"pytest\",\n        \"-v\",\n        \"--cov=cocotb\",\n        \"--cov-branch\",\n        # Don't display coverage report here\n        \"--cov-report=\",\n        \"-k\",\n        \"not simulator_required\",\n    )\n\n    session.log(\"All tests passed!\")\n\n    # Rename the .coverage file to make it unique to the session.\n    Path(\".coverage\").rename(coverage_file)\n\n    session.log(f\"Stored Python coverage for this test run in {coverage_file}.\")\n\n\ndef dev_coverage_combine(session: nox.Session) -> None:\n    \"\"\"Combine coverage from previous dev_* runs into a .coverage file.\"\"\"\n\n    coverage_files = glob.glob(\"**/.cov.test.*\", recursive=True)\n    session.run(\"coverage\", \"combine\", *coverage_files)\n    assert Path(\".coverage\").is_file()\n\n    session.log(\"Wrote combined coverage database for all tests to '.coverage'.\")\n\n\n@nox_uv.session(\n    uv_groups=[\"coverage_report\"],\n    uv_no_install_project=True,\n    uv_sync_locked=False,\n)\ndef dev_coverage_report(session: nox.Session) -> None:\n    \"\"\"Report coverage results.\"\"\"\n\n    # combine coverage files from previous dev_test runs, if not already done\n    if not Path(\".coverage\").is_file():\n        dev_coverage_combine(session)\n\n    # Produce Cobertura XML coverage reports.\n    session.log(\"Producing Python and C/C++ coverage in Cobertura XML format\")\n\n    coverage_python_xml = Path(\".python_coverage.xml\")\n    session.run(\"coverage\", \"xml\", \"-o\", str(coverage_python_xml))\n    assert coverage_python_xml.is_file()\n\n    if session.posargs:\n        gcov_executable_args = [\n            \"--gcov-executable\",\n            session.posargs[0],\n        ]\n    else:\n        gcov_executable_args = []\n    coverage_cpp_xml = Path(\".cpp_coverage.xml\")\n    session.run(\n        \"gcovr\",\n        \"--cobertura\",\n        \"--output\",\n        str(coverage_cpp_xml),\n        \".\",\n        *gcov_executable_args,\n    )\n    assert coverage_cpp_xml.is_file()\n\n    session.log(\n        f\"Cobertura XML files written to {str(coverage_cpp_xml)!r} (C/C++) and {str(coverage_python_xml)!r} (Python)\"\n    )\n\n    # Report human-readable coverage.\n    session.log(\"Python coverage\")\n    session.run(\"coverage\", \"report\")\n\n    session.log(\"Library coverage\")\n    session.run(\n        \"gcovr\",\n        \"--print-summary\",\n        \"--txt\",\n        *gcov_executable_args,\n    )\n\n\n#\n# Release pipeline.\n#\n# - Clean out the dist directory.\n# - Build wheels (release builds).\n# - Install cocotb from wheel.\n# - Run tests against cocotb installed from the wheel.\n#\n# The release pipeline does not collect coverage, and does not run doctests.\n#\n\n# Directory containing the distribution artifacts (sdist and bdist).\ndist_dir = \"dist\"\n\n\n@nox_uv.session(\n    uv_no_install_project=True,\n    uv_groups=[],\n    uv_sync_locked=False,\n)\ndef release_clean(session: nox.Session) -> None:\n    \"\"\"Remove all build artifacts from the dist directory.\"\"\"\n    shutil.rmtree(dist_dir, ignore_errors=True)\n\n\n@nox_uv.session(\n    uv_no_install_project=True,\n    uv_groups=[\"release_build_wheel\"],\n    uv_sync_locked=False,\n)\ndef release_build_wheel(session: nox.Session) -> None:\n    \"\"\"Build a binary distribution (wheels) on the current operating system.\"\"\"\n\n    session.log(\"Building binary distributions (wheels)\")\n    session.run(\n        \"cibuildwheel\",\n        \"--output-dir\",\n        dist_dir,\n    )\n\n    session.log(f\"Binary distribution in release mode built into {dist_dir!r}\")\n\n\n@nox_uv.session(\n    uv_no_install_project=True,\n    uv_groups=[\"release_build_sdist\"],\n    uv_sync_locked=False,\n)\ndef release_build_sdist(session: nox.Session) -> None:\n    \"\"\"Build the source distribution.\"\"\"\n\n    session.log(\"Building source distribution (sdist)\")\n    session.run(\"python\", \"-m\", \"build\", \"--sdist\", \"--outdir\", dist_dir, \".\")\n\n    session.log(f\"Source distribution in release mode built into {dist_dir!r}\")\n\n\n@nox_uv.session(\n    uv_no_install_project=True,\n    uv_groups=[],\n    uv_sync_locked=False,\n)\ndef release_build(session: nox.Session) -> None:\n    \"\"\"Build all distributions for release.\"\"\"\n    session.notify(\"release_build_wheel\")\n    session.notify(\"release_build_sdist\")\n\n\ndef release_install_from_sdist(session: nox.Session) -> None:\n    \"\"\"Install cocotb from sdist.\"\"\"\n\n    # Find the sdist to install.\n    sdists = list(Path(dist_dir).glob(\"cocotb-*.tar.gz\"))\n    if not sdists:\n        session.error(\n            f\"No potential sdist found in the {dist_dir!r} directory. Run the 'release_build_sdist' session first!\"\n        )\n    elif len(sdists) > 1:\n        session.error(\n            f\"More than one potential sdist found in the {dist_dir!r} \"\n            f\"directory. Run the 'release_clean' session first!\"\n        )\n    sdist_path = sdists[0]\n    assert sdist_path.is_file()\n\n    session.log(\"Installing cocotb from sdist, which includes the build step\")\n    session.install(str(sdist_path))\n\n\n@nox_uv.session(\n    uv_no_install_project=True,\n    uv_groups=[\"release_test\"],\n    uv_sync_locked=False,\n)\n@nox.parametrize(\"sim,toplevel_lang,gpi_interface\", simulator_support_matrix())\n@nox.parametrize(\"source\", [\"wheel\", \"sdist\"])\ndef release_test(\n    session: nox.Session, sim: str, toplevel_lang: str, gpi_interface: str, source: str\n) -> None:\n    \"\"\"Run all tests against a cocotb release build.\"\"\"\n    if source == \"sdist\":\n        release_install_from_sdist(session)\n    else:\n        release_install_from_wheel(session)\n\n    session.log(\"Running cocotb-config as basic installation smoke test\")\n    session.run(\"cocotb-config\", \"--version\")\n    configure_test_env(session)\n    release_test_nosim(session)\n    release_test_sim(session, sim, toplevel_lang, gpi_interface)\n\n\ndef release_install_from_wheel(session: nox.Session) -> None:\n    \"\"\"Install cocotb from wheels.\"\"\"\n\n    wheels = list(Path(dist_dir).glob(\"cocotb-*.whl\"))\n    if not wheels:\n        session.error(\n            f\"No potential wheel found in the {dist_dir!r} directory. Run the 'release_build_wheel' session first!\"\n        )\n    session.log(f\"Installing cocotb from wheels in {dist_dir!r}\")\n    session.install(\n        \"--force-reinstall\",\n        \"--only-binary\",\n        \"cocotb\",\n        \"--no-index\",\n        \"--no-deps\",\n        \"--find-links\",\n        dist_dir,\n        \"cocotb\",\n    )\n\n    session.log(\"Running cocotb-config as basic installation smoke test\")\n    session.run(\"cocotb-config\", \"--version\")\n\n\ndef release_test_sim(\n    session: nox.Session, sim: str, toplevel_lang: str, gpi_interface: str\n) -> None:\n    \"\"\"Test a release version of cocotb against a simulator.\"\"\"\n\n    env = env_vars_for_sim_test(sim, toplevel_lang, gpi_interface)\n    config_str = stringify_dict(env)\n\n    session.log(f\"Running simulator-specific tests against a simulator {config_str}\")\n    session.run(\n        \"pytest\",\n        \"-v\",\n        \"-k\",\n        \"simulator_required\",\n        env=env,\n    )\n\n    session.log(f\"All tests passed with configuration {config_str}!\")\n\n\ndef release_test_nosim(session: nox.Session) -> None:\n    \"\"\"Run the simulator-agnostic tests against a cocotb release.\"\"\"\n\n    session.log(\"Running simulator-agnostic tests\")\n    session.run(\n        \"pytest\",\n        \"-v\",\n        \"-k\",\n        \"not simulator_required\",\n    )\n\n    session.log(\"All tests passed!\")\n\n\n#\n# Documentation sessions.\n#\n\n\n@nox_uv.session(\n    uv_groups=[\"docs\"],\n    uv_sync_locked=False,\n)\ndef docs(session: nox.Session) -> None:\n    \"\"\"invoke sphinx-build to build the HTML docs\"\"\"\n    outdir = session.cache_dir / \"docs_out\"\n    session.run(\n        \"sphinx-build\",\n        \"./docs/source\",\n        str(outdir),\n        \"--color\",\n        \"-b\",\n        \"html\",\n        *session.posargs,\n    )\n    index = (outdir / \"index.html\").resolve().as_uri()\n    session.log(f\"Documentation is available at {index}\")\n\n\n@nox_uv.session(\n    uv_groups=[\"docs_preview\"],\n    uv_sync_locked=False,\n)\ndef docs_preview(session: nox.Session) -> None:\n    \"\"\"Build a live preview of the documentation\"\"\"\n    outdir = session.cache_dir / \"docs_out\"\n    # fmt: off\n    session.run(\n        \"sphinx-autobuild\",\n        # Ignore directories which cause a rebuild loop.\n        \"--ignore\", \"*/source/master-notes.rst\",\n        \"--ignore\", \"*/doxygen/*\",\n        # Ignore nox's venv directory.\n        \"--ignore\", \".nox\",\n        # Ignore emacs backup files.\n        \"--ignore\", \"**/#*#\",\n        \"--ignore\", \"**/.#*\",\n        # Ignore vi backup files.\n        \"--ignore\", \"**/.*.sw[px]\",\n        \"--ignore\", \"**/*~\",\n        # FIXME: local to cmarqu :)\n        \"--ignore\", \"*@*:*\",\n        # Also watch the cocotb source directory to rebuild the API docs on\n        # changes to cocotb code.\n        \"--watch\", \"src/cocotb\",\n        \"./docs/source\",\n        str(outdir),\n        *session.posargs,\n    )\n    # fmt: on\n\n\n@nox_uv.session(\n    uv_groups=[\"docs\"],\n    uv_sync_locked=False,\n)\ndef docs_linkcheck(session: nox.Session) -> None:\n    \"\"\"invoke sphinx-build to linkcheck the docs\"\"\"\n    outdir = session.cache_dir / \"docs_out\"\n    session.run(\n        \"sphinx-build\",\n        \"./docs/source\",\n        str(outdir),\n        \"--color\",\n        \"-b\",\n        \"linkcheck\",\n        *session.posargs,\n    )\n\n\n@nox_uv.session(\n    uv_groups=[\"docs\"],\n    uv_sync_locked=False,\n)\ndef docs_spelling(session: nox.Session) -> None:\n    \"\"\"invoke sphinx-build to spellcheck the docs\"\"\"\n    outdir = session.cache_dir / \"docs_out\"\n    session.run(\n        \"sphinx-build\",\n        \"./docs/source\",\n        str(outdir),\n        \"--color\",\n        \"-b\",\n        \"spelling\",\n        *session.posargs,\n    )\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools>=77\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"cocotb\"\ndescription = \"Python-based chip (RTL) verification\"\nreadme = \"README.md\"\nlicense = \"BSD-3-Clause\"\nlicense-files = [\n    \"LICENSE\"\n]\nauthors = [\n    {name = \"Chris Higgs\"},\n    {name = \"Stuart Hodgson\"},\n]\nmaintainers = [\n    {name = \"Kaleb Barrett\"},\n    {name = \"Tomasz Hemperek\"},\n    {name = \"Marlon James\"},\n    {name = \"Colin Marquardt\"},\n    {name = \"Philipp Wagner\"},\n]\ndependencies = [\n    # For finding the libpython on the system so the GPI can preload it before\n    # embedding the Python interpreter.\n    \"find_libpython\",\n    # Backport of Python 3.11's ExceptionGroups that are thrown by TaskManager.\n    \"exceptiongroup; python_version < '3.11'\",\n    # For assertion rewriting, `raises` and `warns` context managers,\n    # `RaisesExc` and `RaisesGroup` test expected errors,\n    # `skip` and `xfail` functions for ending tests early,\n    # and for pytest plugin and test running functionality.\n    # Assertion rewriting interface changed in version 6.\n    \"pytest >= 6\",\n]\nrequires-python = \">= 3.9\"\nclassifiers = [\n    \"Programming Language :: Python :: 3\",\n    \"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)\",\n    \"Framework :: cocotb\",\n]\ndynamic = [\"version\"]\n\n[project.scripts]\ncocotb-config = \"cocotb_tools.config:main\"\n\n[project.urls]\nHomepage = \"https://www.cocotb.org\"\nDocumentation = \"https://docs.cocotb.org\"\nRepository = \"https://github.com/cocotb/cocotb\"\nIssues = \"https://github.com/cocotb/cocotb/issues\"\n\n\n[tool.towncrier]\n    package = \"cocotb\"\n    directory = \"docs/source/newsfragments\"\n    filename = \"docs/source/release_notes.rst\"\n    issue_format = \":pr:`{issue}`\"\n    # The first underline is used for the version/date header,\n    # the second underline for the subcategories (like 'Features')\n    underlines = [\"=\", \"-\"]\n    all_bullets = false\n\n    [[tool.towncrier.type]]\n        directory = \"feature\"\n        name = \"Features\"\n        showcontent = true\n\n    [[tool.towncrier.type]]\n        directory = \"bugfix\"\n        name = \"Bugfixes\"\n        showcontent = true\n\n    [[tool.towncrier.type]]\n        directory = \"doc\"\n        name = \"Improved Documentation\"\n        showcontent = true\n\n    [[tool.towncrier.type]]\n        directory = \"removal\"\n        name = \"Deprecations and Removals\"\n        showcontent = true\n\n    [[tool.towncrier.type]]\n        directory = \"change\"\n        name = \"Changes\"\n        showcontent = true\n\n[tool.ruff]\nextend-exclude = [\n    \"docs/source/conf.py\",\n    \"makefiles\",\n    \"venv\",\n    \"_vendor\",\n    \".nox/\",\n]\ntarget-version = \"py39\"\n\n[tool.ruff.format]\ndocstring-code-format = true\n\n[tool.ruff.lint]\nextend-select = [\n    \"I\",        # isort\n    \"UP\",       # pyupgrade\n    \"PL\",       # pylint\n    \"E\",        # pycodestyle errors\n    \"W\",        # pycodestyle warnings\n    \"F\",        # pyflakes\n    \"C4\",       # flake8-comprehension\n    \"LOG\",      # flake8-logging\n    \"G\",        # flake8-logging-format\n    \"ISC\",      # implicit string concat\n    \"TC\",       # flake8-typechecking\n    \"SIM103\",   # return the condition directly\n    \"SIM300\",   # yoda conditions\n    \"RUF100\",   # unused noqa\n    \"RUF101\",   # redirected noqa\n    \"RUF010\",   # explicit type conversion in f-string\n    \"RUF005\",   # collection literal concatenation\n    \"RUF022\",   # unsorted __all__\n    \"PERF101\",  # unnecessary list cast\n    \"PERF102\",  # unnecessary dict.items()\n    \"B007\",     # unused loop variable\n    \"PYI030\",   # unnecessary literal union\n]\nignore = [\n    \"E741\",    # ambiguous variable name (preference)\n    \"E501\",    # line too long (preference)\n    \"PLR0912\", # Too many branches (>12) (preference)\n    \"PLR0913\", # Too many arguments to function call (>5) (preference)\n    \"PLR0915\", # Too many statements (>50) (preference)\n    \"PLR2004\", # Magic value used in comparison (preference)\n    \"PLW0603\", # Using the global statement (preference)\n    \"PLR0911\", # Too many return statements (preference)\n    \"PLW1641\", # __eq__ without __hash__ (mypy compatibility)\n    # The following 3 are ignored because sphinx doesn't set TYPE_CHECKING,\n    # so it would fail to resolve any names imported in those blocks\n    \"TC001\",   # typing-only first party import\n    \"TC002\",   # typing-only third party import\n    \"TC003\",   # typing-only standard library import\n]\n\n[tool.ruff.lint.per-file-ignores]\n# necessary because of how file is included into documentation\n\"examples/doc_examples/quickstart/test_my_design.py\" = [\n    \"E402\",\n    \"F811\",\n]\n\n[tool.ruff.lint.isort]\nknown-first-party = [\n    \"cocotb\",\n    \"cocotb_tools\",\n    \"pygpi\",\n]\nknown-third-party = [\n    \"pytest\",\n]\nrequired-imports = [\"from __future__ import annotations\"]\n\n[tool.cibuildwheel]\n# Build for supported platforms only.\n#\n# - CPython on Linux x86_64 with glibc\n# - CPython on Windows x86_64\n# - CPython on macOS x86_64 and arm64\nbuild = \"cp*-manylinux_x86_64 cp*-win_amd64 cp*-macosx_x86_64 cp*-macosx_arm64\"\n\n# Build with optimizations and debugging\n# -O2   Enables reasonable optimizations. -O3 is unnecessary with the virtual-call-heavy code in the GPI and may bloat binary size.\n# -g    Generate standard debugging info.\n# -flto Enable LTO which can reduce binary size and improve inlining.\nenvironment = {CFLAGS = \"-O2 -g -flto\", CPPFLAGS = \"-O2 -g -flto\", LDFLAGS = \"-O2 -g -flto\"}\n\n# By default, build on manylinux2014 for compatibility with CentOS/RHEL 8+\n# and Ubuntu 20.04+ (with system Python).\nmanylinux-x86_64-image = \"manylinux2014\"\n\n# Build with optimizations and debugging (Windows)\n# /O2   Enables reasonable optimizations.\n# /Z7   Enables debugging and places info in the binary (/Zi puts debug info in a different file).\n# /Zo   Improves debugging when optimizations are also enabled.\n# /LTCG Enables LTO which can reduce binary size and improve inlining.\n[tool.cibuildwheel.windows]\nenvironment = {CL = \"/O2 /Z7 /Zo /LTCG\"}\n\n[tool.cibuildwheel.macos]\nrepair-wheel-command = \"delocate-wheel --no-sanitize-rpaths --require-archs {delocate_archs} -w {dest_dir} -v {wheel}\"\n\n[tool.pytest.ini_options]\n# Note: Do *not* add files within the cocotb/ tree here. Add them to the\n# noxfile instead.\ntestpaths = [\n    \"tests/pytest\",\n]\n\n# Ensure that all markers used in pytests are declared (in here).\naddopts = \"--strict-markers\"\n\nmarkers = [\n    \"simulator_required: mark tests as needing a simulator\",\n    \"compile: the compile step in runner-based tests\",\n]\n# log_cli = true\n# log_cli_level = DEBUG\n\n[tool.coverage.paths]\nsource = [\n    \"src/cocotb/\",\n    \".nox/**/cocotb/\",\n]\n\n[tool.coverage.report]\nomit = [\n    \"*/cocotb_tools/*\",\n    \"*/_vendor/*\",\n]\nexclude_lines = [\n    # copy-pasted from coveragepy source\n    # TODO when we can move to a newer version of coverage\n    \"#\\\\s*(pragma|PRAGMA)[:\\\\s]?\\\\s*(no|NO)\\\\s*(cover|COVER)\",\n    \"^\\\\s*(((async )?def .*?)?\\\\)(\\\\s*->.*?)?:\\\\s*)?\\\\.\\\\.\\\\.\\\\s*(#|$)\",\n    \"if (typing\\\\.)?TYPE_CHECKING:\",\n]\n\n[tool.codespell]\nignore-words-list = [\n    \"AFE\",\n    \"Synopsys\",\n    \"afe\",\n    \"afile\",\n    \"alog\",\n    \"ccompiler\",\n    \"datas\",\n    \"implementors\",\n    \"inout\",\n    \"nam\",\n    \"sting\",\n    \"synopsys\",\n]\n\nskip = [\"*.svg\"]\n\n[tool.mypy]\npython_version = \"3.11\"\npackages = [\"cocotb\", \"pygpi\", \"cocotb_tools.pytest\"]\nmodules = [\"noxfile\"]\ndisallow_untyped_defs = true\ndisallow_any_unimported = true\ndisallow_untyped_calls = true\ndisallow_untyped_decorators = true\nno_implicit_optional = true\nwarn_redundant_casts = true\nwarn_unused_ignores = true\nimplicit_reexport = false\nshow_error_codes = true\npretty = true\n\n# TODO add lower bounds and justifications\n[dependency-groups]\ndev = [\n    # required for development\n    \"nox\",\n    \"nox-uv\",\n    \"prek\",\n    # allows linting the project manually\n    \"clang-format\",\n    \"mypy>=1.18,!=1.20.*\",  # 1.18 needed for descriptor typing, 1.20 has type narrowing regressions\n    \"ruff\",\n    # allows running tests and doing coverage reporting manually if desired\n    {include-group = \"dev_test\"},\n    {include-group = \"coverage_report\"},\n]\ndocs = [\n    \"Sphinx ~= 8.2.0\",\n    \"breathe\",\n    \"sphinx-book-theme == 1.1.3\",  # pin this to exact version to guard against any CSS changes\n    \"sphinx-design >= 0.6.1\",\n    \"sphinxcontrib-svg2pdfconverter[CairoSVG]\",\n    \"sphinxcontrib-domaintools @ git+https://github.com/ktbarrett/domaintools.git\",\n    \"sphinxcontrib-makedomain\",\n    \"sphinxcontrib-spelling >= 5.3.0\",\n    \"pyenchant\",\n    \"sphinx-issues\",\n    \"sphinx-argparse-cli\",\n    \"towncrier\",\n    \"IPython\",\n    \"enum-tools[sphinx]\",\n    \"sphinx-codeautolink\",\n    \"sphinx-argparse\",\n    \"sphinx-autofixture\",\n    \"pytest\",\n]\ndocs_preview = [\n    {include-group = \"docs\"},\n    \"sphinx-autobuild\",\n]\nrelease_build_wheel = [\n    \"cibuildwheel==3.2.1\",\n]\nrelease_build_sdist = [\n    \"build\",\n]\ntest_common = [\n    \"pytest>=8.4\"  # need RaisesExc and RaisesGroup\n]\ndev_test = [\n    {include-group = \"test_common\"},\n    \"coverage[toml]>=7.2\",\n    \"pytest-cov\",\n]\ncoverage_report = [\n    \"coverage[toml]>=7.2\",\n    \"gcovr==8.4\",\n]\nrelease_test = [\n    {include-group = \"test_common\"},\n\n    # We have to disable the use of the PyPi index when installing cocotb to\n    # guarantee that the wheels in dist are being used. But without an index\n    # pip cannot find the dependencies, which need to be installed from PyPi.\n    # Work around that by explicitly installing the dependencies first from\n    # PyPi, and then installing cocotb itself from the local dist directory.\n    \"exceptiongroup; python_version<'3.11'\",\n    \"find_libpython\",\n]\n\n[tool.uv.dependency-groups]\n# We need Python 3.11 to run Sphinx 8.2 and cibuildwheel 3.2\ndocs = {requires-python = \">=3.11\"}\nrelease_build_wheel = {requires-python = \">=3.11\"}\n"
  },
  {
    "path": "setup.py",
    "content": "#!/usr/bin/env python\n# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport logging\nimport os\nimport subprocess\nimport sys\nfrom io import StringIO\nfrom os import path, walk\n\nfrom setuptools import find_packages, setup\n\n# Note: cocotb is not installed properly yet and is missing dependencies and binaries\n# We can still import other files next to setup.py, as long as they're in MANIFEST.in\n# The below line is necessary for PEP517 support\nsys.path.append(path.dirname(__file__))\n\nfrom cocotb_build_libs import build_ext, get_ext\n\n__version__ = \"2.1.0.dev0\"\n\n\nmax_python3_minor_version = 14\nif \"COCOTB_IGNORE_PYTHON_REQUIRES\" not in os.environ and sys.version_info >= (\n    3,\n    max_python3_minor_version + 1,\n):\n    raise RuntimeError(\n        f\"cocotb {__version__} only supports a maximum Python version of 3.{max_python3_minor_version}.\\n\"\n        \"You can suppress this error by defining the environment variable COCOTB_IGNORE_PYTHON_REQUIRES\\n\"\n        \"There is no guarantee cocotb will work with untested versions of Python and no support will be provided.\"\n    )\n\n\ndef package_files(directory):\n    paths = []\n    for fpath, _, filenames in walk(directory):\n        for filename in filenames:\n            paths.append(path.join(\"..\", \"..\", fpath, filename))\n    return paths\n\n\nif \"dev\" in __version__:\n    try:\n        rev = subprocess.check_output(\n            [\"git\", \"rev-parse\", \"--short\", \"HEAD\"], universal_newlines=True\n        ).strip()\n        # We add an 'r' to ensure this local version field is alphanumeric.\n        # Otherwise when a version is a number with leading 0s they will be stripped.\n        __version__ += f\"+r{rev}\"\n    except Exception:\n        pass\n\n\n# store log from build_libs and display at the end in verbose mode\n# see https://github.com/pypa/pip/issues/6634\nlog_stream = StringIO()\nhandler = logging.StreamHandler(log_stream)\nlog = logging.getLogger(\"cocotb_build_libs\")\nlog.setLevel(logging.INFO)\nlog.addHandler(handler)\n\nsetup(\n    cmdclass={\"build_ext\": build_ext},\n    version=__version__,\n    packages=find_packages(where=\"src\"),\n    package_dir={\"\": \"src\"},\n    package_data={\n        \"cocotb\": (\n            package_files(\"src/cocotb/share/include\")\n            + package_files(\"src/cocotb/share/def\")\n            + package_files(\"src/cocotb/share/lib/verilator\")\n        ),\n        \"cocotb_tools\": (package_files(\"src/cocotb_tools/makefiles\")),\n    },\n    ext_modules=get_ext(),\n)\n\nprint(log_stream.getvalue())\n"
  },
  {
    "path": "src/cocotb/_ANSI.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom cocotb._py_compat import StrEnum\n\n_ESCAPE = \"\\033[\"\n\n\nclass ANSI(StrEnum):\n    \"\"\"ANSI escape codes for coloring output.\n\n    The color names supported are ``[BRIGHT_]{BLACK|RED|GREEN|YELLOW|BLUE|MAGENTA|CYAN|WHITE}{_FG|_BG}``.\n\n    Variables that end in ``_FG`` will color the character or symbol (\"foreground\")\n    and variables that end in ``_BG`` will color the background.\n\n    Foreground and background colors can be combined together with a ``+``.\n    Setting a new foreground color will override the previous foreground, likewise with background colors.\n\n    Use ``DEFAULT_FG`` and ``DEFAULT_BG`` to reset the coloring to the default colors for the foreground and background, respectively.\n    Or use ``DEFAULT`` to reset both.\n    \"\"\"\n\n    DEFAULT_FG = _ESCAPE + \"39m\"\n    DEFAULT_BG = _ESCAPE + \"49m\"\n    DEFAULT = DEFAULT_BG + DEFAULT_FG\n\n    BLACK_FG = _ESCAPE + \"30m\"\n    RED_FG = _ESCAPE + \"31m\"\n    GREEN_FG = _ESCAPE + \"32m\"\n    YELLOW_FG = _ESCAPE + \"33m\"\n    BLUE_FG = _ESCAPE + \"34m\"\n    MAGENTA_FG = _ESCAPE + \"35m\"\n    CYAN_FG = _ESCAPE + \"36m\"\n    WHITE_FG = _ESCAPE + \"37m\"\n\n    BLACK_BG = _ESCAPE + \"40m\"\n    RED_BG = _ESCAPE + \"41m\"\n    GREEN_BG = _ESCAPE + \"42m\"\n    YELLOW_BG = _ESCAPE + \"43m\"\n    BLUE_BG = _ESCAPE + \"44m\"\n    MAGENTA_BG = _ESCAPE + \"45m\"\n    CYAN_BG = _ESCAPE + \"46m\"\n    WHITE_BG = _ESCAPE + \"47m\"\n\n    BRIGHT_BLACK_FG = _ESCAPE + \"90m\"\n    BRIGHT_RED_FG = _ESCAPE + \"91m\"\n    BRIGHT_GREEN_FG = _ESCAPE + \"92m\"\n    BRIGHT_YELLOW_FG = _ESCAPE + \"93m\"\n    BRIGHT_BLUE_FG = _ESCAPE + \"94m\"\n    BRIGHT_MAGENTA_FG = _ESCAPE + \"95m\"\n    BRIGHT_CYAN_FG = _ESCAPE + \"96m\"\n    BRIGHT_WHITE_FG = _ESCAPE + \"97m\"\n\n    BRIGHT_BLACK_BG = _ESCAPE + \"100m\"\n    BRIGHT_RED_BG = _ESCAPE + \"101m\"\n    BRIGHT_GREEN_BG = _ESCAPE + \"102m\"\n    BRIGHT_YELLOW_BG = _ESCAPE + \"103m\"\n    BRIGHT_BLUE_BG = _ESCAPE + \"104m\"\n    BRIGHT_MAGENTA_BG = _ESCAPE + \"105m\"\n    BRIGHT_CYAN_BG = _ESCAPE + \"106m\"\n    BRIGHT_WHITE_BG = _ESCAPE + \"107m\"\n"
  },
  {
    "path": "src/cocotb/__init__.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom logging import Logger\nfrom types import SimpleNamespace\n\nfrom cocotb._decorators import parametrize, skipif, test, xfail\nfrom cocotb._test_manager import create_task, end_test, pass_test, start, start_soon\nfrom cocotb.handle import SimHandleBase\n\nfrom ._version import __version__ as _version\n\n__all__ = (\n    \"RANDOM_SEED\",\n    \"SIM_NAME\",\n    \"SIM_VERSION\",\n    \"__version__\",\n    \"argv\",\n    \"create_task\",\n    \"end_test\",\n    \"is_simulation\",\n    \"log\",\n    \"packages\",\n    \"parametrize\",\n    \"pass_test\",\n    \"plusargs\",\n    \"skipif\",\n    \"start\",\n    \"start_soon\",\n    \"test\",\n    \"top\",\n    \"xfail\",\n)\n\n# Set __module__ on re-exports\nfor thing in [\n    test,\n    parametrize,\n    skipif,\n    xfail,\n    start_soon,\n    start,\n    create_task,\n    pass_test,\n    end_test,\n]:\n    thing.__module__ = __name__\n\n\n__version__: str = _version\n\"\"\"The version of cocotb.\"\"\"\n\n\nlog: Logger\n\"\"\"An easily accessible :class:`~logging.Logger` for the user.\n\nThis logger defaults to the :data:`logging.INFO` log level.\n\n.. versionchanged:: 2.0\n    This was previously the ``\"cocotb\"`` Logger.\n    It is now a Logger under the ``\"test\"`` namespace.\n\"\"\"\n\nargv: list[str]\n\"\"\"The argument list as seen by the simulator.\"\"\"\n\nplusargs: dict[str, bool | str]\n\"\"\"A dictionary of \"plusargs\" handed to the simulation.\n\nSee :envvar:`COCOTB_PLUSARGS` for details.\n\"\"\"\n\npackages: SimpleNamespace\n\"\"\"A :class:`python:types.SimpleNamespace` of package handles.\n\nThis will be populated with handles at test time if packages can be discovered\nvia the GPI.\n\n.. versionadded:: 2.0\n\"\"\"\n\nSIM_NAME: str\n\"\"\"The product information of the running simulator.\"\"\"\n\nSIM_VERSION: str\n\"\"\"The version of the running simulator.\"\"\"\n\nRANDOM_SEED: int\n\"\"\"The last value used to seed the global PRNG.\n\nDuring test collection, this is set to the value provided by :envvar:`COCOTB_RANDOM_SEED`,\nif given, or a random value based on the state of the operating system.\n\nDuring test run, this is set to a new value computed by combining the value used during test collection,\nwith the full test name (e.g. ``my_test_module.my_test``).\n\"\"\"\n\ntop: SimHandleBase\nr\"\"\"\nA handle to the :envvar:`COCOTB_TOPLEVEL` entity/module.\n\nThis is equivalent to the :term:`DUT` parameter given to cocotb tests, so it can be used wherever that variable can be used.\nIt is particularly useful for extracting information about the :term:`DUT` in module-level class and function definitions;\nand in parameters to :class:`.TestFactory`\\ s.\n\"\"\"\n\nis_simulation: bool = False\n\"\"\"``True`` if cocotb was loaded in a simulation.\"\"\"\n"
  },
  {
    "path": "src/cocotb/_base_triggers.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"A collection of triggers which a testbench can :keyword:`await`.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nimport sys\nimport warnings\nfrom abc import abstractmethod\nfrom collections.abc import Generator\nfrom contextlib import AbstractAsyncContextManager\nfrom functools import cached_property\nfrom typing import Callable\n\nfrom cocotb import debug\nfrom cocotb._deprecation import deprecated\nfrom cocotb._utils import pointer_str\n\nif sys.version_info >= (3, 11):\n    from typing import Self\n\n\nclass TriggerCallback:\n    \"\"\"A cancellable handle to a callback registered with a Trigger.\"\"\"\n\n    __slots__ = (\"_trigger\", \"_func\")\n\n    def __init__(\n        self,\n        trigger: Trigger,\n        func: Callable[..., object],\n    ) -> None:\n        self._trigger = trigger\n        self._func = func\n\n    def cancel(self) -> None:\n        self._trigger._deregister(self)\n\n    def _run(self) -> None:\n        self._func()\n\n    def __repr__(self) -> str:\n        return self._func.__name__\n\n\nclass Trigger:\n    \"\"\"A future event that a Task can wait upon.\"\"\"\n\n    def __init__(self) -> None:\n        self._callbacks: dict[TriggerCallback, None] = {}\n\n    @cached_property\n    def _log(self) -> logging.Logger:\n        return logging.getLogger(f\"cocotb.{type(self).__qualname__}.0x{id(self):x}\")\n\n    def _register(self, func: Callable[[], object]) -> TriggerCallback:\n        \"\"\"Add a callback to be called when the Trigger fires.\"\"\"\n        handle = TriggerCallback(self, func)\n        if debug.debug:\n            self._log.debug(\"Registering on %r: %r\", self, handle)\n        do_prime = not self._callbacks\n        self._callbacks[handle] = None\n        # *Must* call `_prime()` after adding callback in case `_prime()` immediately\n        # calls `_react()`\n        # TODO Don't allow `_prime()` to call `_react()`?\n        if do_prime:\n            self._prime()\n        return handle\n\n    def _deregister(self, callback: TriggerCallback) -> None:\n        \"\"\"Remove a callback from a Trigger before it fires.\"\"\"\n        if debug.debug:\n            self._log.debug(\"De-registering on %r: %r\", self, callback)\n        del self._callbacks[callback]\n        if not self._callbacks:\n            self._unprime()\n\n    def _do_callbacks(self) -> None:\n        callbacks, self._callbacks = self._callbacks, {}\n        for cb in callbacks:\n            if debug.debug:\n                self._log.debug(\"Running after %r: %r\", self, cb)\n            cb._run()\n\n    def _react(self) -> None:\n        \"\"\"Function called when a Trigger fires.\n\n        Expected to call ``_do_callbacks()`` and any cleanup of the underlying mechanism\n        required after it fires.\n        \"\"\"\n        if debug.debug:\n            self._log.debug(\"Fired %s\", self)\n        self._do_callbacks()\n\n    @abstractmethod\n    def _prime(self) -> None:\n        \"\"\"Enable the underlying mechanism for the Trigger to fire.\n\n        The underlying mechanism should call this Trigger's ``_react()`` when it fires.\n        \"\"\"\n\n    @abstractmethod\n    def _unprime(self) -> None:\n        \"\"\"Disable the underlying mechanism for the Trigger to fire.\"\"\"\n\n    def __await__(self) -> Generator[Self, None, Self]:\n        yield self\n        return self\n\n\nclass _Event(Trigger):\n    \"\"\"Unique instance used by the Event object.\n\n    One created for each attempt to wait on the event so that the scheduler\n    can maintain a unique mapping of triggers to tasks.\n    \"\"\"\n\n    _callback: Callable[[_Event], None]\n\n    def __init__(self, parent: Event) -> None:\n        super().__init__()\n        self._parent = parent\n\n    def _prime(self) -> None:\n        if self._parent.is_set():\n            # If the event is already set, we need to call the callback\n            # immediately, so we don't need to wait for the scheduler.\n            return self._react()\n\n    def _unprime(self) -> None:\n        pass\n\n    def __repr__(self) -> str:\n        return f\"<{self._parent!r}.wait() at {pointer_str(self)}>\"\n\n\nclass Event:\n    r\"\"\"A way to signal an event across :class:`~cocotb.task.Task`\\ s.\n\n    :keyword:`await`\\ ing the result of :meth:`wait()` will block the :keyword:`await`\\ ing :class:`~cocotb.task.Task`\n    until :meth:`set` is called.\n\n    Args:\n        name: Name for the Event.\n\n    Usage:\n        .. code-block:: python\n\n            e = Event()\n\n\n            async def task1():\n                await e.wait()\n                print(\"resuming!\")\n\n\n            cocotb.start_soon(task1())\n            # do stuff\n            e.set()\n            await NullTrigger()  # allows task1 to execute\n            # resuming!\n\n    .. versionremoved:: 2.0\n\n        Removed the undocumented *data* attribute and argument to :meth:`set`,\n        and the *name* attribute and argument to the constructor.\n    \"\"\"\n\n    def __init__(self, name: str | None = None) -> None:\n        self._event: _Event = _Event(self)\n        self._name: str | None = None\n        if name is not None:\n            warnings.warn(\n                \"The 'name' argument will be removed in a future release.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            self.name = name\n        self._fired: bool = False\n        self._data: object = None\n\n    @property\n    @deprecated(\"The 'name' field will be removed in a future release.\")\n    def name(self) -> str | None:\n        \"\"\"Name of the Event.\n\n        .. deprecated:: 2.0\n            The *name* field will be removed in a future release.\n        \"\"\"\n        return self._name\n\n    @name.setter\n    @deprecated(\"The 'name' field will be removed in a future release.\")\n    def name(self, new_name: str | None) -> None:\n        self._name = new_name\n\n    @property\n    @deprecated(\"The data field will be removed in a future release.\")\n    def data(self) -> object:\n        \"\"\"The data associated with the Event.\n\n        .. deprecated:: 2.0\n            The data field will be removed in a future release.\n            Use a separate variable to store the data instead.\n        \"\"\"\n        return self._data\n\n    @data.setter\n    @deprecated(\"The data field will be removed in a future release.\")\n    def data(self, new_data: object) -> None:\n        self._data = new_data\n\n    def set(self, data: object | None = None) -> None:\n        \"\"\"Set the Event and unblock all Tasks blocked on this Event.\"\"\"\n        self._fired = True\n        if data is not None:\n            warnings.warn(\n                \"The data field will be removed in a future release.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n        self._data = data\n        self._event._react()\n\n    def wait(self) -> Trigger:\n        \"\"\"Block the current Task until the Event is set.\n\n        If the event has already been set, the trigger will fire immediately.\n\n        To set the Event call :meth:`set`.\n        To reset the Event (and enable the use of :meth:`wait` again),\n        call :meth:`clear`.\n        \"\"\"\n        return self._event\n\n    def clear(self) -> None:\n        \"\"\"Clear this event that has been set.\n\n        Subsequent calls to :meth:`~cocotb.triggers.Event.wait` will block until\n        :meth:`~cocotb.triggers.Event.set` is called again.\n        \"\"\"\n        self._fired = False\n\n    def is_set(self) -> bool:\n        \"\"\"Return ``True`` if event has been set.\"\"\"\n        return self._fired\n\n    def __repr__(self) -> str:\n        if self._name is None:\n            fmt = \"<{0} at {2}>\"\n        else:\n            fmt = \"<{0} for {1} at {2}>\"\n        return fmt.format(type(self).__qualname__, self._name, pointer_str(self))\n\n\nclass _InternalEvent(Trigger):\n    \"\"\"Event used internally for triggers that need cross-:class:`~cocotb.task.Task` synchronization.\n\n    This Event can only be waited on once, by a single :class:`~cocotb.task.Task`.\n\n    Provides transparent :func`repr` pass-through to the :class:`Trigger` using this event,\n    providing a better debugging experience.\n    \"\"\"\n\n    def __init__(self, parent: object) -> None:\n        super().__init__()\n        self._parent = parent\n        self._fired: bool = False\n        self._awaited: bool = False\n\n    def _prime(self) -> None:\n        if self.is_set():\n            # If the event is already set, we need to call the callback\n            # immediately, so we don't need to wait for the scheduler.\n            return self._react()\n\n    def _unprime(self) -> None:\n        pass\n\n    def set(self) -> None:\n        \"\"\"Wake up coroutine blocked on this event.\"\"\"\n        self._fired = True\n        self._react()\n\n    def is_set(self) -> bool:\n        \"\"\"Return true if event has been set.\"\"\"\n        return self._fired\n\n    def __await__(\n        self,\n    ) -> Generator[Self, None, Self]:\n        if self._awaited:\n            raise RuntimeError(\"Only one Task may await this Trigger\")\n        self._awaited = True\n        return (yield from super().__await__())\n\n    def __repr__(self) -> str:\n        return repr(self._parent)\n\n\nclass _Lock(Trigger):\n    \"\"\"Unique instance used by the Lock object.\n\n    One created for each attempt to acquire the Lock so that the scheduler\n    can maintain a unique mapping of triggers to tasks.\n    \"\"\"\n\n    def __init__(self, parent: Lock) -> None:\n        super().__init__()\n        self._parent = parent\n\n    def _prime(self) -> None:\n        self._parent._prime_lock(self)\n\n    def _unprime(self) -> None:\n        self._parent._unprime_lock(self)\n\n    def __await__(self) -> Generator[Self, None, Self]:\n        if self._parent._is_used(self):\n            raise RuntimeError(\n                \"Lock.acquire() result can only be used by one task at a time\"\n            )\n        return (yield from super().__await__())\n\n    def __repr__(self) -> str:\n        return f\"<{self._parent!r}.acquire() at {pointer_str(self)}>\"\n\n\nclass Lock(AbstractAsyncContextManager[None]):\n    \"\"\"A mutual exclusion lock.\n\n    Guarantees fair scheduling.\n    Lock acquisition is given in order of attempted lock acquisition.\n\n    Usage:\n        By directly calling :meth:`acquire` and :meth:`release`.\n\n        .. code-block:: python\n\n            lock = Lock()\n            ...\n            await lock.acquire()\n            try:\n                # do some stuff\n                ...\n            finally:\n                lock.release()\n\n        Or...\n\n        .. code-block:: python\n\n            async with Lock():\n                # do some stuff\n                ...\n\n    .. versionchanged:: 1.4\n\n        The lock can be used as an asynchronous context manager in an\n        :keyword:`async with` statement\n    \"\"\"\n\n    def __init__(self, name: str | None = None) -> None:\n        self._pending_primed: list[_Lock] = []\n        self._name: str | None = None\n        if name is not None:\n            warnings.warn(\n                \"The 'name' argument will be removed in a future release.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            self._name = name\n        self._current_acquired: _Lock | None = None\n\n    @property\n    @deprecated(\"The 'name' field will be removed in a future release.\")\n    def name(self) -> str | None:\n        \"\"\"Name of the Lock.\n\n        .. deprecated:: 2.0\n            The *name* field will be removed in a future release.\n        \"\"\"\n        return self._name\n\n    @name.setter\n    @deprecated(\"The 'name' field will be removed in a future release.\")\n    def name(self, new_name: str | None) -> None:\n        self._name = new_name\n\n    def locked(self) -> bool:\n        \"\"\"Return ``True`` if the lock has been acquired.\n\n        .. versionchanged:: 2.0\n            This is now a method to match :meth:`asyncio.Lock.locked`, rather than an attribute.\n        \"\"\"\n        return self._current_acquired is not None\n\n    def _acquire_and_fire(self, lock: _Lock) -> None:\n        self._current_acquired = lock\n        lock._react()\n\n    def _prime_lock(self, lock: _Lock) -> None:\n        if self._current_acquired is None:\n            self._acquire_and_fire(lock)\n        else:\n            self._pending_primed.append(lock)\n\n    def _unprime_lock(self, lock: _Lock) -> None:\n        if lock in self._pending_primed:\n            self._pending_primed.remove(lock)\n\n    def _is_used(self, lock: _Lock) -> bool:\n        return lock is self._current_acquired or lock in self._pending_primed\n\n    def acquire(self) -> Trigger:\n        \"\"\"Produce a trigger which fires when the lock is acquired.\"\"\"\n        return _Lock(self)\n\n    def release(self) -> None:\n        \"\"\"Release the lock.\"\"\"\n        if self._current_acquired is None:\n            raise RuntimeError(f\"Attempt to release an unacquired Lock {self!s}\")\n\n        self._current_acquired = None\n\n        # nobody waiting for this lock\n        if not self._pending_primed:\n            return\n\n        lock = self._pending_primed.pop(0)\n        self._acquire_and_fire(lock)\n\n    def __repr__(self) -> str:\n        if self._name is None:\n            fmt = \"<{0} [{2} waiting] at {3}>\"\n        else:\n            fmt = \"<{0} for {1} [{2} waiting] at {3}>\"\n        return fmt.format(\n            type(self).__qualname__,\n            self._name,\n            len(self._pending_primed),\n            pointer_str(self),\n        )\n\n    async def __aenter__(self) -> None:\n        await self.acquire()\n\n    async def __aexit__(self, *args: object) -> None:\n        self.release()\n\n\nclass NullTrigger(Trigger):\n    \"\"\"Trigger that fires immediately.\n\n    Mostly useful when building or using higher-order functions which need to take or return Triggers.\n\n    The scheduling order of the Task awaiting this Trigger with respect to any other Task is not deterministic\n    and should generally not be relied upon.\n    Instead of using this Trigger to push the Task until \"after\" another Task has run,\n    use other synchronization techniques, such as using an :class:`.Event`.\n\n    **Do not** do this:\n\n    .. code-block:: python\n        :class: removed\n\n        transaction_data = None\n\n\n        def monitor(dut):\n            while dut.valid.value != 1 and dut.ready.value != 1:\n                await RisingEdge(dut.clk)\n            transaction_data = dut.data.value\n\n\n        def use_transaction(dut):\n            while True:\n                await RisingEdge(dut.clk)\n                # We need the NullTrigger here because both Tasks react to RisingEdge,\n                # but there's no guarantee about which Task is run first,\n                # so we need to force this one to run \"later\" using NullTrigger.\n                await NullTrigger()\n                if transaction_data is not None:\n                    process(transaction_data)\n\n\n        use_task = cocotb.start_soon(use_transaction(cocotb.top))\n        monitor_task = cocotb.start_soon(monitor(cocotb.top))\n\n    Instead use an :class:`!Event` to explicitly synchronize the two Tasks, like so:\n\n    .. code-block:: python\n        :class: new\n\n        transaction_data = None\n        transaction_event = Event()\n\n\n        def monitor(dut):\n            while dut.valid.value != 1 and dut.ready.value != 1:\n                await RisingEdge(dut.clk)\n            transaction_data = dut.data.value\n            transaction_event.set()\n\n\n        def use_transaction(dut):\n            # Now we don't need the NullTrigger.\n            # This Task will wake up *strictly* after `monitor_task` sets the transaction.\n            await transaction_event.wait()\n            process(transaction_data)\n\n\n        use_task = cocotb.start_soon(use_transaction(cocotb.top))\n        monitor_task = cocotb.start_soon(monitor(cocotb.top))\n\n    .. versionremoved:: 2.0\n        The *outcome* parameter was removed. There is no alternative.\n    \"\"\"\n\n    def __init__(self, name: str | None = None) -> None:\n        super().__init__()\n        self.name = name\n\n    def _prime(self) -> None:\n        self._react()\n\n    def _unprime(self) -> None:\n        pass\n\n    def __repr__(self) -> str:\n        if self.name is None:\n            fmt = \"<{0} at {2}>\"\n        else:\n            fmt = \"<{0} for {1} at {2}>\"\n        return fmt.format(type(self).__qualname__, self.name, pointer_str(self))\n"
  },
  {
    "path": "src/cocotb/_bridge.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport functools\nimport logging\nimport sys\nimport threading\nfrom bdb import BdbQuit\nfrom collections.abc import Coroutine\nfrom enum import IntEnum\nfrom typing import (\n    Any,\n    Callable,\n    Generic,\n    TypeVar,\n)\n\nimport cocotb\nfrom cocotb import debug\nfrom cocotb._base_triggers import Event, Trigger\nfrom cocotb._outcomes import Error, Outcome, Value, capture\n\nif sys.version_info >= (3, 10):\n    from typing import ParamSpec\n\n    P = ParamSpec(\"P\")\n\nResult = TypeVar(\"Result\")\n\n\ndef resume(\n    func: Callable[P, Coroutine[Trigger, None, Result]],\n) -> Callable[P, Result]:\n    \"\"\"Converts a coroutine function into a blocking function.\n\n    This allows a :term:`coroutine function` that awaits cocotb triggers to be\n    called from a :term:`blocking function` converted by :func:`.bridge`.\n    This completes the bridge through non-:keyword:`async` code.\n\n    When a converted coroutine function is called the current function blocks until the\n    converted function exits.\n\n    Results of the converted function are returned from the function call.\n\n    Args:\n        func: The :term:`coroutine function` to convert into a :term:`blocking function`.\n\n    Returns:\n        *func* as a :term:`blocking function`.\n\n    Raises:\n        RuntimeError:\n            If the function that is returned is subsequently called from a\n            thread that was not started with :class:`.bridge`.\n\n    .. versionchanged:: 2.0\n        Renamed from ``function``.\n        No longer implemented as a type.\n        The ``log`` attribute is no longer available.\n    \"\"\"\n\n    @functools.wraps(func)\n    def wrapper(*args: P.args, **kwargs: P.kwargs) -> Result:\n        return queue_function(func(*args, **kwargs))\n\n    return wrapper\n\n\ndef bridge(\n    func: Callable[P, Result],\n) -> Callable[P, Coroutine[Trigger, None, Result]]:\n    r\"\"\"Converts a blocking function into a coroutine function.\n\n    This function converts a :term:`blocking function` into a :term:`coroutine function`\n    with the expectation that the function being converted is intended to call a\n    :func:`.resume` converted function. This creates a bridge through\n    non-:keyword:`async` code for code wanting to eventually :keyword:`await` on cocotb\n    triggers.\n\n    When a converted function call is used in an :keyword:`await` statement, the current\n    Task blocks until the converted function finishes.\n\n    Results of the converted function are returned from the :keyword:`await` expression.\n\n    .. note::\n        Bridge threads *must* either finish or block on a :func:`.resume`\n        converted function before control is given back to the simulator.\n        This is done to prevent any code from executing in parallel with the simulation.\n\n    Args:\n        func: The :term:`blocking function` to convert into a :term:`coroutine function`.\n\n    Returns:\n        *func* as a :term:`coroutine function`.\n\n    .. versionchanged:: 2.0\n        Renamed from ``external``.\n        No longer implemented as a type.\n        The ``log`` attribute is no longer available.\n    \"\"\"\n\n    @functools.wraps(func)\n    def wrapper(*args: P.args, **kwargs: P.kwargs) -> Coroutine[Trigger, None, Result]:\n        return run_in_executor(func, *args, **kwargs)\n\n    return wrapper\n\n\nclass external_state(IntEnum):\n    INIT = 0\n    RUNNING = 1\n    PAUSED = 2\n    EXITED = 3\n\n\nclass external_waiter(Generic[Result]):\n    def __init__(self) -> None:\n        self._outcome: Outcome[Result] | None = None\n        self.thread: threading.Thread\n        self.event = Event()\n        self.state = external_state.INIT\n        self.cond = threading.Condition()\n        self._log = logging.getLogger(f\"cocotb.bridge.0x{id(self):x}\")\n\n    @property\n    def result(self) -> Result:\n        if self._outcome is None:\n            raise RuntimeError(\"Got result of external before it finished\")\n        return self._outcome.get()\n\n    def _propagate_state(self, new_state: external_state) -> None:\n        with self.cond:\n            if debug.debug:\n                self._log.debug(\n                    f\"Changing state from {self.state} -> {new_state} from {threading.current_thread()}\"\n                )\n            self.state = new_state\n            self.cond.notify()\n\n    def thread_done(self) -> None:\n        if debug.debug:\n            self._log.debug(f\"Thread finished from {threading.current_thread()}\")\n        self._propagate_state(external_state.EXITED)\n\n    def thread_suspend(self) -> None:\n        self._propagate_state(external_state.PAUSED)\n\n    def thread_start(self) -> None:\n        if self.state > external_state.INIT:\n            return\n\n        if not self.thread.is_alive():\n            self._propagate_state(external_state.RUNNING)\n            self.thread.start()\n\n    def thread_resume(self) -> None:\n        self._propagate_state(external_state.RUNNING)\n\n    def thread_wait(self) -> external_state:\n        if debug.debug:\n            self._log.debug(\n                f\"Waiting for the condition lock {threading.current_thread()}\"\n            )\n\n        with self.cond:\n            while self.state == external_state.RUNNING:\n                self.cond.wait()\n\n            if debug.debug:\n                if self.state == external_state.EXITED:\n                    self._log.debug(\n                        f\"Thread {self.thread} has exited from {threading.current_thread()}\"\n                    )\n                elif self.state == external_state.PAUSED:\n                    self._log.debug(\n                        f\"Thread {self.thread} has called yield from {threading.current_thread()}\"\n                    )\n\n            if self.state == external_state.INIT:\n                raise Exception(\n                    f\"Thread {self.thread} state was not allowed from {threading.current_thread()}\"\n                )\n\n        return self.state\n\n\npending_threads: list[external_waiter[Any]] = []\n\n\ndef queue_function(task: Coroutine[Trigger, None, Result]) -> Result:\n    \"\"\"Queue *task* for execution and switch back to main thread.\"\"\"\n    # We should be able to find ourselves inside the pending_threads list\n    matching_threads = [\n        t for t in pending_threads if t.thread == threading.current_thread()\n    ]\n    if len(matching_threads) == 0:\n        raise RuntimeError(\"queue_function called from unrecognized thread\")\n\n    # Raises if there is more than one match. This can never happen, since\n    # each entry always has a unique thread.\n    (t,) = matching_threads\n\n    outcome: Outcome[Result] | None = None\n\n    async def wrapper() -> None:\n        nonlocal outcome\n        # This function runs in the scheduler thread\n        try:\n            outcome = Value(await task)\n        except (KeyboardInterrupt, SystemExit, BdbQuit):\n            # Allow these to bubble up to the execution root to fail the sim immediately.\n            # This follows asyncio's behavior.\n            raise\n        except BaseException as e:\n            outcome = Error(e)\n        # Notify the current (scheduler) thread that we are about to wake\n        # up the background (`@external`) thread, making sure to do so\n        # before the background thread gets a chance to go back to sleep by\n        # calling thread_suspend.\n        # We need to do this here in the scheduler thread so that no more\n        # tasks run until the background thread goes back to sleep.\n        t.thread_resume()\n        event.set()\n\n    event = threading.Event()\n    # must register this with test as there's no way to clean up with threading\n    cocotb.start_soon(wrapper())\n    # The scheduler thread blocks in `thread_wait`, and is woken when we\n    # call `thread_suspend` - so we need to make sure the task is\n    # queued before that.\n    t.thread_suspend()\n    # This blocks the calling `@external` thread until the task finishes\n    event.wait()\n    assert outcome is not None\n    return outcome.get()\n\n\ndef run_in_executor(\n    func: Callable[P, Result], *args: P.args, **kwargs: P.kwargs\n) -> Coroutine[Trigger, None, Result]:\n    \"\"\"Run the task in a separate execution thread and return an awaitable object for the caller.\"\"\"\n    # Create a thread\n    # Create a trigger that is called as a result of the thread finishing\n    # Create an Event object that the caller can await on\n    # Event object set when the thread finishes execution, this blocks the\n    # calling task (but not the thread) until the external completes\n\n    waiter = external_waiter[Result]()\n\n    def execute_external() -> None:\n        waiter._outcome = capture(func, *args, **kwargs)\n        waiter.thread_done()\n\n    async def wrapper() -> Result:\n        thread = threading.Thread(\n            group=None,\n            target=execute_external,\n            name=func.__qualname__ + \"_thread\",\n        )\n\n        waiter.thread = thread\n        pending_threads.append(waiter)\n\n        await waiter.event.wait()\n\n        return waiter.result  # raises if there was an exception\n\n    return wrapper()\n\n\ndef run_bridge_threads() -> None:\n    \"\"\"Progresses the state of all pending threads.\"\"\"\n    # TODO Incorporate all this into a Task-like class which does the following as part\n    # of its resume() so we don't have to call this function as part of the main event\n    # loop.\n\n    # We do not return from here until pending threads have completed, but only\n    # from the main thread, this seems like it could be problematic in cases\n    # where a sim might change what this thread is.\n\n    for ext in pending_threads:\n        ext.thread_start()\n        if debug.debug:\n            ext._log.debug(\n                \"Blocking from %s on %s\",\n                threading.current_thread(),\n                ext.thread,\n            )\n        state = ext.thread_wait()\n        if debug.debug:\n            ext._log.debug(\n                \"Back from wait on self %s with newstate %s\",\n                threading.current_thread(),\n                state,\n            )\n        if state == external_state.EXITED:\n            pending_threads.remove(ext)\n            ext.event.set()\n"
  },
  {
    "path": "src/cocotb/_concurrent_waiters.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nfrom __future__ import annotations\n\nimport sys\nfrom asyncio import CancelledError\nfrom typing import TYPE_CHECKING, Any, Literal, TypeVar, overload\n\nimport cocotb\nfrom cocotb._base_triggers import Event\nfrom cocotb.task import Task\n\nif TYPE_CHECKING:\n    from collections.abc import Awaitable\n\nif sys.version_info >= (3, 10):\n    from typing import TypeAlias\n\nReturnWhenType: TypeAlias = Literal[\n    \"FIRST_COMPLETED\", \"FIRST_EXCEPTION\", \"ALL_COMPLETED\"\n]\n\nT = TypeVar(\"T\")\nT2 = TypeVar(\"T2\")\nT3 = TypeVar(\"T3\")\nT4 = TypeVar(\"T4\")\n\n\n@overload\nasync def wait(\n    a: Awaitable[T],\n    /,\n    *,\n    return_when: ReturnWhenType,\n) -> tuple[Task[T]]: ...\n\n\n@overload\nasync def wait(\n    a: Awaitable[T],\n    b: Awaitable[T2],\n    /,\n    *,\n    return_when: ReturnWhenType,\n) -> tuple[Task[T], Task[T2]]: ...\n\n\n@overload\nasync def wait(\n    a: Awaitable[T],\n    b: Awaitable[T2],\n    c: Awaitable[T3],\n    /,\n    *,\n    return_when: ReturnWhenType,\n) -> tuple[Task[T], Task[T2], Task[T3]]: ...\n\n\n@overload\nasync def wait(\n    a: Awaitable[T],\n    b: Awaitable[T2],\n    c: Awaitable[T3],\n    d: Awaitable[T4],\n    /,\n    *,\n    return_when: ReturnWhenType,\n) -> tuple[Task[T], Task[T2], Task[T3], Task[T4]]: ...\n\n\n@overload\nasync def wait(\n    *aw: Awaitable[T], return_when: ReturnWhenType\n) -> tuple[Task[T], ...]: ...\n\n\nasync def wait(\n    *awaitables: Awaitable[Any], return_when: ReturnWhenType\n) -> tuple[Task[Any], ...]:\n    r\"\"\"Await on all given *awaitables* concurrently and block until the *return_when* condition is met.\n\n    Every :class:`~collections.abc.Awaitable` given to the function is :keyword:`await`\\ ed concurrently in its own :class:`~cocotb.task.Task`.\n    When the return conditions specified by *return_when* are met, this function returns those :class:`!Task`\\ s.\n    Once the return conditions are met, any waiter tasks which are still running are cancelled.\n    This does not cancel :class:`~cocotb.task.Task`\\ s passed as arguments, only the waiter tasks.\n\n    The *return_when* condition must be one of the following:\n\n    - ``\"FIRST_COMPLETED\"``: Returns after the first of the *awaitables* completes, regardless if that was due to an exception or not.\n    - ``\"FIRST_EXCEPTION\"``: Returns after all *awaitables* complete or after the first *awaitable* that completes due to an exception.\n    - ``\"ALL_COMPLETED\"``: Returns after all *awaitables* complete.\n\n    Args:\n        awaitables: The :class:`~collections.abc.Awaitable`\\ s to concurrently :keyword:`!await` upon.\n        return_when:\n            The condition that must be met before returning.\n            One of ``\"FIRST_COMPLETED\"``, ``\"FIRST_EXCEPTION\"``, or ``\"ALL_COMPLETED\"``.\n\n    Returns:\n        A tuple of waiter :class:`~cocotb.task.Task`\\ s.\n        The order of the return tuple corresponds to the order of the input.\n\n    .. versionadded:: 2.1\n    \"\"\"\n\n    async def waiter(aw: Awaitable[T]) -> T:\n        return await aw\n\n    tasks = tuple(Task[Any](waiter(a)) for a in awaitables)\n\n    # Event which is set by done_callback when return condition is met.\n    done = Event()\n\n    # order of cancellation may matter, so we use dict(), which is ordered unlike set()\n    remaining = dict.fromkeys(tasks)\n\n    # Cancel all remaining tasks.\n    # Use a flag to prevent multiple cancellation.\n    cancelled: bool = False\n\n    def cancel() -> None:\n        nonlocal cancelled\n        if cancelled:\n            return\n\n        cancelled = True\n        for t in remaining:\n            t.cancel()\n\n    # Define done_callbacks which set the \"done\" Event when the return condition is met.\n    if return_when == \"FIRST_COMPLETED\":\n\n        def done_callback(task: Task[Any]) -> None:\n            del remaining[task]\n            if not remaining:\n                done.set()\n            else:\n                # Cancel remaining before they have a chance to resume.\n                cancel()\n\n    elif return_when == \"FIRST_EXCEPTION\":\n\n        def done_callback(task: Task[Any]) -> None:\n            del remaining[task]\n            if not remaining:\n                done.set()\n            elif not task.cancelled() and task.exception() is not None:\n                # Cancel remaining before they have a chance to resume.\n                cancel()\n\n    else:\n\n        def done_callback(task: Task[Any]) -> None:\n            del remaining[task]\n            if not remaining:\n                done.set()\n\n    # Register done_callback to all waiter tasks.\n    for task in tasks:\n        task._add_done_callback(done_callback)\n        cocotb.start_soon(task)\n\n    try:\n        await done.wait()\n    except CancelledError:\n        # Cancel waiter tasks if this coroutine was cancelled.\n        for task in tasks:\n            task.cancel()\n        raise\n\n    return tasks\n\n\n@overload\nasync def select(\n    *awaitables: Awaitable[T], return_exception: Literal[False] = False\n) -> tuple[int, T]: ...\n\n\n@overload\nasync def select(\n    *awaitables: Awaitable[T], return_exception: Literal[True]\n) -> tuple[int, T | BaseException]: ...\n\n\nasync def select(\n    *awaitables: Awaitable[T], return_exception: bool = False\n) -> tuple[int, T | BaseException]:\n    r\"\"\"Await on all given *awaitables* concurrently and return the index and result of the first to complete.\n\n    After the first *awaitable* completes, the remaining waiter tasks are cancelled.\n    This does not cancel :class:`~cocotb.task.Task`\\ s passed as arguments,\n    only the internal waiter tasks.\n\n    Args:\n        awaitables: The :class:`~collections.abc.Awaitable`\\ s to concurrently :keyword:`!await` upon.\n        return_exception:\n            If ``False`` (default), re-raises the exception when an *awaitable* results in an exception.\n            If ``True``, returns the exception rather than re-raising when an *awaitable* results in an exception.\n\n    Returns:\n        A tuple comprised of the index into the argument list (0-based) of the first *awaitable* to complete, and the *awaitable*'s result.\n\n    Raises:\n        ValueError: If no *awaitables* are provided.\n\n    .. versionadded:: 2.1\n    \"\"\"\n    if len(awaitables) == 0:\n        raise ValueError(\"At least one awaitable required\")\n\n    tasks = await wait(*awaitables, return_when=\"FIRST_COMPLETED\")\n\n    # Find which awaitable completed.\n    idx: int\n    for i, task in enumerate(tasks):\n        if task.done() and not task.cancelled():\n            idx = i\n            break\n    else:  # pragma: no cover\n        raise RuntimeError(\"Reached unreachable code section\")\n\n    if return_exception and (exc := task.exception()) is not None:\n        return idx, exc\n    else:\n        return idx, task.result()\n\n\n@overload\nasync def gather(\n    a: Awaitable[T],\n    /,\n    *,\n    return_exceptions: Literal[False] = False,\n) -> tuple[T]: ...\n\n\n@overload\nasync def gather(\n    a: Awaitable[T],\n    b: Awaitable[T2],\n    /,\n    *,\n    return_exceptions: Literal[False] = False,\n) -> tuple[T, T2]: ...\n\n\n@overload\nasync def gather(\n    a: Awaitable[T],\n    b: Awaitable[T2],\n    c: Awaitable[T3],\n    /,\n    *,\n    return_exceptions: Literal[False] = False,\n) -> tuple[T, T2, T3]: ...\n\n\n@overload\nasync def gather(\n    a: Awaitable[T],\n    b: Awaitable[T2],\n    c: Awaitable[T3],\n    d: Awaitable[T4],\n    /,\n    *,\n    return_exceptions: Literal[False] = False,\n) -> tuple[T, T2, T3, T4]: ...\n\n\n@overload\nasync def gather(\n    *aw: Awaitable[T], return_exceptions: Literal[False] = False\n) -> tuple[T, ...]: ...\n\n\n@overload\nasync def gather(\n    *aw: Awaitable[T], return_exceptions: Literal[True]\n) -> tuple[T | BaseException, ...]: ...\n\n\nasync def gather(\n    *awaitables: Awaitable[Any],\n    return_exceptions: bool = False,\n) -> tuple[Any, ...]:\n    r\"\"\"Await on all given *awaitables* concurrently and return their results once all have completed.\n\n    After the return condition, based on *return_exceptions*, is met, the remaining waiter tasks are cancelled.\n    This does not cancel :class:`~cocotb.task.Task`\\ s passed as arguments,\n    only the internal waiter tasks.\n\n    Args:\n        awaitables: The :class:`~collections.abc.Awaitable`\\ s to concurrently :keyword:`!await` upon.\n        return_exceptions:\n            If ``False`` (default), after the first *awaitable* results in an exception, cancels the remaining *awaitables* and re-raises the exception.\n            If ``True``, returns the exception rather than the result value when an *awaitable* results in an exception.\n\n    Returns:\n        A tuple of the results of awaiting each *awaitable* in the same order they were given.\n        The order of the return tuple corresponds to the order of the input.\n\n    .. versionadded:: 2.1\n    \"\"\"\n    if len(awaitables) == 0:\n        return ()\n\n    tasks = await wait(\n        *awaitables,\n        return_when=\"ALL_COMPLETED\" if return_exceptions else \"FIRST_EXCEPTION\",\n    )\n    if return_exceptions:\n        # We now know there were no cancelled Tasks, so get all exceptions or results.\n        return tuple(\n            exc if (exc := task.exception()) is not None else task.result()\n            for task in tasks\n        )\n    else:\n        # Find first error if there is one.\n        for task in tasks:\n            if not task.cancelled() and (exc := task.exception()) is not None:\n                raise exc\n        # We now know there were no cancelled Tasks and no exceptions, so get all results.\n        return tuple(task.result() for task in tasks)\n"
  },
  {
    "path": "src/cocotb/_decorators.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport inspect\nimport sys\nfrom collections.abc import Coroutine, Iterable, Mapping, Sequence\nfrom enum import Enum\nfrom itertools import product\nfrom typing import Any, Callable, cast, overload\n\nfrom cocotb._base_triggers import Trigger\nfrom cocotb.simtime import TimeUnit\n\nif sys.version_info >= (3, 10):\n    from typing import TypeAlias\n\nimport pytest\n\n\nclass Test:\n    \"\"\"A cocotb test in a regression.\n\n    Args:\n        func:\n            The test function object.\n\n        args:\n            Positional arguments to pass to the test function.\n\n        kwargs:\n            Keyword arguments to pass to the test function.\n\n        name:\n            The name of the test function.\n\n        module:\n            The name of the module containing the test function.\n\n        doc:\n            The docstring for the test.\n\n        timeout:\n            Simulation time duration before the test is forced to fail with a :exc:`~cocotb.triggers.SimTimeoutError`.\n            A tuple of the timeout value and unit.\n            Accepts any unit that :class:`~cocotb.triggers.Timer` does.\n\n        expect_fail:\n            If ``True`` and the test fails a functional check via an :keyword:`assert` statement, :func:`pytest.raises`,\n            :func:`pytest.warns`, or :func:`pytest.deprecated_call`, the test is considered to have passed.\n            If ``True`` and the test passes successfully, the test is considered to have failed.\n\n        expect_error:\n            Mark the result as a pass only if one of the given exception types is raised in the test.\n\n        skip:\n            Don't execute this test as part of the regression.\n            The test can still be run manually by setting :envvar:`COCOTB_TESTCASE`.\n\n        stage:\n            Order tests logically into stages.\n            Tests from earlier stages are run before tests from later stages.\n    \"\"\"\n\n    # TODO Replace with dataclass in Python 3.7+\n\n    def __init__(\n        self,\n        *,\n        func: Callable[..., Coroutine[Trigger, None, None]],\n        args: Sequence[Any],\n        kwargs: Mapping[str, Any],\n        name: str,\n        module: str,\n        doc: str | None,\n        timeout: tuple[float, TimeUnit] | None,\n        expect_fail: bool,\n        expect_error: tuple[\n            type[BaseException] | pytest.RaisesExc | pytest.RaisesGroup,\n            ...,\n        ],\n        skip: bool,\n        stage: int,\n    ) -> None:\n        self.func = func\n        self.args = args\n        self.kwargs = kwargs\n        self.name = name\n        self.module = module\n        self.doc = doc\n        self.timeout = timeout\n        self.expect_fail = expect_fail\n        self.expect_error = expect_error\n        self.skip = skip\n        self.stage = stage\n        self.included = not skip\n\n    @property\n    def fullname(self) -> str:\n        return f\"{self.module}.{self.name}\"\n\n\nTestFuncType: TypeAlias = Callable[..., Coroutine[Trigger, None, None]]\n\n\nclass TestGenerator:\n    def __init__(\n        self,\n        func: TestFuncType,\n    ) -> None:\n        self.func: TestFuncType = func\n        self.timeout: tuple[float, TimeUnit] | None = None\n        self.expect_fail: bool = False\n        self.expect_error: set[\n            type[BaseException] | pytest.RaisesExc | pytest.RaisesGroup\n        ] = set()\n        self.skip = False\n        self.stage = 0\n        self.name = self.func.__qualname__\n        self.module = self.func.__module__\n        self.doc = self.func.__doc__\n        if self.doc is not None:\n            # cleanup docstring using `trim` function from PEP257\n            self.doc = inspect.cleandoc(self.doc)\n        self.options: list[\n            tuple[str, Sequence[object]]\n            | tuple[Sequence[str], Sequence[Sequence[object]]]\n        ] = []\n\n    def generate_tests(self) -> Iterable[Test]:\n        option_reprs: dict[str, list[str]] = {}\n\n        for name, values in self.options:\n            if isinstance(name, str):\n                option_reprs[name] = _reprs(values)\n            else:\n                # transform to Dict[name, values]\n                transformed: dict[str, list[object]] = {}\n                for nam_idx, nam in enumerate(name):\n                    transformed[nam] = []\n                    for value_array in cast(\"Sequence[Sequence[object]]\", values):\n                        value = value_array[nam_idx]\n                        transformed[nam].append(value)\n                for n, vs in transformed.items():\n                    option_reprs[n] = _reprs(vs)\n\n        # this value is a list of ranges of the same length as each set of values in self.options for passing to itertools.product\n        option_indexes = [range(len(option[1])) for option in self.options]\n\n        # go through the cartesian product of all values of all options\n        for selected_options in product(*option_indexes):\n            test_kwargs: dict[str, object] = {}\n            test_name_pieces: list[str] = [self.name]\n            for option_idx, select_idx in enumerate(selected_options):\n                option_name, option_values = self.options[option_idx]\n                selected_value = option_values[select_idx]\n\n                if isinstance(option_name, str):\n                    # single params per option\n                    selected_value = cast(\"Sequence[object]\", selected_value)\n                    test_kwargs[option_name] = selected_value\n                    test_name_pieces.append(\n                        f\"/{option_name}={option_reprs[option_name][select_idx]}\"\n                    )\n                else:\n                    # multiple params per option\n                    selected_value = cast(\"Sequence[object]\", selected_value)\n                    for n, v in zip(option_name, selected_value):\n                        test_kwargs[n] = v\n                        test_name_pieces.append(f\"/{n}={option_reprs[n][select_idx]}\")\n\n            parametrized_test_name = \"\".join(test_name_pieces)\n\n            yield Test(\n                func=self.func,\n                args=(),\n                kwargs=test_kwargs,\n                name=parametrized_test_name,\n                module=self.module,\n                doc=self.doc,\n                timeout=self.timeout,\n                expect_fail=self.expect_fail,\n                expect_error=tuple(self.expect_error),\n                skip=self.skip,\n                stage=self.stage,\n            )\n\n\ndef _reprs(values: Sequence[object]) -> list[str]:\n    result: list[str] = []\n    for value in values:\n        value_repr = _repr(value)\n        if value_repr is None:\n            # non-representable value in option, so default to index strings and give up\n            return [str(i) for i in range(len(values))]\n        else:\n            result.append(value_repr)\n    return result\n\n\ndef _repr(v: object) -> str | None:\n    if isinstance(v, Enum):\n        return v.name\n    elif isinstance(v, str):\n        if len(v) <= 10 and v.isidentifier():\n            return v\n        else:\n            return None\n    elif isinstance(v, (int, float, bool, type(None))):\n        return repr(v)\n    elif isinstance(v, type):\n        return v.__qualname__\n    elif hasattr(v, \"__qualname__\"):\n        return v.__qualname__\n    else:\n        return None\n\n\n@overload\ndef test(obj: TestFuncType | TestGenerator) -> TestGenerator: ...\n\n\n@overload\ndef test(\n    *,\n    timeout_time: float | None = None,\n    timeout_unit: TimeUnit = \"step\",\n    expect_fail: bool = False,\n    expect_error: type[BaseException] | tuple[type[BaseException], ...] = (),\n    skip: bool = False,\n    stage: int = 0,\n    name: str | None = None,\n) -> Callable[[TestFuncType | TestGenerator], TestGenerator]: ...\n\n\ndef test(\n    obj: TestFuncType | TestGenerator | None = None,\n    *,\n    timeout_time: float | None = None,\n    timeout_unit: TimeUnit = \"step\",\n    expect_fail: bool | None = None,\n    expect_error: type[BaseException] | tuple[type[BaseException], ...] | None = None,\n    skip: bool | None = None,\n    stage: int | None = None,\n    name: str | None = None,\n) -> TestGenerator | Callable[[TestFuncType | TestGenerator], TestGenerator]:\n    r\"\"\"\n    Decorator to register a Callable which returns a Coroutine as a test.\n\n    The test decorator provides a test timeout, and allows us to mark tests as skipped or expecting errors or failures.\n    Tests are evaluated in the order they are defined in a test module.\n\n    Usage:\n        .. code-block:: python\n\n            @cocotb.test(timeout_time=10, timeout_unit=\"ms\")\n            async def test_thing(dut): ...\n\n    Args:\n        timeout_time:\n            Simulation time duration before timeout occurs.\n\n            .. versionadded:: 1.3\n\n            .. note::\n                Test timeout is intended for protection against deadlock.\n                Users should use :class:`~cocotb.triggers.with_timeout` if they require a\n                more general-purpose timeout mechanism.\n\n        timeout_unit:\n            Units of timeout_time, accepts any units that :class:`~cocotb.triggers.Timer` does.\n\n            .. versionadded:: 1.3\n\n            .. versionchanged:: 2.0\n                Passing ``None`` as the *timeout_unit* argument was removed, use ``'step'`` instead.\n\n        expect_fail:\n            If ``True`` and the test fails a functional check via an :keyword:`assert` statement, :class:`pytest.raises`,\n            :class:`pytest.warns`, or :class:`pytest.deprecated_call` the test is considered to have passed.\n            If ``True`` and the test passes successfully, the test is considered to have failed.\n\n        expect_error:\n            Mark the result as a pass only if one of the exception types is raised in the test.\n            This is primarily for cocotb internal regression use for when a simulator error is expected.\n\n            Users are encouraged to use the following idiom instead::\n\n                @cocotb.test()\n                async def my_test(dut):\n                    try:\n                        await thing_that_should_fail()\n                    except ExceptionIExpect:\n                        pass\n                    else:\n                        assert False, \"Exception did not occur\"\n\n            .. versionchanged:: 1.3\n                Specific exception types can be expected\n\n            .. versionchanged:: 2.0\n                Passing a :class:`bool` value was removed.\n                Pass a specific :class:`Exception` or a tuple of Exceptions instead.\n\n        skip:\n            Don't execute this test as part of the regression. Test can still be run\n            manually by setting :make:var:`COCOTB_TESTCASE`.\n\n        stage:\n            Order tests logically into stages, where multiple tests can share a stage.\n            Defaults to 0.\n\n        name:\n            Override the default name of the test.\n            The default test name is the :meth:`__qualname__` of the decorated test function.\n\n            .. versionadded:: 2.0\n\n    Returns:\n        The test function to which the decorator is applied.\n\n    .. note::\n\n        To extend the test decorator, use the following template to create a new\n        ``cocotb.test``\\-like wrapper.\n\n        .. code-block:: python\n\n            import functools\n\n\n            def test_extender(**decorator_kwargs):\n                def decorator(obj):\n                    @cocotb.test(**decorator_kwargs)\n                    @functools.wraps(obj)\n                    async def test(dut, **test_kwargs):\n                        # your code here\n                        ...\n\n                    return obj\n\n                return decorator\n\n    .. versionchanged:: 2.0\n        Support using decorator on test function without supplying parameters first.\n\n        Assumes all default values for the test parameters.\n\n        .. code-block:: python\n\n            @cocotb.test\n            async def test_thing(dut): ...\n    \"\"\"\n    if isinstance(obj, TestGenerator):\n        return obj\n    elif obj is not None:\n        return TestGenerator(obj)\n\n    def wrapper(obj: TestFuncType | TestGenerator) -> TestGenerator:\n        if not isinstance(obj, TestGenerator):\n            obj = TestGenerator(obj)\n        if timeout_time is not None:\n            obj.timeout = (timeout_time, timeout_unit)\n        if expect_fail is not None:\n            obj.expect_fail |= expect_fail\n        if expect_error is not None:\n            if isinstance(expect_error, type):\n                obj.expect_error.add(expect_error)\n            else:\n                for exc in expect_error:\n                    obj.expect_error.add(exc)\n        if skip is not None:\n            obj.skip |= skip\n        if stage is not None:\n            obj.stage = stage\n        if name is not None:\n            obj.name = name\n        return obj\n\n    return wrapper\n\n\n# Prevent pytest from picking up the test decorator as a test\ntest.__test__ = False  # type: ignore[attr-defined]\n\n\n@overload\ndef parametrize(\n    *options_by_tuple: tuple[str, Sequence[object]]\n    | tuple[Sequence[str], Sequence[Sequence[object]]],\n) -> Callable[[TestFuncType | TestGenerator], TestGenerator]: ...\n\n\n@overload\ndef parametrize(\n    **options_by_name: Sequence[object],\n) -> Callable[[TestFuncType | TestGenerator], TestGenerator]: ...\n\n\ndef parametrize(\n    *options_by_tuple: tuple[str, Sequence[object]]\n    | tuple[Sequence[str], Sequence[Sequence[object]]],\n    **options_by_name: Sequence[object],\n) -> Callable[[TestFuncType | TestGenerator], TestGenerator]:\n    \"\"\"Decorator to generate parametrized tests from a single test function.\n\n    Decorates a test function with named test parameters.\n    The call to ``parametrize`` should include the name of each test parameter and the possible values each parameter can hold.\n    This will generate a test for each of the Cartesian products of the parameters and their values.\n\n    .. autolink-skip::\n    .. code-block:: python\n\n        @cocotb.test(\n            skip=False,\n        )\n        @cocotb.parametrize(\n            arg1=[0, 1],\n            arg2=[\"a\", \"b\"],\n        )\n        async def my_test(arg1: int, arg2: str) -> None: ...\n\n    The above is equivalent to the following.\n\n    .. autolink-skip::\n    .. code-block:: python\n\n        @cocotb.test(skip=False)\n        async def my_test_0_a() -> None:\n            arg1, arg2 = 0, \"a\"\n            ...\n\n\n        @cocotb.test(skip=False)\n        async def my_test_0_b() -> None:\n            arg1, arg2 = 0, \"b\"\n            ...\n\n\n        @cocotb.test(skip=False)\n        async def my_test_1_a() -> None:\n            arg1, arg2 = 1, \"a\"\n            ...\n\n\n        @cocotb.test(skip=False)\n        async def my_test_1_b() -> None:\n            arg1, arg2 = 1, \"b\"\n            ...\n\n    Options can also be specified in much the same way that :meth:`TestFactory.add_option <cocotb.regression.TestFactory.add_option>` can,\n    either by supplying tuples of the parameter name to values,\n    or a sequence of variable names and a sequence of values.\n\n    .. autolink-skip::\n    .. code-block:: python\n\n        @cocotb.parametrize(\n            (\"arg1\", [0, 1]),\n            ((\"arg2\", \"arg3\"), [(1, 2), (3, 4)]),\n        )\n        async def my_test_2(arg1: int, arg2: int, arg3: int) -> None: ...\n\n    Args:\n        options_by_tuple:\n            Tuple of parameter name to sequence of values for that parameter,\n            or tuple of sequence of parameter names to sequence of sequences of values for that pack of parameters.\n\n        options_by_name:\n            Mapping of parameter name to sequence of values for that parameter.\n\n    .. versionadded:: 2.0\n    \"\"\"\n\n    # check good inputs\n    for i, option_by_tuple in enumerate(options_by_tuple):\n        if len(option_by_tuple) != 2:\n            raise ValueError(\n                f\"Invalid option tuple {i}, expected exactly two fields `(name, values)`\"\n            )\n        name, values = option_by_tuple\n        if not isinstance(name, str):\n            for n in name:\n                if not n.isidentifier():\n                    raise ValueError(\"Option names must be valid Python identifiers\")\n            values = cast(\"Sequence[Sequence[object]]\", values)\n            for value in values:\n                if len(name) != len(value):\n                    raise ValueError(\n                        f\"Invalid option tuple {i}, mismatching number of parameters ({name}) and values ({value})\"\n                    )\n        elif not name.isidentifier():\n            raise ValueError(\"Option names must be valid Python identifiers\")\n\n    def wrapper(f: TestFuncType | TestGenerator) -> TestGenerator:\n        if not isinstance(f, TestGenerator):\n            f = TestGenerator(f)\n        # Ensure we prepend so that arguments lexically farther down in the \"stack\"\n        # appear in the test name lexically after (more right).\n        # Decorators are evaluated in reverse-lexical order.\n        f.options = [*options_by_tuple, *options_by_name.items(), *f.options]\n        return f\n\n    return wrapper\n\n\ndef skipif(\n    condition: bool, *, reason: str | None = None\n) -> Callable[[TestFuncType | TestGenerator], TestGenerator]:\n    \"\"\"Marks a test as skipped if the condition is ``True``.\n\n    This acts as an alternative to the ``skip`` option to :deco:`cocotb.test`.\n\n    .. autolink-skip::\n    .. code-block:: python\n\n        @cocotb.skipif(\n            cocotb.top.USE_MY_FEATURE.value != 1,\n            reason=\"The design doesn't support my feature.\",\n        )\n        @cocotb.test\n        async def test_my_feature(dut) -> None: ...\n\n    Args:\n        condition: The condition as to whether the test should be skipped. Defaults to ``True``.\n        reason: A string giving the reason as to why this test was skipped.\n\n            This argument is purely for documentation purposes.\n\n    Returns:\n        A decorator function to mark the test.\n\n    .. versionadded:: 2.1\n    \"\"\"\n\n    def decorator(obj: TestFuncType | TestGenerator) -> TestGenerator:\n        if not isinstance(obj, TestGenerator):\n            obj = TestGenerator(obj)\n        obj.skip |= condition\n        return obj\n\n    return decorator\n\n\n_single_exception_types = (\n    type,\n    *(\n        (pytest.RaisesExc, pytest.RaisesGroup)\n        if hasattr(pytest, \"RaisesExc\") and hasattr(pytest, \"RaisesGroup\")\n        else ()\n    ),\n)\n\n\ndef xfail(\n    condition: bool = True,\n    *,\n    reason: str | None = None,\n    raises: type[BaseException]\n    | pytest.RaisesExc\n    | pytest.RaisesGroup\n    | Iterable[type[BaseException]]\n    | None = None,\n) -> Callable[[TestFuncType | TestGenerator], TestGenerator]:\n    \"\"\"Marks a test as expected to fail if the condition is ``True``.\n\n    This acts as an alternative to the ``expect_fail`` option to :deco:`cocotb.test` if *raises* is not given.\n    Or as an alternative to ``expect_error`` if *raises* is given.\n\n    .. autolink-skip::\n    .. code-block:: python\n\n        @cocotb.xfail(reason=\"The HDL does not behave as expected.\")\n        @cocotb.test\n        async def test_design(dut): ...\n\n\n        @cocotb.xfail(\n            cocotb.top.USE_MY_FEATURE.value != 0,\n            raises=IndexError,\n            reason=\"My design is not configured to use the new feature, so the model will eventually fail\",\n        )\n        @cocotb.test\n        async def test_design_feature(dut): ...\n\n    Args:\n        condition: The condition as to whether the test is expected to fail. Defaults to ``True``.\n        reason: A string giving the reason as to why this test is expected to fail.\n\n            This argument is purely for documentation purposes.\n\n        raises: An exception, or iterable of exceptions to expect the test to fail with.\n\n    .. versionadded:: 2.1\n    \"\"\"\n\n    def decorator(obj: TestFuncType | TestGenerator) -> TestGenerator:\n        if not isinstance(obj, TestGenerator):\n            obj = TestGenerator(obj)\n        if condition:\n            if raises is not None:\n                if isinstance(raises, _single_exception_types):\n                    obj.expect_error.add(raises)\n                else:\n                    try:\n                        it = iter(raises)  # type: ignore[arg-type]\n                    except TypeError:\n                        raise TypeError(\n                            \"Expected error types must be an exception type or iterable of exception types\"\n                        ) from None\n                    else:\n                        for exc in it:\n                            if not isinstance(exc, _single_exception_types):\n                                raise TypeError(\n                                    \"Expected error types must be exception types\"\n                                )\n                            obj.expect_error.add(exc)\n            else:\n                obj.expect_fail = True\n        return obj\n\n    return decorator\n"
  },
  {
    "path": "src/cocotb/_deprecation.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport functools\nimport sys\nimport warnings\nfrom typing import Callable, TypeVar\n\nAnyCallableT = TypeVar(\"AnyCallableT\", bound=Callable[..., object])\n\n\n__all__ = [\"deprecated\"]\n\n\nif sys.version_info >= (3, 13):\n    from warnings import deprecated\n\nelse:\n\n    def deprecated(\n        msg: str, *, category: type[Warning] = DeprecationWarning, stacklevel: int = 1\n    ) -> Callable[[AnyCallableT], AnyCallableT]:\n        \"\"\"Emits a DeprecationWarning when the decorated function is called.\n\n        This decorator works on normal functions, methods, and properties.\n        Usage on properties requires the ``@property`` decorator to appear outside the\n        ``@deprecated`` decorator.\n        Concrete classes can be deprecated by decorating their ``__init__`` or ``__new__``\n        method.\n\n        Args:\n            msg: the deprecation message\n            category: the warning class to use\n            stacklevel: the stack level for the warning\n        \"\"\"\n\n        def decorator(f: AnyCallableT) -> AnyCallableT:\n            @functools.wraps(f)\n            def wrapper(*args: object, **kwargs: object) -> object:\n                warnings.warn(msg, category=category, stacklevel=1 + stacklevel)\n                return f(*args, **kwargs)\n\n            return wrapper  # type: ignore[return-value]  # type checkers get confused about this\n\n        return decorator\n"
  },
  {
    "path": "src/cocotb/_event_loop.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport logging\nfrom collections import deque\nfrom functools import cached_property\nfrom typing import Callable\n\nfrom cocotb import debug\nfrom cocotb._bridge import run_bridge_threads\n\n\nclass ScheduledCallback:\n    __slots__ = (\"_func\", \"_cancelled\")\n\n    def __init__(\n        self,\n        func: Callable[[], object],\n    ) -> None:\n        self._func = func\n        self._cancelled: bool = False\n\n    def _run(self) -> None:\n        self._func()\n\n    def cancel(self) -> None:\n        self._cancelled = True\n\n    def __repr__(self) -> str:\n        return self._func.__name__\n\n\nclass EventLoop:\n    def __init__(self) -> None:\n        self._callbacks: deque[ScheduledCallback] = deque()\n        self._cycles: int = 0\n\n    @cached_property\n    def log(self) -> logging.Logger:\n        return logging.getLogger(\"cocotb.event_loop\")\n\n    def run(self) -> None:\n        self._cycles = 0\n        while self._callbacks:\n            while self._callbacks:\n                do_debug = debug.debug\n                cb = self._callbacks.popleft()\n                if not cb._cancelled:\n                    if do_debug:\n                        self.log.debug(\"Running callback %r\", cb)\n                    cb._run()\n                elif do_debug:\n                    self.log.debug(\"Ignoring cancelled callback %r\", cb)\n                if do_debug:\n                    self._cycles += 1\n                    if self._cycles == 100_000:\n                        self.log.warning(\n                            \"Event loop ran 100,000 cycles without returning. An infinite loop is possible.\"\n                        )\n                        self._cycles = 0\n\n            run_bridge_threads()\n\n    def schedule(self, func: Callable[[], object]) -> ScheduledCallback:\n        cb = ScheduledCallback(func)\n        if debug.debug:\n            self.log.debug(\"Scheduling %r\", cb)\n        self._callbacks.append(cb)\n        return cb\n\n\n_inst: EventLoop = EventLoop()\n"
  },
  {
    "path": "src/cocotb/_extended_awaitables.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"A collection of triggers which a testbench can :keyword:`await`.\"\"\"\n\nfrom __future__ import annotations\n\nimport warnings\nfrom abc import abstractmethod\nfrom collections.abc import Awaitable, Generator\nfrom decimal import Decimal\nfrom typing import Any, TypeVar, cast, overload\n\nimport cocotb.handle\nfrom cocotb._base_triggers import NullTrigger, Trigger, _InternalEvent\nfrom cocotb._concurrent_waiters import select\nfrom cocotb._deprecation import deprecated\nfrom cocotb._gpi_triggers import FallingEdge, RisingEdge, Timer, ValueChange\nfrom cocotb.simtime import RoundMode, TimeUnit\nfrom cocotb.task import Task\n\nT = TypeVar(\"T\")\n\n\nclass Waitable(Awaitable[T]):\n    \"\"\"A Trigger-like object that can be implemented using coroutines.\n\n    This converts a ``_wait`` abstract method into a suitable ``__await__``.\n    \"\"\"\n\n    @abstractmethod\n    async def _wait(self) -> T:\n        \"\"\"The coroutine function which implements the functionality of the Waitable.\"\"\"\n\n    def __await__(self) -> Generator[Trigger, None, T]:\n        return self._wait().__await__()\n\n\nasync def _wait_callback(trigger: Awaitable[T]) -> T:\n    return await trigger\n\n\nclass Combine(Waitable[\"Combine\"]):\n    r\"\"\"Trigger that fires when all *triggers* have fired.\n\n    :keyword:`await`\\ ing this returns the :class:`Combine` object.\n    This is similar to Verilog's ``join``.\n    See :ref:`combine-tutorial` for an example.\n\n    Args:\n        triggers: One or more :keyword:`await`\\ able objects.\n\n    Raises:\n        TypeError: When an unsupported *trigger* object is passed.\n\n    .. deprecated:: 2.1\n        Passing :class:`~cocotb.task.Task` objects to :class:`!Combine` is deprecated.\n        Use :func:`~cocotb.triggers.gather` instead and pass coroutines directly instead of wrapping them in :func:`cocotb.start_soon`.\n    \"\"\"\n\n    _task_deprecation_str = (\n        \"Passing Task objects to `Combine` is deprecated. \"\n        \"Use `gather` instead and pass coroutines directly instead of wrapping them in `cocotb.start_soon`.\"\n    )\n\n    @overload\n    def __init__(self, *triggers: Trigger | Waitable[Any]) -> None: ...\n\n    @overload\n    @deprecated(_task_deprecation_str)\n    def __init__(self, *triggers: Trigger | Waitable[Any] | Task[Any]) -> None: ...\n\n    def __init__(self, *triggers: Trigger | Waitable[Any] | Task[Any]) -> None:\n        # Do some basic type-checking up front, rather than waiting until we\n        # await them.\n        for t in triggers:\n            if isinstance(t, Task):\n                warnings.warn(\n                    self._task_deprecation_str, DeprecationWarning, stacklevel=2\n                )\n            elif not isinstance(t, (Trigger, Waitable)):\n                raise TypeError(\n                    f\"All triggers must be instances of Trigger! Got: {type(t).__qualname__}\"\n                )\n\n        self._triggers = triggers\n\n    async def _wait(self) -> Combine:\n        if len(self._triggers) == 0:\n            await NullTrigger()\n        elif len(self._triggers) == 1:\n            await self._triggers[0]\n        else:\n            waiters: list[Task[object]] = []\n            completed: list[Task[object]] = []\n            done = _InternalEvent(self)\n            exception: BaseException | None = None\n\n            def on_done(\n                task: Task[object],\n            ) -> None:\n                # have to check cancelled first otherwise exception() will throw\n                if task.cancelled():\n                    completed.append(task)\n                    if len(completed) == len(waiters):\n                        done.set()\n                    return\n                e = task.exception()\n                if e is not None:\n                    nonlocal exception\n                    exception = e\n                    done.set()\n                else:\n                    completed.append(task)\n                    if len(completed) == len(waiters):\n                        done.set()\n\n            # start a parallel task for each trigger\n            for t in self._triggers:\n                task = Task[object](_wait_callback(t))\n                task._add_done_callback(on_done)\n                cocotb.start_soon(task)\n                waiters.append(task)\n\n            try:\n                # wait for the last waiter to complete\n                await done\n            finally:\n                # kill remaining waiters\n                for w in waiters:\n                    w.cancel()\n\n            if exception is not None:\n                raise exception\n\n        return self\n\n    def __repr__(self) -> str:\n        # no _pointer_str here, since this is not a trigger, so identity\n        # doesn't matter.\n        return \"{}({})\".format(\n            type(self).__qualname__,\n            \", \".join(repr(t) for t in self._triggers),\n        )\n\n\nclass First(Waitable[object]):\n    r\"\"\"Fires when the first trigger in *triggers* fires.\n\n    :keyword:`await`\\ ing this object returns the result of the first trigger that fires.\n    This is similar to Verilog's ``join_any``.\n    See :ref:`first-tutorial` for an example.\n\n    Args:\n        triggers: One or more :keyword:`await`\\ able objects.\n\n    Raises:\n        TypeError: When an unsupported *trigger* object is passed.\n        ValueError: When no triggers are passed.\n\n    .. note::\n        The event loop is single threaded, so while events may be simultaneous\n        in simulation time, they can never be simultaneous in real time.\n        For this reason, the value of ``t_ret is t1`` in the following example\n        is implementation-defined, and will vary by simulator::\n\n            t1 = Timer(10, unit=\"ps\")\n            t2 = Timer(10, unit=\"ps\")\n            t_ret = await First(t1, t2)\n\n    .. note::\n        In the old-style :ref:`generator-based coroutines <yield-syntax>`, ``t = yield [a, b]`` was another spelling of\n        ``t = yield First(a, b)``. This spelling is no longer available when using :keyword:`await`-based\n        coroutines.\n\n    .. deprecated:: 2.1\n        Passing :class:`~cocotb.task.Task` objects to :class:`!First` is deprecated.\n        Use :func:`~cocotb.triggers.select` instead and pass coroutines directly instead of wrapping them in :func:`cocotb.start_soon`.\n    \"\"\"\n\n    _task_deprecation_str = (\n        \"Passing Task objects to `First` is deprecated. \"\n        \"Use `select` instead and pass coroutines directly instead of wrapping them in `cocotb.start_soon`.\"\n    )\n\n    @overload\n    def __init__(\n        self, first: Trigger | Waitable[Any], /, *triggers: Trigger | Waitable[Any]\n    ) -> None: ...\n\n    @overload\n    @deprecated(_task_deprecation_str)\n    def __init__(\n        self,\n        first: Trigger | Waitable[Any] | Task[Any],\n        /,\n        *triggers: Trigger | Waitable[Any] | Task[Any],\n    ) -> None: ...\n\n    def __init__(self, *triggers: Trigger | Waitable[Any] | Task[Any]) -> None:\n        if not triggers:\n            raise ValueError(\"First() requires at least one Trigger or Task argument\")\n\n        # Do some basic type-checking up front, rather than waiting until we\n        # await them.\n        for t in triggers:\n            if isinstance(t, Task):\n                warnings.warn(\n                    self._task_deprecation_str, DeprecationWarning, stacklevel=2\n                )\n            elif not isinstance(t, (Trigger, Waitable)):\n                raise TypeError(\n                    f\"All triggers must be instances of Trigger! Got: {type(t).__qualname__}\"\n                )\n\n        self._triggers = triggers\n\n    async def _wait(self) -> object:\n        if len(self._triggers) == 1:\n            return await self._triggers[0]\n\n        waiters: list[Task[object]] = []\n        done = _InternalEvent(self)\n        completed: list[Task[object]] = []\n\n        def on_done(task: Task[object]) -> None:\n            completed.append(task)\n            done.set()\n\n        # start a parallel task for each trigger\n        for t in self._triggers:\n            task = Task[object](_wait_callback(t))\n            task._add_done_callback(on_done)\n            cocotb.start_soon(task)\n            waiters.append(task)\n\n        try:\n            # wait for a waiter to complete\n            await done\n        finally:\n            # kill all the other waiters\n            for w in waiters:\n                w.cancel()\n\n        return completed[0].result()\n\n    def __repr__(self) -> str:\n        # no _pointer_str here, since this is not a trigger, so identity\n        # doesn't matter.\n        return \"{}({})\".format(\n            type(self).__qualname__,\n            \", \".join(repr(t) for t in self._triggers),\n        )\n\n\nclass ClockCycles(Waitable[\"ClockCycles\"]):\n    r\"\"\"Finishes after *num_cycles* transitions of *signal*.\n\n    :keyword:`await`\\ ing this Trigger returns the :class:`!ClockCycles` object.\n\n    Args:\n        signal: The signal to monitor.\n        num_cycles: The number of cycles to count.\n        rising: If ``True``, count rising edges; if ``False``, count falling edges.\n        edge_type: The kind of :ref:`edge-triggers` to count.\n\n    .. warning::\n        On many simulators transitions occur when the signal changes value from non-``0`` to ``0`` or non-``1`` to ``1``,\n        not just from ``1`` to ``0`` or ``0`` to ``1``.\n\n    .. versionadded:: 2.0\n        Passing the edge trigger type: :class:`.RisingEdge`, :class:`.FallingEdge`, or :class:`.ValueChange`\n        as the third positional argument or by the keyword *edge_type*.\n    \"\"\"\n\n    @overload\n    def __init__(\n        self,\n        signal: cocotb.handle.LogicObject,\n        num_cycles: int,\n    ) -> None: ...\n\n    @overload\n    def __init__(\n        self,\n        signal: cocotb.handle.LogicObject,\n        num_cycles: int,\n        edge_type: type[RisingEdge]\n        | type[FallingEdge]\n        | type[ValueChange]\n        | None = None,\n    ) -> None: ...\n\n    @overload\n    def __init__(\n        self, signal: cocotb.handle.LogicObject, num_cycles: int, *, rising: bool\n    ) -> None: ...\n\n    def __init__(\n        self,\n        signal: cocotb.handle.LogicObject,\n        num_cycles: int,\n        edge_type: bool\n        | type[RisingEdge]\n        | type[FallingEdge]\n        | type[ValueChange]\n        | None = None,\n        *,\n        rising: bool | None = None,\n    ) -> None:\n        self._signal = signal\n        self._num_cycles = num_cycles\n        self._edge_type: type[RisingEdge] | type[FallingEdge] | type[ValueChange]\n        if edge_type is not None and rising is not None:\n            raise TypeError(\"Passed more than one edge selection argument.\")\n        elif edge_type is True:\n            self._edge_type = RisingEdge\n        elif edge_type is False:\n            self._edge_type = FallingEdge\n        elif edge_type is not None:\n            self._edge_type = edge_type\n        elif rising is not None:\n            self._edge_type = RisingEdge if rising else FallingEdge\n        else:\n            # default if no argument is passed\n            self._edge_type = RisingEdge\n\n    @property\n    def signal(self) -> cocotb.handle.LogicObject:\n        \"\"\"The signal being monitored.\"\"\"\n        return self._signal\n\n    @property\n    def num_cycles(self) -> int:\n        \"\"\"The number of cycles to wait.\"\"\"\n        return self._num_cycles\n\n    @property\n    def edge_type(\n        self,\n    ) -> type[RisingEdge] | type[FallingEdge] | type[ValueChange]:\n        \"\"\"The type of edge trigger used.\"\"\"\n        return self._edge_type\n\n    async def _wait(self) -> ClockCycles:\n        trigger = self._edge_type(self._signal)\n        for _ in range(self._num_cycles):\n            await trigger\n        return self\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}({self._signal._path}, {self._num_cycles}, {self._edge_type.__qualname__})\"\n\n\nclass SimTimeoutError(TimeoutError):\n    \"\"\"Exception thrown when a timeout, in terms of simulation time, occurs.\"\"\"\n\n\nasync def with_timeout(\n    trigger: Awaitable[T],\n    timeout_time: float | Decimal,\n    timeout_unit: TimeUnit = \"step\",\n    round_mode: RoundMode | None = None,\n) -> T:\n    r\"\"\"Wait on any awaitable, throw an exception if it waits longer than the given time.\n\n    When a :term:`python:coroutine` is passed,\n    the callee coroutine is started,\n    the caller blocks until the callee completes,\n    and the callee's result is returned to the caller.\n    If timeout occurs, the callee is killed\n    and :exc:`SimTimeoutError` is raised.\n\n    When a :term:`task` is passed,\n    the caller blocks until the callee completes\n    and the callee's result is returned to the caller.\n    If timeout occurs, the callee `continues to run`\n    and :exc:`SimTimeoutError` is raised.\n\n    If a :class:`~cocotb.triggers.Trigger` or :class:`~cocotb.triggers.Waitable` is passed,\n    the caller blocks until the trigger fires,\n    and the trigger is returned to the caller.\n    If timeout occurs, the trigger is cancelled\n    and :exc:`SimTimeoutError` is raised.\n\n    Usage:\n        .. code-block:: python\n\n            await with_timeout(coro, 100, \"ns\")\n            await with_timeout(First(coro, event.wait()), 100, \"ns\")\n\n    Args:\n        trigger:\n            A single object that could be right of an :keyword:`await` expression in cocotb.\n        timeout_time:\n            Simulation time duration before timeout occurs.\n        timeout_unit:\n            Unit of timeout_time, accepts any unit that :class:`~cocotb.triggers.Timer` does.\n        round_mode:\n            String specifying how to handle time values that sit between time steps\n            (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``, ``None``).\n            A ``None`` argument is converted to the current value of :attr:`.Timer.round_mode`.\n\n    Returns:\n        First trigger that completed if timeout did not occur.\n\n    Raises:\n        :exc:`SimTimeoutError`: If timeout occurs.\n\n    .. versionadded:: 1.3\n\n    .. versionchanged:: 1.7\n        Support passing :term:`python:coroutine`\\ s.\n\n    .. versionchanged:: 2.0\n        Passing ``None`` as the *timeout_unit* argument was removed, use ``'step'`` instead.\n\n    \"\"\"\n    i, res = await select(\n        Timer(timeout_time, timeout_unit, round_mode=round_mode), trigger\n    )\n    if i == 0:\n        raise SimTimeoutError\n    else:\n        return cast(\"T\", res)\n"
  },
  {
    "path": "src/cocotb/_gpi_triggers.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"A collection of triggers which a testbench can :keyword:`await`.\"\"\"\n\nfrom __future__ import annotations\n\nimport sys\nimport warnings\nfrom collections.abc import Generator\nfrom decimal import Decimal\nfrom fractions import Fraction\nfrom typing import Any, ClassVar, Generic, TypeVar, Union\n\nimport cocotb\nimport cocotb._event_loop\nimport cocotb.handle\nfrom cocotb import debug, simulator\nfrom cocotb._base_triggers import Trigger\nfrom cocotb._deprecation import deprecated\nfrom cocotb._profiling import profiling_context\nfrom cocotb._utils import pointer_str, singleton\nfrom cocotb.simtime import RoundMode, TimeUnit\nfrom cocotb.utils import get_sim_steps, get_time_from_sim_steps\n\nif sys.version_info >= (3, 11):\n    from typing import Self\n\n\nclass GPITrigger(Trigger):\n    \"\"\"A trigger for a simulation event.\"\"\"\n\n    def __init__(self) -> None:\n        super().__init__()\n        self._cbhdl: simulator.sim_callback | None = None\n\n    def _react(self) -> None:\n        if debug.debug:\n            self._log.debug(\"Fired %s\", self)\n        with profiling_context:\n            global _current_gpi_trigger\n            _current_gpi_trigger = self\n            if debug.debug and not self._callbacks:\n                self._log.error(\"No callbacks on GPITrigger that fired\")\n            self._do_callbacks()\n            cocotb._event_loop._inst.run()\n\n    def _unprime(self) -> None:\n        assert self._cbhdl is not None\n        self._cbhdl.deregister()\n        self._cbhdl = None\n\n\nclass Timer(GPITrigger):\n    r\"\"\"Fire after the specified simulation time period has elapsed.\n\n    This trigger will *always* consume some simulation time\n    and will return control to the :keyword:`await`\\ ing task at the beginning of the time step.\n\n    Args:\n        time: The time value.\n\n            .. versionchanged:: 1.5\n                Previously this argument was misleadingly called `time_ps`.\n\n        unit: The unit of the time value.\n\n            One of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``.\n            When *unit* is ``'step'``,\n            the timestep is determined by the simulator (see :make:var:`COCOTB_HDL_TIMEPRECISION`).\n\n            .. versionchanged:: 2.0\n                Renamed from ``units``.\n\n        round_mode:\n\n            String specifying how to handle time values that sit between time steps\n            (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``, ``None``).\n            A ``None`` argument is converted to the current value of :attr:`.Timer.round_mode`.\n\n    Raises:\n        ValueError: If a non-positive value is passed for Timer setup.\n\n    Usage:\n        >>> await Timer(100, unit=\"ps\")\n\n        The time can also be a ``float``:\n\n        >>> await Timer(100e-9, unit=\"sec\")\n\n        which is particularly convenient when working with frequencies:\n\n        >>> freq = 10e6  # 10 MHz\n        >>> await Timer(1 / freq, unit=\"sec\")\n\n        Other built-in exact numeric types can be used too:\n\n        >>> from fractions import Fraction\n        >>> await Timer(Fraction(1, 10), unit=\"ns\")\n\n        >>> from decimal import Decimal\n        >>> await Timer(Decimal(\"100e-9\"), unit=\"sec\")\n\n        These are most useful when using computed durations while\n        avoiding floating point inaccuracies.\n\n    .. versionchanged:: 1.5\n        Raise an exception when Timer uses a negative value as it is undefined behavior.\n        Warn for 0 as this will cause erratic behavior in some simulators as well.\n\n    .. versionchanged:: 1.5\n        Support ``'step'`` as the *unit* argument to mean \"simulator time step\".\n\n    .. versionchanged:: 1.6\n        Support rounding modes.\n\n    .. versionremoved:: 2.0\n        Passing ``None`` as the *unit* argument was removed, use ``'step'`` instead.\n\n    .. versionremoved:: 2.0\n        The ``time_ps`` parameter was removed, use the ``time`` parameter instead.\n\n    .. versionchanged:: 2.0\n        Passing ``0`` as the *time* argument now raises a :exc:`ValueError`.\n    \"\"\"\n\n    round_mode: ClassVar[RoundMode] = \"error\"\n    \"\"\"The default rounding mode.\"\"\"\n\n    def __init__(\n        self,\n        time: float | Fraction | Decimal,\n        unit: TimeUnit = \"step\",\n        *,\n        round_mode: RoundMode | None = None,\n        units: None = None,\n    ) -> None:\n        super().__init__()\n        if time <= 0:\n            raise ValueError(\"Timer argument time must be positive\")\n        if units is not None:\n            warnings.warn(\n                \"The 'units' argument has been renamed to 'unit'.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            unit = units\n        if round_mode is None:\n            round_mode = type(self).round_mode\n        self._sim_steps = get_sim_steps(time, unit, round_mode=round_mode)\n        # If we round to 0, we fix it up to 1 step as rounding is imprecise,\n        # and Timer(0) is invalid.\n        if self._sim_steps == 0:\n            self._sim_steps = 1\n\n    def _prime(self) -> None:\n        self._cbhdl = simulator.register_timed_callback(self._sim_steps, self._react)\n        if self._cbhdl is None:\n            raise RuntimeError(f\"Unable set up {self} Trigger\")\n\n    def __repr__(self) -> str:\n        return \"<{} of {:1.2f}ps at {}>\".format(\n            type(self).__qualname__,\n            get_time_from_sim_steps(self._sim_steps, unit=\"ps\"),\n            pointer_str(self),\n        )\n\n\n@singleton\nclass ReadOnly(GPITrigger):\n    \"\"\"Fires when the current simulation timestep moves to the read-only phase.\n\n    The read-only phase is entered when the current timestep no longer has any further delta steps.\n    This will be a point where all the signal values are stable as there are no more RTL events scheduled for the timestep.\n    The simulator will not allow scheduling of more events in this timestep.\n    Useful for monitors which need to wait for all processes to execute (both RTL and cocotb) to ensure sampled signal values are final.\n    \"\"\"\n\n    def _prime(self) -> None:\n        self._cbhdl = simulator.register_readonly_callback(self._react)\n        if self._cbhdl is None:\n            raise RuntimeError(f\"Unable set up {self} Trigger\")\n\n    def __await__(self) -> Generator[Self, None, Self]:\n        if isinstance(current_gpi_trigger(), ReadOnly):\n            raise RuntimeError(\n                \"Attempted illegal transition: awaiting ReadOnly in ReadOnly phase\"\n            )\n        return (yield from super().__await__())\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}()\"\n\n\n@singleton\nclass ReadWrite(GPITrigger):\n    \"\"\"Fires when the read-write simulation phase is reached.\"\"\"\n\n    def _prime(self) -> None:\n        self._cbhdl = simulator.register_rwsynch_callback(self._react)\n        if self._cbhdl is None:\n            raise RuntimeError(f\"Unable set up {self} Trigger\")\n\n    def _do_callbacks(self) -> None:\n        # Force scheduled writes to occur first for those simulators where inertial\n        # writes are applied immediately when in ReadWrite mode.\n        cocotb.handle._apply_scheduled_writes()\n        return super()._do_callbacks()\n\n    def __await__(self) -> Generator[Self, None, Self]:\n        if isinstance(current_gpi_trigger(), ReadOnly):\n            raise RuntimeError(\n                \"Attempted illegal transition: awaiting ReadWrite in ReadOnly phase\"\n            )\n        return (yield from super().__await__())\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}()\"\n\n\n@singleton\nclass NextTimeStep(GPITrigger):\n    \"\"\"Fires when the next time step is started.\"\"\"\n\n    def _prime(self) -> None:\n        self._cbhdl = simulator.register_nextstep_callback(self._react)\n        if self._cbhdl is None:\n            raise RuntimeError(f\"Unable set up {self} Trigger\")\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}()\"\n\n\n_SignalType = TypeVar(\"_SignalType\", bound=\"cocotb.handle.ValueObjectBase[Any, Any]\")\n\n\nclass _EdgeBase(GPITrigger, Generic[_SignalType]):\n    \"\"\"Internal base class that fires on a given edge of a signal.\"\"\"\n\n    _edge_type: ClassVar[int]\n    signal: _SignalType\n\n    @classmethod\n    def _make(cls, signal: _SignalType) -> Self:\n        self = GPITrigger.__new__(cls)\n        GPITrigger.__init__(self)\n        self.signal = signal\n        return self\n\n    def __init__(self, _: _SignalType) -> None:\n        pass\n\n    def _prime(self) -> None:\n        self._cbhdl = simulator.register_value_change_callback(\n            self.signal._handle, self._react, type(self)._edge_type\n        )\n        if self._cbhdl is None:\n            raise RuntimeError(f\"Unable set up {self} Trigger\")\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}({self.signal!r})\"\n\n\nclass RisingEdge(\n    _EdgeBase[Union[\"cocotb.handle.LogicObject\", \"cocotb.handle.LogicArrayObject\"]]\n):\n    \"\"\"Fires on the rising edge of *signal*, on a transition to ``1``.\n\n    Only valid for scalar ``logic`` or ``bit``-typed signals.\n\n    Args:\n        signal: The signal upon which to wait for a rising edge.\n\n    Raises:\n        TypeError: If *signal* is not a 1-bit ``logic`` or ``bit``-typed object.\n\n    .. note::\n        Prefer :attr:`await signal.rising_edge <cocotb.handle.LogicObject.rising_edge>` to ``await RisingEdge(signal)``.\n\n    .. warning::\n        On many simulators this will trigger on transitions from non-``0``/``1`` value to ``1``,\n        not just from ``0`` to ``1`` like the ``rising_edge`` function in VHDL.\n    \"\"\"\n\n    _edge_type = simulator.RISING\n\n    def __new__(cls, signal: cocotb.handle.LogicObject) -> RisingEdge:\n        if not isinstance(\n            signal, (cocotb.handle.LogicObject, cocotb.handle.LogicArrayObject)\n        ):\n            raise TypeError(\n                f\"{cls.__qualname__} requires a scalar LogicObject or a 1-bit LogicArrayObject. Got {signal!r} of type {type(signal).__qualname__}\"\n            )\n        return signal.rising_edge\n\n\nclass FallingEdge(\n    _EdgeBase[Union[\"cocotb.handle.LogicObject\", \"cocotb.handle.LogicArrayObject\"]]\n):\n    \"\"\"Fires on the falling edge of *signal*, on a transition to ``0``.\n\n    Only valid for scalar ``logic`` or ``bit``-typed signals.\n\n    Args:\n        signal: The signal upon which to wait for a rising edge.\n\n    Raises:\n        TypeError: If *signal* is not a 1-bit ``logic`` or ``bit``-typed object.\n\n    .. note::\n        Prefer :attr:`await signal.falling_edge <cocotb.handle.LogicObject.falling_edge>` to ``await FallingEdge(signal)``.\n\n    .. warning::\n        On many simulators this will trigger on transitions from non-``0``/``1`` value to ``0``,\n        not just from ``1`` to ``0`` like the ``falling_edge`` function in VHDL.\n    \"\"\"\n\n    _edge_type = simulator.FALLING\n\n    def __new__(cls, signal: cocotb.handle.LogicObject) -> FallingEdge:\n        if not isinstance(\n            signal, (cocotb.handle.LogicObject, cocotb.handle.LogicArrayObject)\n        ):\n            raise TypeError(\n                f\"{cls.__qualname__} requires a scalar LogicObject or a 1-bit LogicArrayObject. Got {signal!r} of type {type(signal).__qualname__}\"\n            )\n        return signal.falling_edge\n\n\nclass ValueChange(_EdgeBase[\"cocotb.handle._NonIndexableValueObjectBase[Any, Any]\"]):\n    \"\"\"Fires on any value change of *signal*.\n\n    Args:\n        signal: The signal upon which to wait for a value change.\n\n    Raises:\n        TypeError: If the signal is not an object which can change value.\n\n    .. note::\n        Prefer :attr:`await signal.value_change <cocotb.handle.NonArrayValueObject.value_change>` to ``await ValueChange(signal)``.\n\n    .. versionadded:: 2.0\n    \"\"\"\n\n    _edge_type = simulator.VALUE_CHANGE\n\n    def __new__(\n        cls, signal: cocotb.handle._NonIndexableValueObjectBase[Any, Any]\n    ) -> ValueChange:\n        if not isinstance(signal, cocotb.handle._NonIndexableValueObjectBase):\n            raise TypeError(\n                f\"{cls.__qualname__} requires a simulation object derived from ValueObjectBase. \"\n                f\"Got {signal!r} of type {type(signal).__qualname__}\"\n            )\n        return signal.value_change\n\n\nclass Edge(ValueChange):\n    \"\"\"Fires on any value change of *signal*.\n\n    Args:\n        signal: The signal upon which to wait for a value change.\n\n    Raises:\n        TypeError: If the signal is not an object which can change value.\n\n    .. deprecated:: 2.0\n\n        Use :attr:`signal.value_change <cocotb.handle.NonArrayValueObject.value_change>` instead.\n    \"\"\"\n\n    @deprecated(\"Use `signal.value_change` instead.\")\n    def __new__(\n        cls, signal: cocotb.handle._NonIndexableValueObjectBase[Any, Any]\n    ) -> Edge:\n        if not isinstance(signal, cocotb.handle._NonIndexableValueObjectBase):\n            raise TypeError(\n                f\"{cls.__qualname__} requires a simulation object derived from ValueObjectBase. \"\n                f\"Got {signal!r} of type {type(signal).__qualname__}\"\n            )\n        return signal._edge\n\n\n# The initializer is a lie, but a useful one. Perhaps one day this can be something like `StartupTrigger`.`\n_current_gpi_trigger: GPITrigger | None = Timer(1, \"step\")\n\n\ndef current_gpi_trigger() -> GPITrigger:\n    \"\"\"Return the last GPITrigger that fired.\"\"\"\n    if _current_gpi_trigger is None:\n        raise RuntimeError(\"No GPI trigger has fired.\")\n    return _current_gpi_trigger\n"
  },
  {
    "path": "src/cocotb/_init.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport importlib.util\nimport logging\nimport os\nimport random\nimport time\nimport warnings\nfrom pathlib import Path\nfrom types import SimpleNamespace\nfrom typing import cast\n\nimport cocotb\nimport cocotb._profiling\nimport cocotb._shutdown\nimport cocotb.handle\nimport cocotb.logging\nimport cocotb.simtime\nimport cocotb.simulator\nfrom cocotb_tools import _env\n\nlog: logging.Logger\n\n\ndef init_package_from_simulation() -> None:\n    \"\"\"Initialize the cocotb package from a simulation context.\"\"\"\n\n    # Initialize subsystems\n    cocotb._shutdown._init()\n    cocotb.logging._init()\n    cocotb._profiling._init()\n    cocotb.simtime._init()\n\n    # Set up local \"cocotb\" logger\n    global log\n    log = logging.getLogger(\"cocotb.initialize\")\n\n    # setup cocotb global variables\n    cocotb.is_simulation = True\n    cocotb.argv = cocotb.simulator.get_simulator_args()\n    cocotb.log = logging.getLogger(\"test\")\n    cocotb.log.setLevel(logging.INFO)\n    cocotb.SIM_NAME = cocotb.simulator.get_simulator_product().strip()\n    cocotb.SIM_VERSION = cocotb.simulator.get_simulator_version().strip()\n    _process_plusargs()\n    _setup_random_seed()\n    _setup_root_handle()\n    _process_packages()\n    _start_user_coverage()\n\n    # log info about the simulation\n    log.info(\n        \"Initialized cocotb v%s from %s\",\n        cocotb.__version__,\n        Path(__file__).parent.absolute(),\n    )\n    log.info(\"Running on %s version %s\", cocotb.SIM_NAME, cocotb.SIM_VERSION)\n\n\ndef _process_plusargs() -> None:\n    cocotb.plusargs = {}\n\n    for option in cocotb.argv:\n        if option.startswith(\"+\"):\n            if option.find(\"=\") != -1:\n                (name, value) = option[1:].split(\"=\", 1)\n                cocotb.plusargs[name] = value\n            else:\n                cocotb.plusargs[option[1:]] = True\n\n\ndef _process_packages() -> None:\n    pkg_dict = {}\n\n    import cocotb.simulator  # noqa: PLC0415\n\n    pkgs = cocotb.simulator.package_iterate()\n    if pkgs is None:\n        cocotb.packages = SimpleNamespace()\n        return\n\n    for pkg in pkgs:\n        handle = cast(\n            \"cocotb.handle.HierarchyObject\", cocotb.handle._make_sim_object(pkg)\n        )\n        name = handle._name\n\n        # Icarus doesn't support named access to package objects:\n        # https://github.com/steveicarus/iverilog/issues/1038\n        # so we cannot lazily create handles\n        if cocotb.SIM_NAME == \"Icarus Verilog\":\n            handle._discover_all()\n        pkg_dict[name] = handle\n\n    cocotb.packages = SimpleNamespace(**pkg_dict)\n\n\ndef _get_package_path(pkg: str) -> Path:\n    \"\"\"Get the filesystem path of a package.\"\"\"\n    spec = importlib.util.find_spec(pkg)\n    if spec is None or spec.origin is None:\n        raise ImportError(f\"Cannot find package {pkg!r}\")\n    return Path(spec.origin).parent.absolute()\n\n\ndef _start_user_coverage() -> None:\n    enable_coverage: bool = False\n\n    if _env.exists(\"COCOTB_USER_COVERAGE\"):\n        enable_coverage = _env.as_bool(\"COCOTB_USER_COVERAGE\")\n\n    elif _env.exists(\"COVERAGE\"):\n        warnings.warn(\n            \"COVERAGE is deprecated in favor of COCOTB_USER_COVERAGE\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        enable_coverage = _env.as_bool(\"COVERAGE\")\n\n    if enable_coverage:\n        try:\n            import coverage  # noqa: PLC0415\n        except ImportError:\n            raise RuntimeError(\n                \"Coverage collection requested but coverage module not available. Install it using `pip install coverage`.\"\n            ) from None\n        else:\n            config_filepath: str = _env.as_str(\"COVERAGE_RCFILE\")\n            if not config_filepath:\n                # Exclude cocotb libraries from coverage collection.\n                log.info(\n                    \"Collecting coverage of user code. No coverage config file supplied via COVERAGE_RCFILE.\"\n                )\n                cocotb_package_dir = _get_package_path(\"cocotb\")\n                cocotb_tools_package_dir = _get_package_path(\"cocotb_tools\")\n                pygpi_package_dir = _get_package_path(\"pygpi\")\n                user_coverage = coverage.coverage(\n                    branch=True,\n                    omit=[\n                        f\"{cocotb_package_dir}/*\",\n                        f\"{cocotb_tools_package_dir}/*\",\n                        f\"{pygpi_package_dir}/*\",\n                    ],\n                )\n            else:\n                log.info(\n                    \"Collecting coverage of user code. Coverage config file supplied.\"\n                )\n                # Allow the config file to handle all configuration\n                user_coverage = coverage.coverage(config_file=config_filepath)\n            user_coverage.load()\n            user_coverage.start()\n\n            def stop_user_coverage() -> None:\n                user_coverage.stop()\n                log.debug(\"Writing user coverage data\")\n                user_coverage.save()\n\n            cocotb._shutdown.register(stop_user_coverage)\n\n\ndef _setup_random_seed() -> None:\n    seed: int = int(time.time())\n\n    if _env.exists(\"COCOTB_RANDOM_SEED\"):\n        seed = _env.as_int(\"COCOTB_RANDOM_SEED\", seed)\n\n    elif _env.exists(\"RANDOM_SEED\"):\n        warnings.warn(\n            \"RANDOM_SEED is deprecated in favor of COCOTB_RANDOM_SEED\",\n            DeprecationWarning,\n        )\n        seed = _env.as_int(\"RANDOM_SEED\", seed)\n\n    elif \"ntb_random_seed\" in cocotb.plusargs:\n        warnings.warn(\n            \"Passing +ntb_random_seed will not be used to seed Python's random number generator in the future. \"\n            \"Ensure you also set `COCOTB_RANDOM_SEED`.\",\n            FutureWarning,\n        )\n        seed = int(str(cocotb.plusargs[\"ntb_random_seed\"]))\n\n    elif \"seed\" in cocotb.plusargs:\n        warnings.warn(\n            \"Passing +seed will not be used to seed Python's random number generator in the future. \"\n            \"Ensure you also set `COCOTB_RANDOM_SEED`.\",\n            FutureWarning,\n        )\n        seed = int(str(cocotb.plusargs[\"seed\"]))\n\n    cocotb.RANDOM_SEED = seed\n    random.seed(seed)\n    log.info(\"Seeding Python random module with %d\", seed)\n\n\ndef _setup_root_handle() -> None:\n    root_name = os.getenv(\"COCOTB_TOPLEVEL\")\n    if root_name is not None:\n        root_name = root_name.strip()\n        if root_name == \"\":\n            root_name = None\n        elif \".\" in root_name:\n            # Skip any library component of the toplevel\n            root_name = root_name.split(\".\", 1)[1]\n\n    import cocotb.simulator  # noqa: PLC0415\n\n    handle = cocotb.simulator.get_root_handle(root_name)\n    if not handle:\n        raise RuntimeError(f\"Can not find root handle {root_name!r}\")\n\n    cocotb.top = cocotb.handle._make_sim_object(handle)\n"
  },
  {
    "path": "src/cocotb/_outcomes.py",
    "content": "\"\"\"\nInspired by https://github.com/python-trio/outcome\n\nAn outcome is similar to the built-in :any:`concurrent.futures.Future`\nor :any:`asyncio.Future`, but without being tied to a particular task model.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport abc\nimport sys\nfrom typing import Callable, Generic, TypeVar\n\nfrom cocotb._utils import remove_traceback_frames\n\nT = TypeVar(\"T\")\n\nif sys.version_info >= (3, 10):\n    from typing import ParamSpec\n\n    P = ParamSpec(\"P\")\n\n\ndef capture(fn: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> Outcome[T]:\n    \"\"\"Obtain an `Outcome` representing the result of a function call.\"\"\"\n    try:\n        return Value(fn(*args, **kwargs))\n    except BaseException as e:\n        e = remove_traceback_frames(e, [\"capture\"])\n        return Error(e)\n\n\nclass Outcome(Generic[T]):\n    @abc.abstractmethod\n    def get(self) -> T:\n        \"\"\"Get the value of this outcome, or throw its exception.\"\"\"\n\n\nclass Value(Outcome[T]):\n    def __init__(self, value: T):\n        self.value = value\n\n    def get(self) -> T:\n        return self.value\n\n    def __repr__(self) -> str:\n        return f\"Value({self.value!r})\"\n\n\nclass Error(Outcome[T]):\n    def __init__(self, error: BaseException) -> None:\n        self.error = error\n\n    def get(self) -> T:\n        raise self.error\n\n    def __repr__(self) -> str:\n        return f\"Error({self.error!r})\"\n"
  },
  {
    "path": "src/cocotb/_profiling.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\n# Debug mode controlled by environment variables\nfrom __future__ import annotations\n\nimport cProfile\nimport pstats\nfrom contextlib import AbstractContextManager, nullcontext\n\nimport cocotb._shutdown\nfrom cocotb_tools import _env\n\nprofiling_context: AbstractContextManager[None, None]\n\n\nif _env.as_bool(\"COCOTB_ENABLE_PROFILING\"):\n    _profile: cProfile.Profile\n\n    def _init() -> None:\n        global _profile\n        _profile = cProfile.Profile()\n\n        def finalize() -> None:\n            ps = pstats.Stats(_profile).sort_stats(\"cumulative\")\n            ps.dump_stats(\"cocotb.pstat\")\n\n        cocotb._shutdown.register(finalize)\n\n    class _profiling_context(AbstractContextManager[None, None]):\n        \"\"\"Context manager that profiles its contents.\"\"\"\n\n        def __enter__(self) -> None:\n            _profile.enable()\n\n        def __exit__(self, *excinfo: object) -> None:\n            _profile.disable()\n\n    profiling_context = _profiling_context()\n\nelse:\n\n    def _init() -> None:\n        pass\n\n    profiling_context = nullcontext()\n"
  },
  {
    "path": "src/cocotb/_py_compat.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nBackports and compatibility shims for newer python features.\n\nThese are for internal use - users should use a third party library like `six`\nif they want to use these shims in their own code\n\"\"\"\n\nfrom __future__ import annotations\n\nimport sys\n\n__all__ = (\"StrEnum\",)\n\nif sys.version_info >= (3, 11):\n    from enum import StrEnum\nelse:\n    from enum import Enum\n\n    class StrEnum(str, Enum):\n        def __str__(self) -> str:\n            return self.value\n"
  },
  {
    "path": "src/cocotb/_shutdown.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom typing import Callable\n\n_callbacks: list[Callable[[], None]] = []\n\"\"\"List of callbacks to be called when cocotb shuts down.\"\"\"\n\n\ndef register(cb: Callable[[], None]) -> None:\n    \"\"\"Register a callback to be called when cocotb shuts down.\"\"\"\n    _callbacks.append(cb)\n\n\ndef _shutdown() -> None:\n    \"\"\"Call all registered shutdown callbacks.\"\"\"\n    while _callbacks:\n        cb = _callbacks.pop(0)\n        cb()\n\n\ndef _init() -> None:\n    import cocotb.simulator  # noqa: PLC0415\n\n    cocotb.simulator.set_sim_event_callback(_shutdown)\n"
  },
  {
    "path": "src/cocotb/_task_manager.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"TaskManager and related code.\"\"\"\n\nfrom __future__ import annotations\n\nimport inspect\nimport sys\nfrom asyncio import CancelledError\nfrom bdb import BdbQuit\nfrom collections.abc import Awaitable, Callable, Coroutine\nfrom typing import Any, TypeVar, overload\n\nfrom cocotb._base_triggers import NullTrigger\nfrom cocotb.task import Task, current_task\nfrom cocotb.triggers import Event, Trigger\n\nif sys.version_info >= (3, 11):\n    from typing import Self\nelse:\n    from exceptiongroup import BaseExceptionGroup\n\nif sys.version_info >= (3, 10):\n    from typing import ParamSpec\n\n    P = ParamSpec(\"P\")\n\n\nT = TypeVar(\"T\")\n\n\nasync def _waiter(aw: Awaitable[T]) -> T:\n    return await aw\n\n\nclass TaskManager:\n    r\"\"\"An :term:`asynchronous context manager` which runs :term:`coroutine function`\\ s or :term:`awaitable`\\ s concurrently until all finish.\n\n    See :ref:`task_manager_tutorial` for detailed usage information.\n\n    Args:\n        default_continue_on_error: Default value for *continue_on_error* for child Tasks started by this TaskManager.\n        context_continue_on_error: Value for *continue_on_error* for the context block itself.\n\n            If not specified, defaults to the value of *default_continue_on_error*.\n\n    .. versionadded:: 2.1\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        default_continue_on_error: bool = False,\n        context_continue_on_error: bool | None = None,\n    ) -> None:\n        self._default_continue_on_error = default_continue_on_error\n        self._context_continue_on_error: bool = (\n            context_continue_on_error\n            if context_continue_on_error is not None\n            else default_continue_on_error\n        )\n\n        self._exceptions: set[BaseException] = set()\n        # dict value is per-Task continue_on_error setting\n        self._remaining_tasks: dict[Task[Any], bool] = {}\n        self._none_remaining = Event()\n        self._cancelled: bool = False\n        self._finishing: bool = False\n        self._entered: bool = False\n        # parent task will not exist if we aren't using this as a context manager\n        self._parent_task: Task[Any] | None = None\n\n        # Start with no remaining tasks\n        self._none_remaining.set()\n\n    def _ensure_can_add(self) -> None:\n        if self._cancelled:\n            raise RuntimeError(\"Cannot add new Tasks to TaskManager after error\")\n        elif self._finishing:\n            raise RuntimeError(\"Cannot add new Tasks to TaskManager after finishing\")\n        elif not self._entered:\n            raise RuntimeError(\n                \"Cannot add new Tasks to TaskManager before entering context\"\n            )\n        if current_task() is not self._parent_task:\n            raise RuntimeError(\"Cannot add new Tasks to TaskManager from another Task\")\n\n    def start_soon(\n        self,\n        aw: Awaitable[T],\n        *,\n        name: str | None = None,\n        continue_on_error: bool | None = None,\n    ) -> Task[T]:\n        r\"\"\"Await the *aw* argument concurrently.\n\n        Args:\n            aw: A :class:`~collections.abc.Awaitable` to :keyword:`await` concurrently.\n            name: A name to associate with the :class:`!Task` awaiting *aw*.\n            continue_on_error: Value of *continue_on_error* for this Task only.\n\n                If not specified, defaults to the value of the :class:`!TaskManager`'s *default_continue_on_error* argument.\n\n        Returns:\n            A :class:`~cocotb.task.Task` which is awaiting *aw* concurrently.\n        \"\"\"\n        self._ensure_can_add()\n\n        if isinstance(aw, Coroutine):\n            # This must come before Awaitable since Coroutine is a subclass of Awaitable\n            pass\n        elif isinstance(aw, Awaitable):\n            aw = _waiter(aw)\n        else:\n            raise TypeError(\n                f\"start_soon() expected an Awaitable, got {type(aw).__name__}\"\n            )\n        task = Task[T](aw, name=name)\n        self._add_task(task, continue_on_error=continue_on_error)\n        return task\n\n    @overload\n    def fork(\n        self,\n        coro_func: Callable[[], Coroutine[Trigger, None, T]],\n        /,\n    ) -> Task[T]: ...\n\n    @overload\n    def fork(\n        self, *, continue_on_error: bool\n    ) -> Callable[[Callable[[], Coroutine[Trigger, None, T]]], Task[T]]: ...\n\n    def fork(\n        self,\n        coro_func: Callable[..., Coroutine[Trigger, None, T]] | None = None,\n        *,\n        continue_on_error: bool | None = None,\n    ) -> Task[T] | Callable[[Callable[[], Coroutine[Trigger, None, T]]], Task[T]]:\n        r\"\"\"Decorate a coroutine function to run it concurrently.\n\n        Args:\n            coro_func: A :term:`coroutine function` to run concurrently. Typically only passed as a decorator.\n            continue_on_error: Value of *continue_on_error* for this Task only.\n\n                If not specified, defaults to the value of the :class:`!TaskManager`'s *default_continue_on_error* argument.\n                Passing this requires calling the :meth:`fork` method before decorating the coroutine function.\n\n        Returns:\n            A :class:`~cocotb.task.Task` which is running *coro_func* concurrently.\n\n        .. code-block:: python\n\n            async with TaskManager() as tm:\n\n                @tm.fork\n                async def my_func():\n                    # Do stuff\n                    ...\n\n                @tm.fork(continue_on_error=True)\n                async def other_func():\n                    # Do other stuff in parallel to my_func\n                    ...\n        \"\"\"\n        self._ensure_can_add()\n\n        if coro_func is None:\n            if continue_on_error is None:\n                raise TypeError(\n                    \"Missing required keyword-only argument: 'continue_on_error'\"\n                )\n\n            def deco(\n                coro: Callable[[], Coroutine[Trigger, None, T]],\n            ) -> Task[T]:\n                return self.fork(  # type: ignore[call-overload]\n                    coro,\n                    continue_on_error=continue_on_error,\n                )\n\n            return deco\n\n        if not inspect.iscoroutinefunction(coro_func):\n            raise TypeError(\n                f\"fork() expected a coroutine function, got {type(coro_func).__name__}\"\n            )\n        task = Task[T](coro_func(), name=coro_func.__name__)\n        self._add_task(task, continue_on_error=continue_on_error)\n        return task\n\n    def _add_task(\n        self,\n        task: Task[Any],\n        *,\n        continue_on_error: bool | None = None,\n    ) -> None:\n        # Track the Task and store per-Task continue_on_error setting\n        task._add_done_callback(self._done_callback)\n        if continue_on_error is None:\n            continue_on_error = self._default_continue_on_error\n        self._remaining_tasks[task] = continue_on_error\n        self._none_remaining.clear()\n\n        # Schedule the Task to run soon\n        task._ensure_started()\n\n    def _done_callback(self, task: Task[Any]) -> None:\n        \"\"\"Callback run when a child Task finishes.\"\"\"\n        continue_on_error = self._remaining_tasks.pop(task)\n        if not self._remaining_tasks:\n            self._none_remaining.set()\n\n        # If a child Task failed, cancel all other child Tasks.\n        if not task.cancelled() and (exc := task.exception()) is not None:\n            self._exceptions.add(exc)\n            if not continue_on_error:\n                self._cancel()\n\n    def _cancel(self) -> None:\n        \"\"\"Cancel all unfinished child Tasks.\"\"\"\n        if self._cancelled:\n            return\n        self._cancelled = True\n\n        # If a child Task fails while we are in the middle of a TaskManager block,\n        # cancel the parent Task to force the block to end.\n        if not self._finishing and self._parent_task is not None:\n            self._parent_task.cancel()\n\n        # Cancel all child Tasks.\n        for task in self._remaining_tasks:\n            task.cancel()\n\n    async def __aenter__(self) -> Self:\n        if self._finishing:\n            raise RuntimeError(\"Cannot re-enter finished TaskManager context\")\n        self._entered = True\n        self._parent_task = current_task()\n        return self\n\n    async def __aexit__(\n        self, exc_type: object, exc: BaseException | None, traceback: object\n    ) -> None:\n        self._finishing = True\n\n        if self._parent_task is not None and self._cancelled:\n            # The context block was cancelled due to a child Task failure.\n            if isinstance(exc, CancelledError):\n                # Suppress CancelledError in this case to allow child Tasks to finish cancelling.\n                exc = None\n                assert self._parent_task is not None\n                self._parent_task._uncancel()\n            else:\n                # The context block ignored the cancellation. Hard fail the test.\n                # There is a special case in Task if a cancelled Task finishes without\n                # raising CancelledError, it fails the test. So we just await *something*\n                # here to hit that code path.\n                # TODO Make this force a test failure.\n                self._cancel()\n                await NullTrigger()\n        elif exc is not None:\n            if isinstance(exc, CancelledError):\n                # Something else cancelled the parent task. Propagate CancelledError.\n                self._cancel()\n                return None  # re-raise CancelledError\n            elif isinstance(exc, (KeyboardInterrupt, SystemExit, BdbQuit)):\n                # Certain BaseExceptions should be immediately propagated like they are in Task.\n                self._cancel()\n                return None  # re-raise exception\n            elif not self._context_continue_on_error:\n                # Block finished with an exception and we are not continuing on error.\n                self._cancel()\n\n        # Wait for all Tasks to finish / finish cancelling.\n        try:\n            await self._none_remaining.wait()\n        except CancelledError:\n            # Cancel all child Tasks if the current Task is cancelled by the user while\n            # waiting for all child Tasks to finish. If the TaskManager is already\n            # cancelling due to a child Task failure, this will no-op.\n            self._cancel()\n            raise\n        except BaseException:\n            # The current Task failed while waiting for child Tasks to finish.\n            # This is likely because we ignored a CancelledError since there is no other\n            # way to fail this await AFAICT. Cancel children and let it pass up as there's\n            # nothing we can do.\n            # TODO Make this force a test failure. Special case KeyboardInterrupt/SystemExit/BdbQuit\n            self._cancel()\n            raise\n\n        self._finished = True\n\n        # Build BaseExceptionGroup if there were any errors. Ignore CancelledError.\n        if exc is not None and not isinstance(exc, CancelledError):\n            self._exceptions.add(exc)\n        if self._exceptions:\n            # BaseExceptionGroup constructor will automatically return an ExceptionGroup if all elements are Exceptions.\n            raise BaseExceptionGroup(\n                \"TaskManager finished with errors\", tuple(self._exceptions)\n            )\n\n        # Return True to handle suppressing CancelledError if there were no exceptions\n        return True  # type: ignore[return-value]  # __aexit__ can return True\n"
  },
  {
    "path": "src/cocotb/_test_factory.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport inspect\nimport logging\nimport warnings\nfrom collections.abc import Coroutine, Sequence\nfrom itertools import product\nfrom types import FrameType, FunctionType\nfrom typing import Callable, cast, overload\n\nfrom cocotb._base_triggers import Trigger\nfrom cocotb._decorators import Test\nfrom cocotb.simtime import TimeUnit\n\n\nclass TestFactory:\n    \"\"\"Factory to automatically generate tests.\n\n    Args:\n        test_function: A Callable that returns the test Coroutine.\n            Must take *dut* as the first argument.\n        *args: Remaining arguments are passed directly to the test function.\n            Note that these arguments are not varied. An argument that\n            varies with each test must be a keyword argument to the\n            test function.\n        **kwargs: Remaining keyword arguments are passed directly to the test function.\n            Note that these arguments are not varied. An argument that\n            varies with each test must be a keyword argument to the\n            test function.\n\n    Assuming we have a common test function that will run a test. This test\n    function will take keyword arguments (for example generators for each of\n    the input interfaces) and generate tests that call the supplied function.\n\n    This Factory allows us to generate sets of tests based on the different\n    permutations of the possible arguments to the test function.\n\n    For example, if we have a module that takes backpressure, has two configurable\n    features where enabling ``feature_b`` requires ``feature_a`` to be active, and\n    need to test against data generation routines ``gen_a`` and ``gen_b``:\n\n    >>> tf = TestFactory(test_function=run_test)\n    >>> tf.add_option(name=\"data_in\", optionlist=[gen_a, gen_b])\n    >>> tf.add_option(\"backpressure\", [None, random_backpressure])\n    >>> tf.add_option(\n    ...     (\"feature_a\", \"feature_b\"), [(False, False), (True, False), (True, True)]\n    ... )\n    >>> tf.generate_tests()\n\n    We would get the following tests:\n\n        * ``gen_a`` with no backpressure and both features disabled\n        * ``gen_a`` with no backpressure and only ``feature_a`` enabled\n        * ``gen_a`` with no backpressure and both features enabled\n        * ``gen_a`` with ``random_backpressure`` and both features disabled\n        * ``gen_a`` with ``random_backpressure`` and only ``feature_a`` enabled\n        * ``gen_a`` with ``random_backpressure`` and both features enabled\n        * ``gen_b`` with no backpressure and both features disabled\n        * ``gen_b`` with no backpressure and only ``feature_a`` enabled\n        * ``gen_b`` with no backpressure and both features enabled\n        * ``gen_b`` with ``random_backpressure`` and both features disabled\n        * ``gen_b`` with ``random_backpressure`` and only ``feature_a`` enabled\n        * ``gen_b`` with ``random_backpressure`` and both features enabled\n\n    The tests are appended to the calling module for auto-discovery.\n\n    Tests are simply named ``test_function_N``. The docstring for the test (hence\n    the test description) includes the name and description of each generator.\n\n    .. versionchanged:: 1.5\n        Groups of options are now supported\n\n    .. versionchanged:: 2.0\n        You can now pass :func:`cocotb.test` decorator arguments when generating tests.\n\n    .. deprecated:: 2.0\n        Use :func:`cocotb.parametrize` instead.\n    \"\"\"\n\n    def __init__(\n        self,\n        test_function: Callable[..., Coroutine[Trigger, None, None]],\n        *args: object,\n        **kwargs: object,\n    ) -> None:\n        warnings.warn(\n            \"TestFactory is deprecated, use `@cocotb.parametrize` instead\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        self.test_function = test_function\n        self.args = args\n        self.kwargs_constant = kwargs\n        self.kwargs: dict[\n            str | Sequence[str],\n            Sequence[object] | Sequence[Sequence[object]],\n        ] = {}\n        self._log = logging.getLogger(f\"TestFactory({self.test_function.__name__})\")\n\n    @overload\n    def add_option(self, name: str, optionlist: Sequence[object]) -> None: ...\n\n    @overload\n    def add_option(\n        self, name: Sequence[str], optionlist: Sequence[Sequence[object]]\n    ) -> None: ...\n\n    def add_option(\n        self,\n        name: str | Sequence[str],\n        optionlist: Sequence[object] | Sequence[Sequence[object]],\n    ) -> None:\n        \"\"\"Add a named option to the test.\n\n        Args:\n            name:\n                An option name, or an iterable of several option names. Passed to test as keyword arguments.\n\n            optionlist:\n                A list of possible options for this test knob.\n                If N names were specified, this must be a list of N-tuples or\n                lists, where each element specifies a value for its respective\n                option.\n\n        .. versionchanged:: 1.5\n            Groups of options are now supported\n        \"\"\"\n        if not isinstance(name, str):\n            optionlist = cast(\"Sequence[Sequence[object]]\", optionlist)\n            for opt in optionlist:\n                if len(name) != len(opt):\n                    raise ValueError(\n                        \"Mismatch between number of options and number of option values in group\"\n                    )\n        self.kwargs[name] = optionlist\n\n    def generate_tests(\n        self,\n        *,\n        prefix: str | None = None,\n        postfix: str | None = None,\n        stacklevel: int = 0,\n        name: str | None = None,\n        timeout_time: float | None = None,\n        timeout_unit: TimeUnit = \"step\",\n        expect_fail: bool = False,\n        expect_error: type[BaseException] | tuple[type[BaseException], ...] = (),\n        skip: bool = False,\n        stage: int = 0,\n    ) -> None:\n        \"\"\"\n        Generate an exhaustive set of tests using the cartesian product of the\n        possible keyword arguments.\n\n        The generated tests are appended to the namespace of the calling\n        module.\n\n        Args:\n            prefix:\n                Text string to append to start of ``test_function`` name when naming generated test cases.\n                This allows reuse of a single ``test_function`` with multiple :class:`TestFactories <.TestFactory>` without name clashes.\n\n                .. deprecated:: 2.0\n                    Use the more flexible ``name`` field instead.\n\n            postfix:\n                Text string to append to end of ``test_function`` name when naming generated test cases.\n                This allows reuse of a single ``test_function`` with multiple :class:`TestFactories <.TestFactory>` without name clashes.\n\n                .. deprecated:: 2.0\n                    Use the more flexible ``name`` field instead.\n            stacklevel:\n                Which stack level to add the generated tests to. This can be used to make a custom TestFactory wrapper.\n\n            name:\n                Passed as ``name`` argument to :func:`cocotb.test`.\n\n                .. versionadded:: 2.0\n\n            timeout_time:\n                Passed as ``timeout_time`` argument to :func:`cocotb.test`.\n\n                .. versionadded:: 2.0\n\n            timeout_unit:\n                Passed as ``timeout_unit`` argument to :func:`cocotb.test`.\n\n                .. versionadded:: 2.0\n\n            expect_fail:\n                Passed as ``expect_fail`` argument to :func:`cocotb.test`.\n\n                .. versionadded:: 2.0\n\n            expect_error:\n                Passed as ``expect_error`` argument to :func:`cocotb.test`.\n\n                .. versionadded:: 2.0\n\n            skip:\n                Passed as ``skip`` argument to :func:`cocotb.test`.\n\n                .. versionadded:: 2.0\n\n            stage:\n                Passed as ``stage`` argument to :func:`cocotb.test`.\n\n                .. versionadded:: 2.0\n        \"\"\"\n\n        if prefix is not None:\n            warnings.warn(\n                \"``prefix`` argument is deprecated. Use the more flexible ``name`` field instead.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n        else:\n            prefix = \"\"\n\n        if postfix is not None:\n            warnings.warn(\n                \"``postfix`` argument is deprecated. Use the more flexible ``name`` field instead.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n        else:\n            postfix = \"\"\n\n        # trust the user puts a reasonable stacklevel in\n        glbs = cast(\"FrameType\", inspect.stack()[stacklevel][0].f_back).f_globals\n\n        test_func_name = self.test_function.__qualname__ if name is None else name\n\n        for index, testoptions in enumerate(\n            dict(zip(self.kwargs, v)) for v in product(*self.kwargs.values())\n        ):\n            name = f\"{prefix}{test_func_name}{postfix}_{(index + 1):03d}\"\n            doc: str = \"Automatically generated test\\n\\n\"\n\n            # preprocess testoptions to split tuples\n            testoptions_split: dict[str, Sequence[object]] = {}\n            for optname, optvalue in testoptions.items():\n                if isinstance(optname, str):\n                    optvalue = cast(\"Sequence[object]\", optvalue)\n                    testoptions_split[optname] = optvalue\n                else:\n                    # previously checked in add_option; ensure nothing has changed\n                    optvalue = cast(\"Sequence[Sequence[object]]\", optvalue)\n                    assert len(optname) == len(optvalue)\n                    for n, v in zip(optname, optvalue):\n                        testoptions_split[n] = v\n\n            for optname, optvalue in testoptions_split.items():\n                if callable(optvalue):\n                    optvalue = cast(\"FunctionType\", optvalue)\n                    if optvalue.__doc__ is None:\n                        desc = \"No docstring supplied\"\n                    else:\n                        desc = optvalue.__doc__.split(\"\\n\")[0]\n                    doc += f\"\\t{optname}: {optvalue.__qualname__} ({desc})\\n\"\n                else:\n                    doc += f\"\\t{optname}: {optvalue!r}\\n\"\n\n            kwargs = self.kwargs_constant.copy()\n            kwargs.update(testoptions_split)\n\n            if name in glbs:\n                self._log.error(\n                    \"Overwriting %s in module %s. \"\n                    \"This causes a previously defined testcase not to be run. \"\n                    \"Consider using the `name`, `prefix`, or `postfix` arguments to augment the name.\",\n                    name,\n                    glbs[\"__name__\"],\n                )\n\n            timeout = (timeout_time, timeout_unit) if timeout_time is not None else None\n\n            if isinstance(expect_error, type):\n                expect_error = (expect_error,)\n\n            test = Test(\n                func=self.test_function,\n                args=self.args,\n                kwargs=kwargs,\n                name=name,\n                module=glbs[\"__name__\"],\n                doc=doc,\n                timeout=timeout,\n                expect_fail=expect_fail,\n                expect_error=expect_error,\n                skip=skip,\n                stage=stage,\n            )\n\n            glbs[test.name] = test\n"
  },
  {
    "path": "src/cocotb/_test_manager.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport pdb\nimport sys\nfrom asyncio import CancelledError\nfrom collections.abc import Coroutine\nfrom typing import (\n    Any,\n    Callable,\n    NoReturn,\n)\n\nimport cocotb\nimport cocotb._event_loop\nfrom cocotb._base_triggers import Event, NullTrigger, Trigger, TriggerCallback\nfrom cocotb._deprecation import deprecated\nfrom cocotb._extended_awaitables import SimTimeoutError\nfrom cocotb._gpi_triggers import Timer\nfrom cocotb.simtime import TimeUnit\nfrom cocotb.task import ResultType, Task\nfrom cocotb_tools import _env\n\nif sys.version_info < (3, 11):\n    from exceptiongroup import BaseExceptionGroup\n\n_pdb_on_exception = _env.as_bool(\"COCOTB_PDB_ON_EXCEPTION\")\n\n\nclass TestManager:\n    \"\"\"State of the currently executing Test.\"\"\"\n\n    # TODO\n    # Make the tasks list a TaskManager.\n    # Make shutdown errors and outcome be an ExceptionGroup from that TaskManager.\n    # Replace result() with passing the outcome to the done callback.\n    # Make this and Task the same object which is a Coroutine.\n    # Reimplement the logic in the body of an async function.\n    # Make RunningTest a normal Task that the RegressionManager runs and registers a\n    #  done callback with.\n\n    def __init__(\n        self,\n        test_coro: Coroutine[Trigger, None, Any],\n        *,\n        name: str,\n        timeout: tuple[float, TimeUnit] | None = None,\n        test_complete_cb: Callable[[], None],\n    ) -> None:\n        self._timeout = timeout\n        self._timeout_cb: TriggerCallback | None = None\n        self._test_complete_cb: Callable[[], None] = test_complete_cb\n\n        # We create the main task here so that the init checks can be done immediately.\n        self._main_task = Task[None](test_coro, name=f\"Test {name}\")\n        self._tasks: list[Task[Any]] = []\n        self._excs: list[BaseException] = []\n        self._finishing: bool = False\n        self._complete: bool = False\n        self._done = Event()\n\n    def _test_done_callback(self, task: Task[None]) -> None:\n        self.remove_task(task)\n        # If cancelled, end the Test without additional error. This case would only\n        # occur if a child threw a CancelledError or if the Test was forced to shutdown.\n        if task.cancelled():\n            self._abort()\n            return\n        # Handle outcome appropriately and shut down the Test.\n        e = task.exception()\n        if e is None:\n            self._abort()\n        elif isinstance(e, EndTest):\n            msg_str = f\": {e.msg}\" if e.msg else \"\"\n            task._log.info(\"Test stopped early by this task%s\", msg_str)\n            self._abort()\n        else:\n            self._abort(e)\n\n    def start(self) -> None:\n        # set global current test manager\n        global _current_test\n        _current_test = self\n\n        # start main task\n        self._main_task._add_done_callback(self._test_done_callback)\n        self._main_task._ensure_started()\n        self._tasks.append(self._main_task)\n\n        # start timeout if specified\n        if self._timeout is not None:\n            self._timeout_cb = Timer(*self._timeout)._register(self._on_timeout)\n\n        cocotb._event_loop._inst.run()\n\n    def _on_timeout(self) -> None:\n        self._timeout_cb = None\n        self._abort(SimTimeoutError())\n\n    def exception(self) -> BaseException | None:\n        if self._excs:\n            if len(self._excs) == 1:\n                return self._excs[0]\n            else:\n                return BaseExceptionGroup(\"Multiple exceptions in test\", self._excs)\n        return None\n\n    def result(self) -> None:\n        exc = self.exception()\n        if exc:\n            raise exc\n\n    def done(self) -> bool:\n        \"\"\"Return whether the test has completed.\"\"\"\n        return self._complete\n\n    def cancel(self, msg: str | None = None) -> None:\n        \"\"\"End the test prematurely.\"\"\"\n        if msg is not None:\n            exc = CancelledError(msg)\n        else:\n            exc = CancelledError()\n        self._abort(exc)\n\n    def _abort(self, exc: BaseException | None = None) -> None:\n        \"\"\"Shutdown the test\"\"\"\n\n        if exc is not None:\n            self._excs.append(exc)\n\n        if self._finishing:\n            return\n        self._finishing = True\n\n        # Break into pdb on test end before all Tasks are killed.\n        if _pdb_on_exception and exc is not None:\n            try:\n                pdb.post_mortem(exc.__traceback__)\n            except BaseException:\n                pdb.set_trace()\n\n        # Cancel the timeout if it is running.\n        if self._timeout_cb is not None:\n            self._timeout_cb.cancel()\n\n        # Cancel Tasks.\n        for task in self._tasks[:]:\n            task._cancel_now()\n\n        # Register function to clean up global state once all Tasks have ended.\n        if self._done.is_set():\n            self._on_complete()\n        else:\n            self._done.wait()._register(self._on_complete)\n\n    def _on_complete(self) -> None:\n        # Clear the current global current test manager\n        global _current_test\n        _current_test = None\n\n        self._complete = True\n\n        # Tell RegressionManager the test is complete\n        self._test_complete_cb()\n\n    def add_task(self, task: Task[Any]) -> None:\n        task._add_done_callback(self._task_done_callback)\n        self._tasks.append(task)\n        self._done.clear()\n\n    def remove_task(self, task: Task[Any]) -> None:\n        self._tasks.remove(task)\n        if not self._tasks:\n            self._done.set()\n\n    def _task_done_callback(self, task: Task[Any]) -> None:\n        self.remove_task(task)\n        # if cancelled, do nothing\n        if task.cancelled():\n            return\n        # if there's a Task awaiting this one, don't fail\n        if task.complete._callbacks:\n            return\n        # if no failure, do nothing\n        e = task.exception()\n        if e is None:\n            return\n        elif isinstance(e, EndTest):\n            msg_str = f\": {e.msg}\" if e.msg else \"\"\n            task._log.info(\"Test stopped early by this task%s\", msg_str)\n            self._abort()\n        else:\n            self._abort(e)\n\n\ndef start_soon(\n    coro: Task[ResultType] | Coroutine[Trigger, None, ResultType],\n    *,\n    name: str | None = None,\n) -> Task[ResultType]:\n    \"\"\"\n    Schedule a :term:`coroutine` to be run concurrently in a :class:`~cocotb.task.Task`.\n\n    Note that this is not an :keyword:`async` function,\n    and the new task will not execute until the calling task yields control.\n\n    Args:\n        coro: A :class:`!Task` or :term:`!coroutine` to be run concurrently.\n        name:\n            The task's name.\n\n            .. versionadded:: 2.0\n\n    Returns:\n        The :class:`~cocotb.task.Task` that is scheduled to be run.\n\n    .. versionadded:: 1.6\n    \"\"\"\n    task = create_task(coro, name=name)\n    task._ensure_started()\n    return task\n\n\n@deprecated(\"Use ``cocotb.start_soon`` instead.\")\nasync def start(\n    coro: Task[ResultType] | Coroutine[Trigger, None, ResultType],\n    *,\n    name: str | None = None,\n) -> Task[ResultType]:\n    \"\"\"\n    Schedule a :term:`coroutine` to be run concurrently, then yield control to allow pending tasks to execute.\n\n    The calling task will resume execution before control is returned to the simulator.\n\n    When the calling task resumes, the newly scheduled task may have completed,\n    raised an Exception, or be pending on a :class:`~cocotb.triggers.Trigger`.\n\n    Args:\n        coro: A :class:`!Task` or :term:`!coroutine` to be run concurrently.\n        name:\n            The task's name.\n\n            .. versionadded:: 2.0\n\n    Returns:\n        The :class:`~cocotb.task.Task` that has been scheduled and allowed to execute.\n\n    .. versionadded:: 1.6\n\n    .. deprecated:: 2.0\n        Use :func:`cocotb.start_soon` instead.\n        If you need the scheduled Task to start before continuing the current Task,\n        use an :class:`.Event` to block the current Task until the scheduled Task starts,\n        like so:\n\n        .. code-block:: python\n\n            async def coro(started: Event) -> None:\n                started.set()\n                # Do stuff...\n\n\n            task_started = Event()\n            task = cocotb.start_soon(coro(task_started))\n            await task_started.wait()\n    \"\"\"\n    task = start_soon(coro, name=name)\n    await NullTrigger()\n    return task\n\n\ndef create_task(\n    coro: Task[ResultType] | Coroutine[Trigger, None, ResultType],\n    *,\n    name: str | None = None,\n) -> Task[ResultType]:\n    \"\"\"\n    Construct a :term:`!coroutine` into a :class:`~cocotb.task.Task` without scheduling the task.\n\n    The task can later be scheduled with :func:`cocotb.start` or :func:`cocotb.start_soon`.\n\n    Args:\n        coro: A :class:`!Task` or a :term:`!coroutine` to be turned into a :class:`!Task`.\n        name:\n            The task's name.\n\n            .. versionadded:: 2.0\n\n    Returns:\n        Either the provided :class:`~cocotb.task.Task` or a new Task wrapping the coroutine.\n\n    .. versionadded:: 1.6\n    \"\"\"\n    if _current_test is None:\n        raise RuntimeError(\"No test is currently running; cannot schedule new Task.\")\n\n    if isinstance(coro, Task):\n        # We do not add the done callback here, so that custom Tasks are not considered\n        # \"toplevel\" tasks and end the test when they fail.\n        if name is not None:\n            coro.set_name(name)\n        return coro\n\n    task = Task[ResultType](coro, name=name)\n    _current_test.add_task(task)\n\n    return task\n\n\nclass TestSuccess(BaseException):\n    \"\"\"Implementation of :func:`pass_test`.\n\n    Users are *not* intended to catch or raise this exception type.\n    \"\"\"\n\n    def __init__(self, msg: str | None) -> None:\n        super().__init__(msg)\n        self.msg = msg\n\n\n@deprecated(\n    \"Use `cocotb.skip` to skip a test, or use `cocotb.end_test` to end a test while respecting expected failures.\"\n)\ndef pass_test(msg: str | None = None) -> NoReturn:\n    \"\"\"Force a test to pass.\n\n    The test will end after this function is called.\n    The outcome of the test will be forced to pass,\n    even if a :deco:`cocotb.xfail` decorator is used,\n    or ``expect_error`` and ``expect_fail`` arguments to :deco:`cocotb.test` are passed.\n\n    Args:\n        msg: The message to display when the test passes.\n\n    .. versionadded:: 2.0\n\n    .. deprecated:: 2.1\n        Forcing a test to pass is considered bad practice.\n        Use :func:`cocotb.skip` if you want to end the test immediately and force the outcome to 'skipped'.\n        Or use :func:`cocotb.end_test` if you want to end the test immediately while respecting expected failures.\n    \"\"\"\n    raise TestSuccess(msg)\n\n\nclass EndTest(BaseException):\n    \"\"\"Implementation of :func:`cocotb.end_test`.\n\n    Users are *not* intended to catch or raise this exception type.\n    \"\"\"\n\n    def __init__(self, msg: str | None) -> None:\n        super().__init__(msg)\n        self.msg = msg\n\n\ndef end_test(msg: str | None = None) -> NoReturn:\n    \"\"\"End a test.\n\n    The test will end after this function is called as if it passed.\n    However, any :deco:`cocotb.xfail` decorators\n    or ``expect_error`` and ``expect_fail`` arguments to :func:`cocotb.test` will be respected.\n    Meaning, if they are used, the test will fail, as a failure was expected.\n\n    Args:\n        msg: The message to display when the test ends.\n    \"\"\"\n    raise EndTest(msg)\n\n\n_current_test: TestManager | None = None\n\"\"\"The currently executing test's state.\"\"\"\n"
  },
  {
    "path": "src/cocotb/_utils.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Utilities for implementors.\"\"\"\n\nfrom __future__ import annotations\n\nimport sys\nimport traceback\nimport types\nfrom collections.abc import Iterable\nfrom enum import Enum, IntEnum\nfrom functools import wraps\nfrom types import TracebackType\nfrom typing import (\n    Any,\n    TypeVar,\n    cast,\n    overload,\n)\n\nif sys.version_info >= (3, 10):\n    from typing import TypeAlias\n\nExceptionTuple: TypeAlias = tuple[type[BaseException], BaseException, TracebackType]\n\n\n@overload\ndef remove_traceback_frames(\n    tb_or_exc: ExceptionTuple, frame_names: list[str]\n) -> ExceptionTuple: ...\n\n\n@overload\ndef remove_traceback_frames(\n    tb_or_exc: BaseException, frame_names: list[str]\n) -> BaseException: ...\n\n\n@overload\ndef remove_traceback_frames(\n    tb_or_exc: TracebackType, frame_names: list[str]\n) -> TracebackType: ...\n\n\ndef remove_traceback_frames(\n    tb_or_exc: ExceptionTuple | BaseException | TracebackType,\n    frame_names: list[str],\n) -> ExceptionTuple | BaseException | TracebackType:\n    \"\"\"\n    Strip leading frames from a traceback\n\n    Args:\n        tb_or_exc:\n            Object to strip frames from. If an exception is passed, creates\n            a copy of the exception with a new shorter traceback. If a tuple\n            from `sys.exc_info` is passed, returns the same tuple with the\n            traceback shortened\n        frame_names:\n            Names of the frames to strip, which must be present at the top of the Traceback or Exception.\n\n    Returns:\n        Traceback or Exception passed to the function with the *frame_names* stripped out.\n    \"\"\"\n    # self-invoking overloads\n    if isinstance(tb_or_exc, BaseException):\n        exc: BaseException = tb_or_exc\n        return exc.with_traceback(\n            remove_traceback_frames(\n                cast(\"TracebackType\", exc.__traceback__), frame_names\n            )\n        )\n    elif isinstance(tb_or_exc, tuple):\n        exc_type, exc_value, exc_tb = tb_or_exc\n        exc_tb = remove_traceback_frames(exc_tb, frame_names)\n        return exc_type, exc_value, exc_tb\n    # base case\n    else:\n        tb: TracebackType = tb_or_exc\n        for frame_name in frame_names:\n            # the assert and cast are there assuming the frame_names being removed are correct\n            assert tb.tb_frame.f_code.co_name == frame_name\n            tb = cast(\"TracebackType\", tb.tb_next)\n        return tb\n\n\ndef walk_coro_stack(\n    coro: types.CoroutineType[Any, Any, Any],\n) -> Iterable[tuple[types.FrameType, int]]:\n    \"\"\"Walk down the coroutine stack, starting at *coro*.\n\n    Args:\n        coro: The :class:`coroutine` object to traverse.\n\n    Yields:\n        Frame and line number of each frame in the coroutine.\n    \"\"\"\n    c: types.CoroutineType[Any, Any, Any] | None = coro\n    while c is not None:\n        try:\n            f = c.cr_frame\n        except AttributeError:\n            break\n        else:\n            c = c.cr_await\n        if f is not None:\n            yield (f, f.f_lineno)\n\n\ndef extract_coro_stack(\n    coro: types.CoroutineType[Any, Any, Any], limit: int | None = None\n) -> traceback.StackSummary:\n    r\"\"\"Create a list of pre-processed entries from the coroutine stack.\n\n    This is based on :func:`traceback.extract_tb`.\n\n    If *limit* is omitted or ``None``, all entries are extracted.\n    The list is a :class:`traceback.StackSummary` object, and\n    each entry in the list is a :class:`traceback.FrameSummary` object\n    containing attributes ``filename``, ``lineno``, ``name``, and ``line``\n    representing the information that is usually printed for a stack\n    trace. The line is a string with leading and trailing\n    whitespace stripped; if the source is not available it is ``None``.\n\n    Args:\n        coro: The :class:`coroutine` object from which to extract a stack.\n        level: The maximum number of frames from *coro*\\ s stack to extract.\n\n    Returns:\n        The stack of *coro*.\n    \"\"\"\n    return traceback.StackSummary.extract(walk_coro_stack(coro), limit=limit)\n\n\nEnumT = TypeVar(\"EnumT\", bound=Enum)\n\n\nclass DocEnum(Enum):\n    \"\"\"Like :class:`enum.Enum`, but allows documenting enum values.\n\n    Documentation for enum members can be optionally added by setting enum values to a tuple of the intended value and the docstring.\n    This adds the provided docstring to the ``__doc__`` field of the enum value.\n\n    .. code-block:: python\n\n        class MyEnum(DocEnum):\n            \\\"\\\"\\\"Class documentation\\\"\\\"\\\"\n\n            VALUE1 = 1, \"Value documentation\"\n            VALUE2 = 2  # no documentation\n\n    Taken from :ref:`this StackOverflow answer <https://stackoverflow.com/questions/50473951/how-can-i-attach-documentation-to-members-of-a-python-enum/50473952#50473952>`\n    by :ref:`Eric Wieser <https://stackoverflow.com/users/102441/eric>`,\n    as recommended by the ``enum_tools`` documentation.\n    \"\"\"\n\n    def __new__(cls: type[EnumT], value: object, doc: str | None = None) -> EnumT:\n        # super().__new__() assumes the value is already an enum value\n        # so we side step that and create a raw object and fill in _value_\n        self = object.__new__(cls)\n        self._value_ = value\n        if doc is not None:\n            self.__doc__ = doc\n        return self\n\n\nIntEnumT = TypeVar(\"IntEnumT\", bound=IntEnum)\n\n\nclass DocIntEnum(IntEnum):\n    \"\"\"Like DocEnum but for :class:`IntEnum` enum types.\"\"\"\n\n    def __new__(cls: type[IntEnumT], value: int, doc: str | None = None) -> IntEnumT:\n        self = int.__new__(cls, value)\n        self._value_ = value\n        if doc is not None:\n            self.__doc__ = doc\n        return self\n\n\nT = TypeVar(\"T\")\n\n\ndef singleton(orig_cls: type[T]) -> type[T]:\n    \"\"\"Class decorator which turns a type into a Singleton type.\"\"\"\n    orig_new = orig_cls.__new__\n    orig_init = orig_cls.__init__\n    instance = None\n\n    @wraps(orig_cls.__new__)\n    def __new__(cls: type[T], *args: object, **kwargs: object) -> T:\n        nonlocal instance\n        if instance is None:\n            instance = orig_new(cls, *args, **kwargs)\n            orig_init(instance, *args, **kwargs)\n        return instance\n\n    @wraps(orig_cls.__init__)\n    def __init__(self: T, *args: object, **kwargs: object) -> None:\n        pass\n\n    # I'd like to get rid of type ignoring \"assignment\", but I'm not sure how to convince\n    # mypy that the new function definitions are compatible with the old.\n    orig_cls.__new__ = __new__  # type: ignore[method-assign, assignment]\n    orig_cls.__init__ = __init__  # type: ignore[method-assign, assignment]\n    return orig_cls\n\n\ndef pointer_str(obj: object) -> str:\n    \"\"\"Get the memory address of *obj* as used in :meth:`object.__repr__`.\n\n    This is equivalent to ``sprintf(\"%p\", id(obj))``, but Python does not\n    support ``%p``.\n    \"\"\"\n    full_repr = object.__repr__(obj)  # gives \"<{type} object at {address}>\"\n    return full_repr.rsplit(\" \", 1)[1][:-1]\n\n\ndef safe_divide(a: float, b: float) -> float:\n    \"\"\"Used when computing time ratios to ensure no exception is raised if either time is 0.\"\"\"\n    try:\n        return a / b\n    except ZeroDivisionError:\n        if a == 0:\n            return float(\"nan\")\n        else:\n            return float(\"inf\")\n"
  },
  {
    "path": "src/cocotb/_vendor/README.md",
    "content": "# Third-party code\n\nThis directory contains code from various third parties, which is distributed\ntogether with cocotb. Note that some code may be licensed differently from\ncocotb itself; refer to the individual files for details.\n\n## SystemVerilog VPI\n\nThe headers `vpi/vpi_user.h` and `vpi/sv_vpi_user.sv` are part of the\nSystemVerilog LRM.\n\n## VHPI\n\nThe header `vhpi/vhpi_user.h` is part of the VHPI/VHDL standard.\n\n## ModelSim/Questa FLI\n\nThe header `fli/mti.h` is part of the Siemens EDA Questa distribution and\ndistributed under the\n[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0).\n\nThe header `fli/acc_user.h` defines the PLI ACC (access) routines.\nThe file is part of the\n[Verilog 2001 LRM](https://standards.ieee.org/ieee/1364/2052/) (IEEE 1364-2001),\nAnnex E, and is shipped in a version as modified by Siemens EDA.\n\nThe header `fli/acc_vhdl.h` is a ModelSim/Questa extension to the PLI standard to\nsupport VHDL.\n\n## TCL\n\nThe files in the `tcl` directory are part of the\n[Tcl 8.6.5 source code](https://www.tcl.tk/software/tcltk/download.html), which\nis distributed under a BSD license. Refer to `tcl/license.terms` for details.\n"
  },
  {
    "path": "src/cocotb/_vendor/fli/acc_user.h",
    "content": "/*****************************************************************************\n * acc_user.h\n *\n * IEEE 1364-2001 Verilog HDL Programming Language Interface (PLI).\n *\n * This file contains the constant definitions, structure definitions, and\n * routine declarations for the Verilog Programming Language Interface ACC\n * access routines.\n *\n ****************************************************************************/\n\n/* $Id: //dvt/mti/rel/2021.4/src/vsim/acc_user.h#1 $ */\n\n#ifndef ACC_USER_H\n#define ACC_USER_H\n\n#ifdef  __cplusplus\nextern \"C\" {\n#endif\n\n/*---------------------------------------------------------------------------*/\n/*--------------------------- Portability Help ------------------------------*/\n/*---------------------------------------------------------------------------*/\n/* Sized variables */\n#ifndef PLI_TYPES\n#define PLI_TYPES\ntypedef int             PLI_INT32;\ntypedef unsigned int    PLI_UINT32;\ntypedef short           PLI_INT16;\ntypedef unsigned short  PLI_UINT16;\ntypedef char            PLI_BYTE8;\ntypedef unsigned char   PLI_UBYTE8;\n#endif\n\n/* import a symbol into dll */\n#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)) \n#ifndef PLI_DLLISPEC\n#define PLI_DLLISPEC __declspec(dllimport)\n#define ACC_USER_DEFINED_DLLISPEC 1\n#endif\n#else\n#ifndef PLI_DLLISPEC\n#define PLI_DLLISPEC\n#endif\n#endif\n\n/* export a symbol from dll */\n#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))\n#ifndef PLI_DLLESPEC\n#define PLI_DLLESPEC __declspec(dllexport)\n#define ACC_USER_DEFINED_DLLESPEC 1\n#endif\n#else\n#ifndef PLI_DLLESPEC\n#define PLI_DLLESPEC\n#endif\n#endif\n\n/* mark a function as external */\n#ifndef PLI_EXTERN\n#define PLI_EXTERN\n#endif\n\n/* mark a variable as external */\n#ifndef PLI_VEXTERN\n#define PLI_VEXTERN extern\n#endif\n\n#ifndef PLI_PROTOTYPES\n#define PLI_PROTOTYPES\n#define PROTO_PARAMS(params) params\n/* object is imported by the dll */\n#define XXTERN PLI_EXTERN PLI_DLLISPEC\n/* object is exported by the dll */\n#define EETERN PLI_EXTERN PLI_DLLESPEC\n#endif\n\n/*\n * The following group of defines exists purely for backwards compatibility\n */\n#ifndef PLI_EXTRAS\n#define PLI_EXTRAS\n/* guard bool/true/false when compiling with C++, C99 or later */\n#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L))\n#define bool                   int\n#define true                   1\n#define TRUE                   1\n#define false                  0\n#define FALSE                  0\n#endif\n#define null                   0L\n#define global extern\n#define local  static\n#define exfunc\n#endif\n\n\n/*---------------------------------------------------------------------------*/\n/*------------------------------- definitions -------------------------------*/\n/*---------------------------------------------------------------------------*/\n\n/*----------------------------- general defines -----------------------------*/\ntypedef void   *HANDLE;\n#ifndef VPI_USER_CDS_H\ntypedef void   *handle;\n#endif\n\n#define OPEN_HANDLE_REP ((handle)0x1)\n\n#define HANDLE_IS_OPEN(hand) ((hand) == OPEN_HANDLE_REP)\n\n/*------------------------------- object types ------------------------------*/\n#define    accModule               20\n#define    accScope                21\n#define    accNet                  25\n#define    accReg                  30\n#define    accRegister             accReg\n#define    accPort                 35\n#define    accTerminal             45\n#define    accInputTerminal        46\n#define    accOutputTerminal       47\n#define    accInoutTerminal        48\n#define    accCombPrim            140\n#define    accSeqOptPrim          141\n#define    accSeqPrim             142\n#define    accAndGate             144\n#define    accNandGate            146\n#define    accNorGate             148\n#define    accOrGate              150\n#define    accXorGate             152\n#define    accXnorGate            154\n#define    accBufGate             156\n#define    accNotGate             158\n#define    accBufif0Gate          160\n#define    accBufif1Gate          162\n#define    accNotif0Gate          164\n#define    accNotif1Gate          166\n#define    accNmosGate            168\n#define    accPmosGate            170\n#define    accCmosGate            172\n#define    accRnmosGate           174\n#define    accRpmosGate           176\n#define    accRcmosGate           178\n#define    accRtranGate           180\n#define    accRtranif0Gate        182\n#define    accRtranif1Gate        184\n#define    accTranGate            186\n#define    accTranif0Gate         188\n#define    accTranif1Gate         190\n#define    accPullupGate          192\n#define    accPulldownGate        194\n#define    accIntegerParam        200\n#define    accIntParam            accIntegerParam\n#define    accRealParam           202\n#define    accStringParam         204\n#define    accPath                206\n#define    accTchk                208\n#define    accPrimitive           210\n#define    accBit                 212\n#define    accPortBit             214\n#define    accNetBit              216\n#define    accRegBit              218\n#define    accParameter           220\n#define    accSpecparam           222\n#define    accSpecParam           accSpecparam\n#define    accTopModule           224\n#define    accModuleInstance      226\n#define    accCellInstance        228\n#define    accModPath             230\n#define    accWirePath            234\n#define    accInterModPath        236\n#define    accScalarPort          250\n#define    accBitSelectPort       252\n#define    accPartSelectPort      254\n#define    accVectorPort          256\n#define    accConcatPort          258\n#define    accWire                260\n#define    accWand                261\n#define    accWor                 262\n#define    accTri                 263\n#define    accTriand              264\n#define    accTrior               265\n#define    accTri0                266\n#define    accTri1                267\n#define    accTrireg              268\n#define    accSupply0             269\n#define    accSupply1             270\n#define    accNamedEvent          280\n#define    accEventVar            accNamedEvent\n#define    accIntegerVar          281\n#define    accIntVar              281\n#define    accRealVar             282\n#define    accTimeVar             283\n#define    accScalar              300\n#define    accVector              302\n#define    accCollapsedNet        304\n#define    accExpandedVector      306\n#define    accUnExpandedVector    307\n#define    accProtected           308\n#define    accSetup               366\n#define    accHold                367\n#define    accWidth               368\n#define    accPeriod              369\n#define    accRecovery            370\n#define    accSkew                371\n#define    accTimeSkew            381\n#define    accFullSkew            382\n#define    accRemoval             372\n#define    accRecrem              373\n#define    accNochange            376\n#define    accNoChange            accNochange\n#define    accSetuphold           377\n#define    accInput               402\n#define    accOutput              404\n#define    accInout               406\n#define    accMixedIo             407\n#define    accPositive            408\n#define    accNegative            410\n#define    accUnknown             412\n#define    accPathTerminal        420\n#define    accPathInput           422\n#define    accPathOutput          424\n#define    accDataPath            426\n#define    accTchkTerminal        428\n#define    accBitSelect           500\n#define    accPartSelect          502\n#define    accTask                504\n#define    accFunction            506\n#define    accStatement           508\n#define    accTaskCall            510\n#define    accFunctionCall        512\n#define    accSystemTask          514\n#define    accSystemFunction      516\n#define    accSystemRealFunction  518\n#define    accUserTask            520\n#define    accUserFunction        522\n#define    accUserRealFunction    524\n#define    accNamedBeginStat      560\n#define    accNamedForkStat       564\n#define    accNamedForeachStmt    565\n#define    accConstant            600\n#define    accConcat              610\n#define    accOperator            620\n#define    accMinTypMax           696\n#define    accModPathHasIfnone    715\n#define    accSeqOptFastPrim_1    801\n#define    accSeqOptFastPrim_2    802\n#define    accSeqOptFastPrim_3    803\n#define    accSeqOptFastPrim_4    804\n#define    accSeqOptFastPrim_5    805\n#define    accSeqOptFastPrim_6    806\n#define    accSeqOptFastPrim_7    807\n#define    accSeqOptFastPrim_8    808\n#define    accModportTask         809\n\n/*------------------ parameter values for acc_configure() -------------------*/\n#define    accPathDelayCount        1\n#define    accPathDelimStr          2\n#define    accDisplayErrors         3\n#define    accDefaultAttr0          4\n#define    accToHiZDelay            5\n#define    accEnableArgs            6\n#define    accDisplayWarnings       8\n#define    accDevelopmentVersion   11\n#define    accMapToMipd            17\n#define    accMinTypMaxDelays      19\n\n/*------------ edge information used by acc_handle_tchk(), etc.  ------------*/\n#define accNoedge                   0\n#define accNoEdge                   0\n#define accEdge01                   1\n#define accEdge10                   2\n#define accEdge0x                   4\n#define accEdgex1                   8\n#define accEdge1x                  16\n#define accEdgex0                  32\n#define accPosedge                 13\n#define accPosEdge                 accPosedge\n#define accNegedge                 50\n#define accNegEdge                 accNegedge\n\n/*------------------------------- delay modes -------------------------------*/\n#define accDelayModeNone            0\n#define accDelayModePath            1\n#define accDelayModeDistrib         2\n#define accDelayModeUnit            3\n#define accDelayModeZero            4\n#define accDelayModeMTM             5\n#define accDelayModeSUDP            6\n\n/*------------ values for type field in t_setval_delay structure ------------*/\n#define accNoDelay                  0\n#define accInertialDelay            1\n#define accTransportDelay           2\n#define accPureTransportDelay       3\n#define accForceFlag                4\n#define accReleaseFlag              5\n#define accAssignFlag               6\n#define accDeassignFlag             7\n\n/*------------ values for type field in t_setval_value structure ------------*/\n#define accBinStrVal                1\n#define accOctStrVal                2\n#define accDecStrVal                3\n#define accHexStrVal                4\n#define accScalarVal                5\n#define accIntVal                   6\n#define accRealVal                  7\n#define accStringVal                8\n#define accVectorVal               10\n\n/*------------------------------ scalar values ------------------------------*/\n#define acc0                        0\n#define acc1                        1\n#define accX                        2\n#define accZ                        3\n\n/*---------------------------- VCL scalar values ----------------------------*/\n#define vcl0                        acc0\n#define vcl1                        acc1\n#define vclX                        accX\n#define vclx                        vclX\n#define vclZ                        accZ\n#define vclz                        vclZ\n\n/*----------- values for vc_reason field in t_vc_record structure -----------*/\n#define logic_value_change          1\n#define strength_value_change       2\n#define real_value_change           3\n#define vector_value_change         4\n#define event_value_change          5\n#define integer_value_change        6\n#define time_value_change           7\n#define sregister_value_change      8\n#define vregister_value_change      9\n#define realtime_value_change      10\n\n/*--------------------------- VCL strength values ---------------------------*/\n#define vclSupply                   7\n#define vclStrong                   6\n#define vclPull                     5\n#define vclLarge                    4\n#define vclWeak                     3\n#define vclMedium                   2\n#define vclSmall                    1\n#define vclHighZ                    0\n\n/*----------------------- vcl bit flag definitions -------------------------*/\n#define vcl_strength_flag           1\n#define vcl_verilog_flag            2\n\n/*----------------------- flags used with acc_vcl_add -----------------------*/\n#define vcl_verilog_logic           2\n#define VCL_VERILOG_LOGIC           vcl_verilog_logic\n#define vcl_verilog_strength        3\n#define VCL_VERILOG_STRENGTH        vcl_verilog_strength\n\n/*---------------------- flags used with acc_vcl_delete ---------------------*/\n#define vcl_verilog                 vcl_verilog_logic\n#define VCL_VERILOG                 vcl_verilog\n\n/*---------- values for the type field in the t_acc_time structure --------- */\n#define accTime                     1\n#define accSimTime                  2\n#define accRealTime                 3\n\n/*------------------------------ product types ------------------------------*/\n#define accSimulator                1\n#define accTimingAnalyzer           2\n#define accFaultSimulator           3\n#define accOther                    4\n\n\n/*---------------------------------------------------------------------------*/\n/*-------------------------- structure definitions --------------------------*/\n/*---------------------------------------------------------------------------*/\n\ntypedef struct t_vc_record *p_vc_record;\n\ntypedef PLI_INT32 (*consumer_function)(p_vc_record);\n\n/*----------------- data structure used with acc_set_value() ----------------*/\ntypedef struct t_acc_time\n{\n  PLI_INT32 type;\n  PLI_INT32 low,\n            high;\n  double    real;\n} s_acc_time, *p_acc_time;\n\n/*----------------- data structure used with acc_set_value() ----------------*/\ntypedef struct t_setval_delay\n{\n  s_acc_time time;\n  PLI_INT32  model;\n} s_setval_delay, *p_setval_delay;\n\n/*--------------------- data structure of vector values ---------------------*/\ntypedef struct t_acc_vecval\n{\n  PLI_INT32 aval;\n  PLI_INT32 bval;\n} s_acc_vecval, *p_acc_vecval;\n\n/*------ data structure used with acc_set_value() and acc_fetch_value() -----*/\ntypedef struct t_setval_value\n{\n  PLI_INT32 format;\n  union\n    {\n      PLI_BYTE8    *str;\n      PLI_INT32     scalar;\n      PLI_INT32     integer;\n      double        real;\n      p_acc_vecval  vector;\n    } value;\n} s_setval_value, *p_setval_value, s_acc_value, *p_acc_value;\n\n/*----------------------- structure for VCL strengths -----------------------*/\ntypedef struct t_strengths\n{\n  PLI_UBYTE8 logic_value;\n  PLI_UBYTE8 strength1;\n  PLI_UBYTE8 strength2;\n} s_strengths, *p_strengths;\n\n/*--------------- structure passed to callback routine for VCL --------------*/\ntypedef struct t_vc_record\n{\n  PLI_INT32  vc_reason;\n  PLI_INT32  vc_hightime;\n  PLI_INT32  vc_lowtime;\n  PLI_BYTE8 *user_data;\n  union\n    {\n      PLI_UBYTE8  logic_value;\n      double      real_value;\n      handle      vector_handle;\n      s_strengths strengths_s;\n    } out_value;\n} s_vc_record;\n\n/*------------- structure used with acc_fetch_location() routine ------------*/\ntypedef struct t_location\n{\n  PLI_INT32  line_no;\n  PLI_BYTE8 *filename;\n} s_location, *p_location;\n\n/*---------- structure used with acc_fetch_timescale_info() routine ---------*/\ntypedef struct t_timescale_info\n{\n  PLI_INT16 unit;\n  PLI_INT16 precision;\n} s_timescale_info, *p_timescale_info;\n\n\n/*---------------------------------------------------------------------------*/\n/*-------------------------- routine declarations ---------------------------*/\n/*---------------------------------------------------------------------------*/\n\nXXTERN PLI_INT32   acc_append_delays PROTO_PARAMS((handle object, ...));\nXXTERN PLI_INT32   acc_append_pulsere PROTO_PARAMS((handle object, double val1r, double val1x, ...));\nXXTERN void        acc_close PROTO_PARAMS((void));\nXXTERN handle     *acc_collect PROTO_PARAMS((handle (*p_next_routine)(handle object_handle, handle obj), handle scope_object, PLI_INT32 *aof_count));\nXXTERN PLI_INT32   acc_compare_handles PROTO_PARAMS((handle h1, handle h2));\nXXTERN PLI_INT32   acc_configure PROTO_PARAMS((PLI_INT32 item, PLI_BYTE8 *value));\nXXTERN PLI_INT32   acc_count PROTO_PARAMS((handle (*next_func)(handle object_handle, handle obj), handle object_handle));\nXXTERN char       *acc_decompile_exp PROTO_PARAMS((handle condition ));\nXXTERN PLI_INT32  *acc_error_flag_address PROTO_PARAMS((void));\nXXTERN PLI_INT32   acc_fetch_argc PROTO_PARAMS((void));\nXXTERN PLI_BYTE8 **acc_fetch_argv PROTO_PARAMS((void));\nXXTERN double      acc_fetch_attribute PROTO_PARAMS((handle object, PLI_BYTE8 *attribute_string, ...));\nXXTERN PLI_INT32   acc_fetch_attribute_int PROTO_PARAMS((handle object, PLI_BYTE8 *attribute_string, ...));\nXXTERN PLI_BYTE8  *acc_fetch_attribute_str PROTO_PARAMS((handle object, PLI_BYTE8 *attribute_string, ...));\nXXTERN PLI_BYTE8  *acc_fetch_defname PROTO_PARAMS((handle object_handle));\nXXTERN PLI_INT32   acc_fetch_delay_mode PROTO_PARAMS((handle object_p));\nXXTERN PLI_INT32   acc_fetch_delays PROTO_PARAMS((handle object, ...));\nXXTERN PLI_INT32   acc_fetch_direction PROTO_PARAMS((handle object_handle));\nXXTERN PLI_INT32   acc_fetch_edge PROTO_PARAMS((handle acc_obj));\nXXTERN PLI_BYTE8  *acc_fetch_fullname PROTO_PARAMS((handle object_handle));\nXXTERN PLI_INT32   acc_fetch_fulltype PROTO_PARAMS((handle object_h));\nXXTERN PLI_INT32   acc_fetch_index PROTO_PARAMS((handle object_handle));\nXXTERN double      acc_fetch_itfarg PROTO_PARAMS((PLI_INT32 n, handle tfinst));\nXXTERN PLI_INT32   acc_fetch_itfarg_int PROTO_PARAMS((PLI_INT32 n, handle tfinst));\nXXTERN PLI_BYTE8  *acc_fetch_itfarg_str PROTO_PARAMS((PLI_INT32 n, handle tfinst));\nXXTERN PLI_INT32   acc_fetch_location PROTO_PARAMS((p_location location_p, handle object));\nXXTERN PLI_BYTE8  *acc_fetch_name PROTO_PARAMS((handle object_handle));\nXXTERN PLI_INT32   acc_fetch_paramtype PROTO_PARAMS((handle param_p));\nXXTERN double      acc_fetch_paramval PROTO_PARAMS((handle param));\nXXTERN char       *acc_fetch_paramval_str PROTO_PARAMS((handle param));\nXXTERN PLI_INT32   acc_fetch_polarity PROTO_PARAMS((handle path));\nXXTERN PLI_INT32   acc_fetch_precision PROTO_PARAMS((void));\nXXTERN PLI_INT32   acc_fetch_pulsere PROTO_PARAMS((handle path_p, double *val1r, double *val1e, ...));\nXXTERN PLI_INT32   acc_fetch_range PROTO_PARAMS((handle node, PLI_INT32 *msb, PLI_INT32 *lsb));\nXXTERN PLI_INT32   acc_fetch_size PROTO_PARAMS((handle obj_h));\nXXTERN double      acc_fetch_tfarg PROTO_PARAMS((PLI_INT32 n));\nXXTERN PLI_INT32   acc_fetch_tfarg_int PROTO_PARAMS((PLI_INT32 n));\nXXTERN PLI_BYTE8  *acc_fetch_tfarg_str PROTO_PARAMS((PLI_INT32 n));\nXXTERN void        acc_fetch_timescale_info PROTO_PARAMS((handle obj, p_timescale_info aof_timescale_info));\nXXTERN PLI_INT32   acc_fetch_type PROTO_PARAMS((handle object_handle));\nXXTERN PLI_BYTE8  *acc_fetch_type_str PROTO_PARAMS((PLI_INT32 type));\nXXTERN PLI_BYTE8  *acc_fetch_value PROTO_PARAMS((handle object_handle, PLI_BYTE8 *format_str, p_acc_value acc_value_p));\nXXTERN void        acc_free PROTO_PARAMS((handle *array_ptr));\nXXTERN handle      acc_handle_by_name PROTO_PARAMS((PLI_BYTE8 *inst_name, handle scope_p));\nXXTERN handle      acc_handle_condition PROTO_PARAMS((handle obj));\nXXTERN handle      acc_handle_conn PROTO_PARAMS((handle term_p));\nXXTERN handle      acc_handle_datapath PROTO_PARAMS((handle path));\nXXTERN handle      acc_handle_hiconn PROTO_PARAMS((handle port_ref));\nXXTERN handle      acc_handle_interactive_scope PROTO_PARAMS((void));\nXXTERN handle      acc_handle_itfarg PROTO_PARAMS((PLI_INT32 n, handle tfinst));\nXXTERN handle      acc_handle_loconn PROTO_PARAMS((handle port_ref));\nXXTERN handle      acc_handle_modpath PROTO_PARAMS((handle mod_p, PLI_BYTE8 *pathin_name, PLI_BYTE8 *pathout_name, ...));\nXXTERN handle      acc_handle_notifier PROTO_PARAMS((handle tchk));\nXXTERN handle      acc_handle_object PROTO_PARAMS((PLI_BYTE8 *inst_name));\nXXTERN handle      acc_handle_parent PROTO_PARAMS((handle object_p));\nXXTERN handle      acc_handle_path PROTO_PARAMS((handle source, handle destination));\nXXTERN handle      acc_handle_pathin PROTO_PARAMS((handle path_p));\nXXTERN handle      acc_handle_pathout PROTO_PARAMS((handle path_p));\nXXTERN handle      acc_handle_port PROTO_PARAMS((handle mod_handle, PLI_INT32 port_num));\nXXTERN handle      acc_handle_scope PROTO_PARAMS((handle object));\nXXTERN handle      acc_handle_simulated_net PROTO_PARAMS((handle net_h));\nXXTERN handle      acc_handle_tchk PROTO_PARAMS((handle mod_p, PLI_INT32 tchk_type, PLI_BYTE8 *arg1_conn_name, PLI_INT32 arg1_edgetype, ...));\nXXTERN handle      acc_handle_tchkarg1 PROTO_PARAMS((handle tchk));\nXXTERN handle      acc_handle_tchkarg2 PROTO_PARAMS((handle tchk));\nXXTERN handle      acc_handle_terminal PROTO_PARAMS((handle gate_handle, PLI_INT32 terminal_index));\nXXTERN handle      acc_handle_tfarg PROTO_PARAMS((PLI_INT32 n));\nXXTERN handle      acc_handle_tfinst PROTO_PARAMS((void));\nXXTERN PLI_INT32   acc_initialize PROTO_PARAMS((void));\nXXTERN handle      acc_next PROTO_PARAMS((PLI_INT32 *type_list, handle h_scope, handle h_object));\nXXTERN handle      acc_next_bit PROTO_PARAMS ((handle vector, handle bit));\nXXTERN handle      acc_next_cell PROTO_PARAMS((handle scope, handle cell));\nXXTERN handle      acc_next_cell_load PROTO_PARAMS((handle net_handle, handle load));\nXXTERN handle      acc_next_child PROTO_PARAMS((handle mod_handle, handle child));\nXXTERN handle      acc_next_driver PROTO_PARAMS((handle net, handle driver));\nXXTERN handle      acc_next_hiconn PROTO_PARAMS((handle port, handle hiconn));\nXXTERN handle      acc_next_input PROTO_PARAMS((handle path, handle pathin));\nXXTERN handle      acc_next_load PROTO_PARAMS((handle net, handle load));\nXXTERN handle      acc_next_loconn PROTO_PARAMS((handle port, handle loconn));\nXXTERN handle      acc_next_modpath PROTO_PARAMS((handle mod_p, handle path));\nXXTERN handle      acc_next_net PROTO_PARAMS((handle mod_handle, handle net));\nXXTERN handle      acc_next_output PROTO_PARAMS((handle path, handle pathout));\nXXTERN handle      acc_next_parameter PROTO_PARAMS((handle module_p, handle param));\nXXTERN handle      acc_next_port PROTO_PARAMS((handle ref_obj_p, handle port));\nXXTERN handle      acc_next_portout PROTO_PARAMS((handle mod_p, handle port));\nXXTERN handle      acc_next_primitive PROTO_PARAMS((handle mod_handle, handle prim));\nXXTERN handle      acc_next_scope PROTO_PARAMS((handle ref_scope_p, handle scope));\nXXTERN handle      acc_next_specparam PROTO_PARAMS((handle module_p, handle sparam));\nXXTERN handle      acc_next_tchk PROTO_PARAMS((handle mod_p, handle tchk));\nXXTERN handle      acc_next_terminal PROTO_PARAMS((handle gate_handle, handle term));\nXXTERN handle      acc_next_topmod PROTO_PARAMS((handle topmod));\nXXTERN PLI_INT32   acc_object_in_typelist PROTO_PARAMS((handle object, PLI_INT32 *type_list));\nXXTERN PLI_INT32   acc_object_of_type PROTO_PARAMS((handle object, PLI_INT32 type));\nXXTERN PLI_INT32   acc_product_type PROTO_PARAMS((void));\nXXTERN PLI_BYTE8  *acc_product_version PROTO_PARAMS((void));\nXXTERN PLI_INT32   acc_release_object PROTO_PARAMS((handle obj));\nXXTERN PLI_INT32   acc_replace_delays PROTO_PARAMS((handle object, ...));\nXXTERN PLI_INT32   acc_replace_pulsere PROTO_PARAMS((handle object, double val1r, double val1x, ...));\nXXTERN void        acc_reset_buffer PROTO_PARAMS((void));\nXXTERN PLI_INT32   acc_set_interactive_scope PROTO_PARAMS((handle scope, PLI_INT32 callback_flag));\nXXTERN PLI_INT32   acc_set_pulsere PROTO_PARAMS((handle path_p, double val1r, double val1e));\nXXTERN PLI_BYTE8  *acc_set_scope PROTO_PARAMS((handle object, ...));\nXXTERN PLI_INT32   acc_set_value PROTO_PARAMS((handle obj, p_setval_value setval_p, p_setval_delay delay_p));\nXXTERN void        acc_vcl_add PROTO_PARAMS((handle object_p, PLI_INT32 (*consumer)(p_vc_record), PLI_BYTE8 *user_data, PLI_INT32 vcl_flags));\nXXTERN void        acc_vcl_delete PROTO_PARAMS((handle object_p, PLI_INT32 (*consumer)(p_vc_record), PLI_BYTE8 *user_data, PLI_INT32 vcl_flags));\nXXTERN PLI_BYTE8  *acc_version PROTO_PARAMS((void));\n\n\n/*---------------------------------------------------------------------------*/\n/*----------------------- global variable definitions -----------------------*/\n/*---------------------------------------------------------------------------*/\n\n#if (!defined(VSIM) && !defined(VOPT)) && (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))\n#define acc_error_flag (*acc_error_flag_address())\n#else\nPLI_VEXTERN PLI_DLLISPEC PLI_INT32 acc_error_flag;\n#endif\n\n\n/*---------------------------------------------------------------------------*/\n/*---------------------------- macro definitions ----------------------------*/\n/*---------------------------------------------------------------------------*/\n\n#define  acc_handle_calling_mod_m  acc_handle_parent((handle)tf_getinstance())\n\n#undef PLI_EXTERN\n#undef PLI_VEXTERN\n\n#ifdef ACC_USER_DEFINED_DLLISPEC\n#undef ACC_USER_DEFINED_DLLISPEC\n#undef PLI_DLLISPEC\n#endif\n#ifdef ACC_USER_DEFINED_DLLESPEC\n#undef ACC_USER_DEFINED_DLLESPEC\n#undef PLI_DLLESPEC\n#endif\n\n#ifdef PLI_PROTOTYPES\n#undef PLI_PROTOTYPES\n#undef PROTO_PARAMS\n#undef XXTERN\n#undef EETERN\n#endif\n\n#ifdef  __cplusplus\n}\n#endif\n\n#endif /* ACC_USER_H */\n"
  },
  {
    "path": "src/cocotb/_vendor/fli/acc_vhdl.h",
    "content": "\n/*****************************************************************************\n *\n * acc_vhdl.h\n *\n * List of all predefined type and fulltype constants for VHDL objects.\n *\n * Type Constant       Fulltype Constant       Description\n * ===========================================================================\n *\n * accAlias            accAlias                Object is a VHDL object alias.\n * accAlias            accAliasSignal          ??\n * accAlias            accAliasConstant        ??\n * accAlias            accAliasGeneric         ??\n * accAlias            accAliasVariable        ??\n * ---------------------------------------------------------------------------\n * accArchitecture     accArchitecture         Object is a VHDL architecture.\n *\n *                     accEntityVitalLevel0    Object is an architecture\n *                                             whose entity is decorated with\n *                                             the attribute VITAL_Level0.\n *\n *                     accArchVitalLevel0      Object is an architecture\n *                                             that is decorated with the\n *                                             attribute VITAL_Level0.\n *\n *                     accArchVitalLevel1      Object is an architecture\n *                                             that is decorated with the\n *                                             attribute VITAL_Level1.\n *\n *                     accForeignArch          Object is an architecture\n *                                             that is decorated with the\n *                                             attribute FOREIGN and that\n *                                             does not contain any VHDL\n *                                             statements or objects other\n *                                             than generics and/or ports.\n *\n *                     accForeignArchMixed     Object is an architecture\n *                                             that is decorated with the\n *                                             attribute FOREIGN and that\n *                                             contains at least one VHDL\n *                                             statement and/or object in\n *                                             addition to any generics\n *                                             and/or ports.\n *\n *                     accForeignArchContext   Object is an architecture\n *                                             inserted into the context\n *                                             tree by a 3rd party\n *                                             that is decorated with the\n *                                             attribute FOREIGN and that\n *                                             does not contain any VHDL\n *                                             statements or objects other\n *                                             than generics and/or ports.\n *\n *                     accForeignArchContextMixed  Object is an architecture\n *                                                 inserted into the context\n *                                                 tree by a 3rd party that\n *                                                 is decorated with the\n *                                                 attribute FOREIGN and that\n *                                                 contains at least one VHDL\n *                                                 statement and/or object in\n *                                                 addition to any generics\n *                                                 and/or ports.\n * ---------------------------------------------------------------------------\n * accBlock            accBlock                Object is a VHDL block.\n * ---------------------------------------------------------------------------\n * accConfiguration    accConfiguration        Object is a VHDL configuration.\n * ---------------------------------------------------------------------------\n * accVHDLFile         accVHDLFile             Object is a FILE (1993 and later)\n *                                             or a variable of a file type (1987).\n * ---------------------------------------------------------------------------\n * accForeign          accShadow               Object is a region created\n *                                             with the FLI function\n *                                             mti_CreateRegion().\n * ---------------------------------------------------------------------------\n * accForeignObject    accForeignObject        Object is a 3rd party object.\n * ---------------------------------------------------------------------------\n * accForeignScope     accForeignScope         Object is a 3rd party scope.\n * ---------------------------------------------------------------------------\n * accForLoop          accForLoop              Object is a VHDL for loop.\n * ---------------------------------------------------------------------------\n * accGenerate         accGenerate             Object is a VHDL generate\n *                                             statement.\n *\n *                     accForGenerate          FOR generate statement.\n *\n *                     accIfGenerate           IF generate statement.\n *\n *                     accElsifGenerate        ELSIF generate substatement.\n *\n *                     accElseGenerate         ELSE generate substatement.\n *\n *                     accCaseGenerate         CASE generate statement.\n *\n *                     accCaseOTHERSGenerate   CASE generate (OTHERS choice)\n *                                             substatement.\n * ---------------------------------------------------------------------------\n * accGeneric          accGeneric              Object is a VHDL generic on an\n *                                             entity.\n *\n *                     accGenericConstant      Same as above except that it\n *                                             cannot be modified after design\n *                                             elaboration, presumably because it\n *                                             affects the structural makeup of\n *                                             the design.\n *\n *                     accGenericNotEntity     Object is a VHDL generic on a\n *                                             package or a subprogram.\n *\n *                     accGenericNotEntityConstant Same as above, and it can't\n *                                                 be changed for the same\n *                                                 reasons.\n *\n *                     accInterfacePackage     Object is an interface package on\n *                                             an entity.\n *\n *                     accInterfacePackageNotEntity Object is an interface package\n *                                                  on a package or subprogram.\n *\n *                     accInterfaceSubpgm      Object is an interface subprogram on\n *                                             an entity.\n *\n *                     accInterfaceSubpgmNotEntity Object is an interface subprogram on\n *                                             a package or subprogram.\n #\n *                     accInterfaceType        Object is an interface type on an entity.\n *\n *                     accInterfaceTypeNotEntity Object is an interface type on\n *                                             a package or subprogram.\n *\n * ---------------------------------------------------------------------------\n * accPackage          accPackage              Object is a VHDL package.\n * ---------------------------------------------------------------------------\n * accProcess          accProcess              Object is a VHDL process.\n * ---------------------------------------------------------------------------\n * accSignal           accSignal               Object is a VHDL signal.\n * ---------------------------------------------------------------------------\n * accSubprogram       accSubprogram           Object is a VHDL subprogram.\n * ---------------------------------------------------------------------------\n * accVariable         accVariable             Object is a VHDL variable.\n * ---------------------------------------------------------------------------\n * accVHDLConstant     accVHDLConstant         Object is a VHDL constant.\n * ---------------------------------------------------------------------------\n * accAccessObject     accAccessObject         Object was created with 'new'.\n *                                             Exists only in simulator and when\n *                                             viewing a WLF file.\n *\n *****************************************************************************/\n\n/* $Id: //dvt/mti/rel/2021.4/src/vsim/acc_vhdl.h#1 $ */\n\n#ifndef ACC_VHDL_H\n#define ACC_VHDL_H\n\n/* ATTENTION: Do not define values here below 1010 or above 1499. */\n\n#define    accArchitecture            1010\n#define    VHDL_FIRST_ACC_ID          accArchitecture\n\n#define    accEntityVitalLevel0       1011\n#define    accArchVitalLevel0         1012\n#define    accArchVitalLevel1         1013\n#define    accForeignArch             1014\n#define    accForeignArchMixed        1015\n#define    accArchArray               1016\n#define    accEntity                  1017\n#define    accForeignArchContext      1018\n#define    accForeignArchContextMixed 1019\n#define    accBlock                   1020\n#define    accCompInst                1021\n#define    accDirectInst              1022\n#define    accinlinedBlock            1023\n#define    accinlinedinnerBlock       1024\n#define    accGenerate                1030\n#define    accIfGenerate              1031\n#define    accElsifGenerate           1032\n#define    accElseGenerate            1033\n#define    accForGenerate             1034\n#define    accCaseGenerate            1035\n#define    accCaseOTHERSGenerate      1036\n#define    accPackage                 1040\n#define    accPackageUninstantiated   1041\n#define    accPackageInstantiated     1042\n#define    accPackageAmsEntry         1043\n#define    accConfiguration           1050\n#define    accSubprogram              1060\n#define    accProcess                 1070\n#define    accForLoop                 1080\n#define    accForeign                 1090\n#define    accShadow                  1091\n#define    accShadowConv              1092\n#define    accSignal                  1100\n#define    accSignalBit               1101\n#define    accSignalSubComposite      1102\n#define    accVariable                1110\n#define    accGeneric                 1120\n#define    accGenericConstant         1121\n#define    accGenericNotEntity        1122\n#define    accGenericNotEntityConstant 1123\n#define    accInterfacePackage        1124\n#define    accInterfacePackageNotEntity 1125\n#define    accInterfaceSubprogram     1126\n#define    accInterfaceSubprogramNotEntity 1127\n#define    accInterfaceType           1128\n#define    accInterfaceTypeNotEntity  1129\n#define    accAlias                   1130\n#define    accAliasSignal             1131\n#define    accAliasConstant           1132\n#define    accAliasGeneric            1133\n#define    accAliasVariable           1134\n#define    accAliasAMSTerminal        1135\n#define    accAliasLWS                1136\n#define    accVHDLConstant            1140\n#define    accVHDLFile                1150\n#define    accForeignObject           1160\n#define    accAccessObject            1170\n#define    VHDL_LAST_ACC_ID           accAccessObject\n\n#define    accForeignScope            1180\n#define    accAMSArchitecture         1181\n#define    accAMSTerminal             1182\n#define    accAMSQuantity             1183\n#define    accAMSPackage              1184\n\n\n#define\t VS_TYPE_IS_VHDL(a) (((a) <= VHDL_LAST_ACC_ID) && (a) >= VHDL_FIRST_ACC_ID)\n\n#endif /* ACC_VHDL_H */\n\n\n"
  },
  {
    "path": "src/cocotb/_vendor/fli/mti.h",
    "content": "/*\n   Copyright 2022 Siemens\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n*/\n\n#ifndef MTI_H\n#define MTI_H\n\n#ifndef DEFINE_UCDBT\n#define DEFINE_UCDBT\ntypedef void* ucdbT;          /* generic handle to a UCDB */\n#endif\n/*****************************************************************************\n * DEFINES\n *****************************************************************************/\n\n#ifndef PROTO\n#if defined(_WIN32) || defined(__STDC__) || defined(__cplusplus)\n#define PROTO(arg) arg\n#else\n#define PROTO(arg) ()\n#endif\n#endif /* PROTO */\n\n/*****************************************************************************\n * TYPE DEFINITIONS\n *****************************************************************************/\n\n/*\n *  Notice - this definition appears in mti.h, ucdb.h and mtiLongT.h\n */\n\n#if !defined(MTI_LONG_INCLUDED)\n#define MTI_LONG_INCLUDED\n\n/* Sun defines _LP64, HP and Linux define __LP64__, AIX defines __64BIT__ */\n#if defined(_LP64) || defined(__LP64__) || defined(_WIN64)\n# if !defined(__64BIT__)\n#   define __64BIT__\n# endif\n#endif\n\n/* Ensure that size-critical types are defined on all OS platforms. */\n#if defined (_MSC_VER)\n    typedef unsigned __int64 uint64_t;\n    typedef unsigned __int32 uint32_t;\n    typedef unsigned __int16 uint16_t;\n    typedef unsigned __int8 uint8_t;\n    typedef signed __int64 int64_t;\n    typedef signed __int32 int32_t;\n    typedef signed __int16 int16_t;\n    typedef signed __int8 int8_t;\n#elif defined(__MINGW32__)\n# include <stdint.h>\n#elif defined(__linux)\n# include <inttypes.h>\n#else\n# include <sys/types.h>\n#endif\n\n\t/* in L32P64 long is 32 bits and pointers are 64 bits. */\n#if defined (_WIN64)\n\ttypedef __int64 mtiLongT;\n\ttypedef unsigned __int64 mtiUlongT;\n#else\n\ttypedef long mtiLongT;\n\ttypedef unsigned long mtiUlongT;\n#endif\n\n#endif /* !defined(MTI_LONG_INCLUDED) */\n\ntypedef struct mtiDriverIdTag   * mtiDriverIdT;  /* Handle to a signal drvr */\ntypedef struct mtiProcessIdTag  * mtiProcessIdT; /* Handle to a process     */\ntypedef struct mtiRegionIdTag   * mtiRegionIdT;  /* Handle to a region      */\ntypedef struct mtiObjIdTag      * mtiObjIdT;     /* Handle to a p_obj       */\ntypedef struct mtiSignalIdTag   * mtiSignalIdT;  /* Handle to a signal      */\ntypedef struct mtiTypeIdTag     * mtiTypeIdT;    /* Handle to a type desc   */\ntypedef struct mtiVariableIdTag * mtiVariableIdT;/* Handle to a variable    */\ntypedef struct mtiValueIdTag    * mtiValueIdT;   /* Handle to a value desc  */\ntypedef struct mtiCompValueIdTag * mtiCompValueIdT; /* Handle to a composite value desc  */\ntypedef struct mtiAMSTerminalIdTag   * mtiAMSTerminalIdT;  /* Handle to a AMS Terminal      */\ntypedef struct mtiAMSQuantityIdTag   * mtiAMSQuantityIdT;  /* Handle to a AMS Quantity      */\ntypedef void * mtiHandleListT;\ntypedef void * mtiHandleListItrT;\n\ntypedef int          mtiInt32T;\ntypedef unsigned int mtiUInt32T;\n\ntypedef mtiInt32T    mtiDelayT;\n\ntypedef void (*mtiEnvCBFuncPtrT)       PROTO((void * param, void * context));\ntypedef void (*mtiSimStatusCBFuncPtrT) PROTO((void * param, int running));\ntypedef void (*mtiVoidFuncPtrT)        PROTO((void * param));\ntypedef void (*mtiUCDBSaveFuncPtrT)    PROTO((ucdbT ucdb, \n                                              mtiRegionIdT region, \n                                              void * param));\ntypedef void (*mtiNoParamFuncPtrT)     PROTO((void));\n\n/* Types */\n\ntypedef enum mtiTypeKindEnum_ {\n    MTI_TYPE_SCALAR   =  0,        /* Integer types                          */\n    MTI_TYPE_ARRAY    =  1,\n    MTI_TYPE_RECORD   =  2,\n    MTI_TYPE_ENUM     =  3,\n    MTI_TYPE_INTEGER  =  4,        /* not used (use MTI_TYPE_SCALAR instead) */\n    MTI_TYPE_PHYSICAL =  5,\n    MTI_TYPE_REAL     =  6,\n    MTI_TYPE_ACCESS   =  7,\n    MTI_TYPE_FILE     =  8,\n    MTI_TYPE_TIME     =  9,\n    MTI_TYPE_REG      = 10,\n    MTI_TYPE_NET      = 11,\n    MTI_TYPE_MEMELEM  = 13,\n    MTI_TYPE_C_REAL   = 15,\n    MTI_TYPE_VL_ENUM  = 19,\n    MTI_TYPE_WREAL    = 46,\n    MTI_TYPE_C_ENUM   = 264\n} mtiTypeKindT;\n\n/* Directions (which are really port/signal modes) */\n\ntypedef enum mtiDirectionEnum_ {\n    MTI_INTERNAL,\n    MTI_DIR_IN,\n    MTI_DIR_OUT,\n    MTI_DIR_INOUT\n} mtiDirectionT;\n\n/* Process triggers */\n\ntypedef enum mtiProcessTriggerEnum_ {\n    MTI_ACTIVE,\n    MTI_EVENT\n} mtiProcessTriggerT;\n\n/* Driver modes */\n\ntypedef enum mtiDriverModeEnum_ {\n    MTI_INERTIAL,\n    MTI_TRANSPORT\n} mtiDriverModeT;\n\n/* Force types */\n\ntypedef enum mtiForceTypeEnum_ {\n    MTI_FORCE_DEFAULT,\n    MTI_FORCE_DEPOSIT,\n    MTI_FORCE_DRIVE,\n    MTI_FORCE_FREEZE\n} mtiForceTypeT;\n\n/* SystemC Control/Observe Compatibility mode */\n\ntypedef enum mtiCntrlObsrvCompatEnum_ {\n    MTI_SCCO_DEFAULT, /* default behaviour for SignalSpy call */\n    MTI_SCCO_CONTROL, /* control_foreign_signal compatibility mode */\n    MTI_SCCO_OBSERVE,  /* observe_foreign_signal compatibility mode */\n    MTI_SCCO_SCV_CONNECT  /* scv_connect compatibility mode */\n} mtiCntrlObsrvCompatT;\n\n/* Process priority */\n\ntypedef enum mtiProcessPriorityEnum_ {\n    MTI_PROC_NORMAL    = 0,    /* Normal processes run (when triggered)      */\n                               /* after all immediate processes have run and */\n                               /* settled. They can run once per delta and   */\n                               /* can schedule events in zero delay.         */\n\n    MTI_PROC_IMMEDIATE = 1,    /* All immediate processes run immediately    */\n                               /* after signal activation (if triggered). If */\n                               /* any immediate process activates any        */\n                               /* signals, then the signals are reevaluated  */\n                               /* and all immediate processes (if triggered) */\n                               /* are run again in the same delta. This      */\n                               /* cycle continues until no more signals are  */\n                               /* activated.                                 */\n\n    MTI_PROC_POSTPONED = 2,    /* Postponed processes run once (when         */\n                               /* triggered) at the end of the time step for */\n                               /* which they are scheduled after all         */\n                               /* immediate, normal, synchronized, and NBA   */\n                               /* processes.  They cannot schedule anything  */\n                               /* in zero delay.  (In Verilog, these types   */\n                               /* of processes are also known as read-only   */\n                               /* synchronization processes or $monitor()    */\n                               /* processes.)                                */\n\n    MTI_PROC_NBA       = 3,    /* Non-Blocking Assignment processes (when    */\n                               /* triggered) run after synchronized          */\n                               /* processes, but before postponed processes. */\n                               /* They can run once per delta and can        */\n                               /* schedule events in zero delay.             */\n\n    MTI_PROC_SYNCH     = 4     /* Synchronized processes (when triggered)    */\n                               /* run after immediate and normal processes,  */\n                               /* but before NBA processes. They can run     */\n                               /* once per delta and can schedule events in  */\n                               /* zero delay.                                */\n} mtiProcessPriorityT;\n\n/* Time format conversion */\n\ntypedef enum mtiTimeFlagEnum_ {\n\tMTI_TIME_BEST_UNITS    = 1,   /* Determine automatically the units to use */\n\tMTI_TIME_INSERT_COMMAS = 2,   /* Insert commas every three digits */\n\tMTI_TIME_NO_DEF_UNIT   = 8,   /* Do not display default units */\n\tMTI_TIME_FREQUENCY     = 16   /* Display time as 1/t in hz */\n} mtiTimeFlagT;\n\n/* -------------------- Data structure for time values -------------------- */\n\n#if defined(__64BIT__) && !defined(NOINT64)\n\n/* 64-bit scalar time type */\n\ntypedef mtiLongT mtiTime64T;\n#define MTI_TIME64_INIT(h,l)    ((mtiLongT)(h)<<32 | (unsigned int)(l))\n#define MTI_TIME64_HI32(t)      ((mtiInt32T)((t)>>32))\n#define MTI_TIME64_LO32(t)      ((mtiUInt32T)(t))\n#define MTI_TIME64_ASGN(t,h,l)  {(t) = (mtiLongT)(h)<<32 | (unsigned int)(l);}\n\n#elif defined(USE_INTTYPES)\n\n/* 64-bit scalar time type */\n\n# include <sys/types.h>\ntypedef int64 mtiTime64T;\n#define MTI_TIME64_INIT(h,l)    ((int64)(h)<<32 | (unsigned int)(l))\n#define MTI_TIME64_HI32(t)      ((mtiInt32T)((t)>>32))\n#define MTI_TIME64_LO32(t)      ((mtiUInt32T)(t))\n#define MTI_TIME64_ASGN(t,h,l)  {(t) = (int64)(h)<<32 | (unsigned int)(l);}\n\n#else  /* 64-bit aligned time structure */\n\nstruct mtiInt64TimeVal_ {\n#if defined(_WIN32) || defined(__linux) || (defined(__sun) && !defined(__sparc))\n\tunsigned int lo; /* little-endian, sunos5x86, sunos5x866_64 */\n\tint          hi;\n# define MTI_TIME64_INIT(h,l)    {{(l), (h)}}\n#elif (defined(__sun) && defined(__sparc))\n\tint          hi; /* big-endian sunos5v9 */\n\tunsigned int lo;\n# define MTI_TIME64_INIT(h,l)    {{(h), (l)}}\n#else\n#error \"don't know how to determine endian-ness on this machine!\"\n#endif\n};\n\ntypedef union mtiTime64Union_ {\n\tstruct mtiInt64TimeVal_ s;\n# if defined(__64BIT__)\n    mtiLongT v;\n# elif defined (__GNUC__) && !defined(__STRICT_ANSI__)\n    long long v;\n# else\n    double d;\n# endif\n} mtiTime64T;\n#define MTI_TIME64_ASGN(t,h,l)    {(t).s.hi = (h); (t).s.lo = (l);}\n#define MTI_TIME64_HI32(t)        ((t).s.hi)\n#define MTI_TIME64_LO32(t)        ((t).s.lo)\n\n#endif\n\n/* Types to handle Real values as return values of foreign functions. */\n\ntypedef union {\n    mtiTime64T val64;\n    mtiInt32T  val32;\n    mtiLongT   val_long;\n    double     val_real;\n    char *     val_ptr;\n} mtiUniversalValueT;\n\ntypedef mtiUniversalValueT mtiRealT;\n\n#define MTI_GET_REAL_VALUE(r) ((r).val_real)\n#define MTI_ASSIGN_TO_REAL(target,source) ((target).val_real = source)\n\n/* Data structure for physical type units */\n\ntypedef struct mtiPhysicalDataStruct_ mtiPhysicalDataT;\nstruct mtiPhysicalDataStruct_ {\n    mtiPhysicalDataT  * next;           /* Ptr to next unit; NULL at end     */\n    char              * unit_name;      /* Name of unit                      */\n    mtiInt32T           position;       /* Multiple of primary unit          */\n};\n\n/* Data structure for ports and generics */\n\n/*****************************************************************************\n * NOTE: For generics of type string, generic_array_value is NOT\n *       null-terminated.  See the FLI manual for information\n *       on accessing VHDL array values.\n *****************************************************************************/\n\nunion mtiGenericValUnion_{\n  mtiInt32T       generic_value;         /* Integer/physical/enum generic     */\n\t\t\t\t\t\t\t\t\t\t /* value                             */\n  double          generic_value_real;    /* Real generic value                */\n  mtiTime64T      generic_value_time;    /* Time generic value                */\n  void          * generic_array_value;   /* Array generic value               */\n  mtiVariableIdT  generic_record_varid;  /* Generic record variable           */\n  mtiSignalIdT    port;                  /* Signal ID of port                 */\n#if defined(_POWER)\n  long long      _qalign_natural;        /** force 8-byte alignment of union **/\n#endif /* _POWER (IBM cc) */\n};\n\ntypedef struct mtiInterfaceListStruct_ mtiInterfaceListT;\nstruct mtiInterfaceListStruct_ {\n    char            * name;                  /* Simple name of generic/port       */\n    mtiTypeIdT        type;                  /* Type of generic/port              */\n    mtiDirectionT     port_dir;              /* Direction of port                 */\n                                             /* (All generics are INTERNAL)       */\n\tunion mtiGenericValUnion_ u;\n    mtiInterfaceListT *nxt;                  /* Next generic/port in list         */\n};\n\n/*****************************************************************************\n * FUNCTION PROTOTYPES\n *****************************************************************************/\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n/***********\n * Regions *\n ***********/\n\nextern mtiRegionIdT        mti_CreateRegion         PROTO((mtiRegionIdT parent,\n                                                           char * name));\nextern mtiRegionIdT        mti_FindRegion           PROTO((char * name));\nextern mtiRegionIdT        mti_FirstLowerRegion     PROTO((mtiRegionIdT reg));\nextern mtiRegionIdT        mti_GetCallingRegion     PROTO((void));\nextern mtiRegionIdT        mti_GetCurrentRegion     PROTO((void));\nextern mtiRegionIdT        mti_GetTopRegion         PROTO((void));\nextern mtiRegionIdT        mti_HigherRegion         PROTO((mtiRegionIdT reg));\nextern mtiRegionIdT        mti_NextRegion           PROTO((mtiRegionIdT reg));\n\nextern char              * mti_GetLibraryName       PROTO((mtiRegionIdT reg));\nextern char              * mti_GetPrimaryName       PROTO((mtiRegionIdT reg));\nextern char              * mti_GetRegionFullName    PROTO((mtiRegionIdT reg));\nextern char              * mti_GetRegionName        PROTO((mtiRegionIdT reg));\nextern char              * mti_GetRegionSourceName  PROTO((mtiRegionIdT reg));\nextern char              * mti_GetSecondaryName     PROTO((mtiRegionIdT reg));\n\nextern int                 mti_GetRegionKind        PROTO((mtiRegionIdT reg));\n\nextern mtiInterfaceListT * mti_GetGenericList       PROTO((mtiRegionIdT reg));\n\n/*************\n * Processes *\n *************/\n\nextern mtiProcessIdT  mti_CreateProcess      PROTO((char * name,\n                                                    mtiVoidFuncPtrT func,\n                                                    void * param));\nextern mtiProcessIdT  mti_CreateProcessWithPriority\n                                             PROTO((char * name,\n                                                 mtiVoidFuncPtrT func,\n                                                 void * param,\n                                                 mtiProcessPriorityT priority));\nextern mtiProcessIdT  mti_FirstProcess       PROTO((mtiRegionIdT reg));\nextern mtiProcessIdT  mti_NextProcess        PROTO((void));\n\nextern char         * mti_GetProcessName     PROTO((mtiProcessIdT proc));\nextern mtiRegionIdT   mti_GetProcessRegion   PROTO((mtiProcessIdT proc));\n\nextern void           mti_Desensitize        PROTO((mtiProcessIdT proc));\nextern void           mti_ScheduleWakeup     PROTO((mtiProcessIdT proc,\n                                                    mtiDelayT delay));\nextern void           mti_ScheduleWakeup64   PROTO((mtiProcessIdT proc,\n                                                    mtiTime64T delay));\nextern void           mti_Sensitize          PROTO((mtiProcessIdT proc,\n                                                    mtiSignalIdT sig,\n                                                    mtiProcessTriggerT when));\n\n/***********\n * Signals *\n ***********/\n\nextern mtiSignalIdT   mti_CreateSignal         PROTO((char * name,\n                                                      mtiRegionIdT reg,\n                                                      mtiTypeIdT type));\nextern mtiSignalIdT   mti_FindPort             PROTO((mtiInterfaceListT * list,\n                                                      char * name));\nextern mtiSignalIdT   mti_FindSignal           PROTO((char * name));\nextern mtiSignalIdT   mti_FirstSignal          PROTO((mtiRegionIdT reg));\nextern mtiSignalIdT   mti_NextSignal           PROTO((void));\n\nextern int            mti_ForceSignal          PROTO((mtiSignalIdT sigid,\n                                                    char        * value_string,\n                                                    mtiDelayT     delay,\n                                                    mtiForceTypeT force_type,\n                                                    mtiInt32T     cancel_period,\n                                                    mtiInt32T     repeat_period\n                                                    ));\nextern int            mti_ReleaseSignal        PROTO((mtiSignalIdT sigid));\n\nextern void         * mti_GetArraySignalValue  PROTO((mtiSignalIdT sig,\n                                                      void * buf));\nextern mtiSignalIdT * mti_GetDrivingSignals    PROTO((char * name));\nextern mtiSignalIdT   mti_GetParentSignal      PROTO((mtiSignalIdT sig));\nextern mtiSignalIdT   mti_GetResolvedSignalParent  PROTO((mtiSignalIdT sig));\nextern mtiSignalIdT   mti_GetEquivSignal       PROTO((mtiSignalIdT sig));\nextern mtiDirectionT  mti_GetSignalMode        PROTO((mtiSignalIdT sig));\nextern char         * mti_GetSignalName        PROTO((mtiSignalIdT sig));\nextern char         * mti_GetSignalNameIndirect  PROTO((mtiSignalIdT sig,\n                                                        char * buf,\n                                                        int length));\nextern mtiRegionIdT   mti_GetSignalRegion      PROTO((mtiSignalIdT sig));\nextern mtiSignalIdT * mti_GetSignalSubelements PROTO((mtiSignalIdT sig,\n                                                      mtiSignalIdT * buf));\nextern mtiTypeIdT     mti_GetSignalType        PROTO((mtiSignalIdT sig));\nextern mtiInt32T      mti_GetSignalValue       PROTO((mtiSignalIdT sig));\nextern void         * mti_GetSignalValueIndirect PROTO((mtiSignalIdT sig,\n                                                      void * buf));\n\nextern void           mti_SetSignalValue       PROTO((mtiSignalIdT sig,\n                                                      mtiLongT val));\n\nextern char         * mti_SignalImage          PROTO((mtiSignalIdT sig));\nextern int            mti_SignalIsResolved     PROTO((mtiSignalIdT sig));\nextern void           mti_SignalDump           PROTO((mtiSignalIdT sig));\n\n/***********\n * Drivers *\n ***********/\n\nextern mtiDriverIdT   mti_CreateDriver         PROTO((mtiSignalIdT sig));\nextern mtiDriverIdT   mti_FindDriver           PROTO((mtiSignalIdT sig));\nextern mtiDriverIdT * mti_GetDriverSubelements PROTO((mtiDriverIdT drv,\n                                                      mtiDriverIdT * buf));\nextern char        ** mti_GetDriverNames       PROTO((mtiSignalIdT sig,\n                                                      mtiInt32T * length));\nextern char         * mti_GetDriverValues      PROTO((mtiSignalIdT sig,\n                                                      mtiInt32T * length));\n\nextern void           mti_ScheduleDriver       PROTO((mtiDriverIdT drv,\n                                                      mtiLongT value,\n                                                      mtiDelayT delay,\n                                                      mtiDriverModeT mode));\nextern void           mti_ScheduleDriver64     PROTO((mtiDriverIdT drv,\n                                                      mtiLongT value,\n                                                      mtiTime64T delay,\n                                                      mtiDriverModeT mode));\nextern void           mti_SetDriverOwner       PROTO((mtiDriverIdT drv,\n                                                      mtiProcessIdT proc));\n\n/**************************************************\n * Variables/Generics/Constants/SystemC Variables *\n *************************************************/\n\nextern mtiVariableIdT   mti_FindVar            PROTO((char * name));\nextern mtiVariableIdT   mti_FirstVar           PROTO((mtiProcessIdT proc));\nextern mtiVariableIdT   mti_FirstVarByRegion   PROTO((mtiRegionIdT reg));\nextern mtiVariableIdT   mti_NextVar            PROTO((void));\n\nextern void           * mti_GetArrayVarValue   PROTO((mtiVariableIdT var,\n                                                      void * buf));\nextern void           * mti_GetVarAddr         PROTO((char * name));\nextern char           * mti_GetVarImage        PROTO((char * name));\nextern char           * mti_GetVarImageById    PROTO((mtiVariableIdT var));\nextern char           * mti_GetVarName         PROTO((mtiVariableIdT var));\nextern mtiVariableIdT * mti_GetVarSubelements  PROTO((mtiVariableIdT var,\n                                                      mtiVariableIdT * buf));\nextern mtiTypeIdT       mti_GetVarType         PROTO((mtiVariableIdT var));\nextern mtiInt32T        mti_GetVarValue        PROTO((mtiVariableIdT var));\nextern void           * mti_GetVarValueIndirect PROTO((mtiVariableIdT var,\n                                                      void * buf));\nextern int              mti_GetVarKind         PROTO((mtiVariableIdT var));\n\nextern void             mti_SetVarValue        PROTO((mtiVariableIdT var,\n                                                      mtiLongT val));\n\n/*********\n * Types *\n *********/\n\nextern mtiTypeIdT      mti_CreateArrayType     PROTO((mtiInt32T  left,\n                                                      mtiInt32T  right,\n                                                      mtiTypeIdT elem_type));\nextern mtiTypeIdT      mti_CreateEnumType      PROTO((mtiInt32T size,\n                                                      mtiInt32T count,\n                                                      char **   literals));\nextern mtiTypeIdT      mti_CreateRealType      PROTO((void));\nextern mtiTypeIdT      mti_CreateScalarType    PROTO((mtiInt32T left,\n                                                      mtiInt32T right));\nextern mtiTypeIdT      mti_CreateTimeType      PROTO((void));\n\nextern mtiTypeIdT      mti_GetArrayElementType PROTO((mtiTypeIdT type));\nextern char         ** mti_GetEnumValues       PROTO((mtiTypeIdT type));\nextern mtiPhysicalDataT * mti_GetPhysicalData  PROTO((mtiTypeIdT type));\nextern mtiTypeKindT    mti_GetTypeKind         PROTO((mtiTypeIdT type));\nextern int             mti_IsSystemcType       PROTO((mtiTypeIdT type));\nextern int             mti_IsSystemcSignedType PROTO((mtiTypeIdT type));\n\nextern char          * mti_Image               PROTO((void * value,\n                                                      mtiTypeIdT type));\n\nextern mtiInt32T       mti_TickDir             PROTO((mtiTypeIdT type));\nextern mtiInt32T       mti_TickHigh            PROTO((mtiTypeIdT type));\nextern mtiInt32T       mti_TickLeft            PROTO((mtiTypeIdT type));\nextern mtiInt32T       mti_TickLength          PROTO((mtiTypeIdT type));\nextern mtiInt32T       mti_TickLow             PROTO((mtiTypeIdT type));\nextern mtiInt32T       mti_TickRight           PROTO((mtiTypeIdT type));\n\nextern mtiInt32T       mti_GetNumRecordElements          PROTO((mtiTypeIdT type));\n\n/*************\n * Callbacks *\n *************/\n\nextern void  mti_AddInputReadyCB               PROTO((int file_desc,\n                                                      mtiVoidFuncPtrT func,\n                                                      void * param));\nextern void  mti_AddOutputReadyCB              PROTO((int file_desc,\n                                                      mtiVoidFuncPtrT func,\n                                                      void * param));\n\nextern void  mti_AddSocketInputReadyCB         PROTO((int socket_desc,\n                                                      mtiVoidFuncPtrT func,\n                                                      void * param));\nextern void  mti_AddSocketOutputReadyCB        PROTO((int socket_desc,\n                                                      mtiVoidFuncPtrT func,\n                                                      void * param));\n\nextern void  mti_AddEnvCB            PROTO((mtiEnvCBFuncPtrT func,void *param));\nextern void  mti_AddLoadDoneCB       PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_AddQuitCB           PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_AddRestartCB        PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_AddRestoreCB        PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_AddRestoreDoneCB    PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_AddSaveCB           PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_AddSimStatusCB      PROTO((mtiSimStatusCBFuncPtrT func,\n                                            void *param));\nextern void  mti_AddUCDBSaveCB       PROTO((mtiRegionIdT region,\n                                            mtiUCDBSaveFuncPtrT func,\n                                            void*param));\n\nextern void  mti_RemoveEnvCB         PROTO((mtiEnvCBFuncPtrT func,void *param));\nextern void  mti_RemoveLoadDoneCB    PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_RemoveQuitCB        PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_RemoveRestartCB     PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_RemoveRestoreCB     PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_RemoveRestoreDoneCB PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_RemoveSaveCB        PROTO((mtiVoidFuncPtrT func, void *param));\nextern void  mti_RemoveSimStatusCB   PROTO((mtiSimStatusCBFuncPtrT func,\n                                            void *param));\nextern void  mti_AddDPISaveRestoreCB PROTO((mtiVoidFuncPtrT saveFuncPtr, char* restoreFuncName));\n\n\n/*********************\n * Memory Management *\n *********************/\n\nextern void   * mti_Malloc                PROTO((mtiUlongT size));\nextern void   * mti_Realloc               PROTO((void * p, mtiUlongT size));\nextern void     mti_Free                  PROTO((void * p));\nextern void     mti_VsimFree              PROTO((void * ptr));\n\n/******************\n * Save & Restore *\n ******************/\n\nextern char   * mti_GetCheckpointFilename PROTO((void));\nextern char   * mti_GetCheckpointDirname  PROTO((void));\nextern char   * mti_GetRestoreDirname  PROTO((void));\nextern int      mti_IsRestore             PROTO((void));\nextern int      mti_IsColdRestore         PROTO((void));\nextern void     mti_SaveBlock             PROTO((char * p, mtiUlongT size));\nextern void     mti_SaveChar              PROTO((char data));\nextern void     mti_SaveLong              PROTO((mtiLongT data));\nextern void     mti_SaveShort             PROTO((short data));\nextern void     mti_SaveString            PROTO((char * data));\nextern void     mti_RestoreBlock          PROTO((char * p));\nextern char     mti_RestoreChar           PROTO((void));\nextern mtiLongT mti_RestoreLong           PROTO((void));\nextern short    mti_RestoreShort          PROTO((void));\nextern char   * mti_RestoreString         PROTO((void));\nextern void     mti_RestoreProcess        PROTO((mtiProcessIdT   proc,\n                                                 char *          name,\n                                                 mtiVoidFuncPtrT func,\n                                                 void *          param));\n\n/*****************\n * Time & Events *\n *****************/\n\nextern mtiUInt32T    mti_Delta            PROTO((void));\nextern mtiInt32T     mti_Now              PROTO((void));\nextern mtiTime64T  * mti_NowIndirect      PROTO((mtiTime64T *timep));\nextern mtiInt32T     mti_NowUpper         PROTO((void));\nextern char        * mti_NowFormatted     PROTO((mtiTimeFlagT flags));\nextern char        * mti_TimeToString     PROTO((mtiTime64T  *timep, \n\t\t\t\t\t\t\t\t\t\t\t\t mtiTimeFlagT  flags));\n\nextern int      mti_GetNextEventTime      PROTO((mtiTime64T * timep));\nextern int      mti_GetNextNextEventTime  PROTO((mtiTime64T * timep));\nextern int      mti_GetResolutionLimit    PROTO((void));\nextern void     mti_GetRunStopTime        PROTO((mtiTime64T * timep));\n\n/****************************\n * Communication & Commands *\n ****************************/\n\nextern void     mti_AddCommand            PROTO((char * cmd_name,\n                                                 mtiVoidFuncPtrT func));\n\n#ifdef _TCL\nextern void     mti_AddTclCommand         PROTO((const char *          cmd_name,\n                                                 Tcl_CmdProc *   func,\n                                                 void *          param,\n                                                 mtiVoidFuncPtrT funcDeleteCB));\n#endif /* _TCL */\n\nextern void     mti_Command               PROTO((const char * cmd));\nextern int      mti_Cmd                   PROTO((const char * cmd));\nextern void   * mti_Interp                PROTO((void));\n\nextern int      mti_AskStdin              PROTO((char * buf, char * prompt));\nextern void     mti_PrintMsg              PROTO((int flags, const char * msg));\nextern void     mti_PrintMessage          PROTO((const char * msg));\nextern void     mti_PrintFormatted        PROTO((const char * format, ...));\n\nextern void     mti_Break                 PROTO((void));\nextern void     mti_FatalError            PROTO((void));\nextern void     mti_Exit                  PROTO((int exit_status));\nextern void     mti_Quit                  PROTO((void));\nextern void     mti_QuitWithErrorCode     PROTO((const char* file_name, \n                                                 int line_number, \n\t\t\t\t\t\t\t\t\t\t\t\t int error_code));\n\n/*****************\n * Miscellaneous *\n *****************/\n\nextern char   * mti_GetProductVersion     PROTO((void));\nextern char   * mti_GetWlfFilename        PROTO((void));\n\nextern char   * mti_FindProjectEntry      PROTO((char * section,\n                                                 char * name,\n                                                 int    expand));\nextern void     mti_WriteProjectEntry     PROTO((char * key, char * val));\n\nextern int      mti_IsFirstInit           PROTO((void));\n\nextern void     mti_KeepLoaded            PROTO((void));\n\nextern int      mti_AddAttrToVsimTestrecord PROTO((const char * key,\n                                                   void * value));\n\nextern int      mti_GetAttrFromVsimTestrecord PROTO((const char * key,\n                                                     void * value));\n\nextern int      mti_GetSimulationStatus   PROTO((void));\n\nextern int      mti_RemoveAttrFromVsimTestrecord PROTO((const char * key));\nextern int      mti_CallStack             PROTO((void));\nextern int      mti_IsVoptMode            PROTO((void));\nextern int      mti_IsGBEMode             PROTO((void));\nextern int      mti_NoScHdlParam          PROTO((void));\n\n/*****************\n * VHDL - AMS *\n *****************/\n\nextern void* ams_debug_FirstAMSObj                    PROTO((mtiRegionIdT reg, uint32_t acc_type));\nextern void* ams_debug_NextAMSObj                     PROTO((uint32_t acc_type));\nextern mtiTypeIdT ams_debug_GetTerminalType           PROTO((void* term_obj));\nextern mtiTypeIdT ams_debug_GetQuantityType           PROTO((void* quant_obj));\nextern void* ams_debug_GetPlusTerminal                PROTO((void* quant_obj));\nextern void* ams_debug_GetMinusTerminal               PROTO((void* quant_obj));\nextern void* ams_debug_GetImplicitQuantityPrefix      PROTO((void* quant_obj));\nextern double ams_debug_GetQuantityValue              PROTO((void* quant_obj));\nextern void ams_debug_SetQuantityValue                PROTO((void* quant_obj, double value));\nextern int ams_debug_getQuantityTDKind                PROTO((void* quant_obj));\nextern int ams_debug_getQuantityPortMode              PROTO((void* quant_obj));\nextern int ams_debug_getArrayQuantityNumChildren      PROTO((void* quant_obj));\nextern int ams_debug_validateQuantityStructure        PROTO((void* quant_obj, int validateSetGet, char* printStr));\nextern void* ams_debug_getQuantityPortHiconn          PROTO((void* quant_obj));\nextern double ams_debug_GetTerminalContribution       PROTO((void* term_obj));\nextern void ams_debug_SetTerminalContribution         PROTO((void* term_obj, double value));\nextern double ams_debug_GetTerminalReference          PROTO((void* term_obj));\nextern void ams_debug_SetTerminalReference            PROTO((void* term_obj, double value));\nextern int ams_debug_getTerminalTDKind                PROTO((void* term_obj));\nextern int ams_debug_getTerminalPortMode              PROTO((void* term_obj));\nextern int ams_debug_getArrayTerminalNumChildren      PROTO((void* term_obj));\nextern int ams_debug_validateTerminalStructure        PROTO((void* term_obj, int validateSetGet, char* printStr));\nextern void* ams_debug_getTerminalPortHiconn          PROTO((void* term_obj));\n\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n\n#endif /* MTI_H */\n\n/* ***************************** End of Header ***************************** */\n"
  },
  {
    "path": "src/cocotb/_vendor/tcl/license.terms",
    "content": "This software is copyrighted by the Regents of the University of\nCalifornia, Sun Microsystems, Inc., Scriptics Corporation, ActiveState\nCorporation and other parties.  The following terms apply to all files\nassociated with the software unless explicitly disclaimed in\nindividual files.\n\nThe authors hereby grant permission to use, copy, modify, distribute,\nand license this software and its documentation for any purpose, provided\nthat existing copyright notices are retained in all copies and that this\nnotice is included verbatim in any distributions. No written agreement,\nlicense, or royalty fee is required for any of the authorized uses.\nModifications to this software may be copyrighted by their authors\nand need not follow the licensing terms described here, provided that\nthe new terms are clearly indicated on the first page of each file where\nthey apply.\n\nIN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\nFOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\nARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\nDERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\nTHE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\nINCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\nIS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\nNO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\nMODIFICATIONS.\n\nGOVERNMENT USE: If you are acquiring this software on behalf of the\nU.S. government, the Government shall have only \"Restricted Rights\"\nin the software and related documentation as defined in the Federal\nAcquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you\nare acquiring the software on behalf of the Department of Defense, the\nsoftware shall be classified as \"Commercial Computer Software\" and the\nGovernment shall have only \"Restricted Rights\" as defined in Clause\n252.227-7014 (b) (3) of DFARs.  Notwithstanding the foregoing, the\nauthors grant the U.S. Government and others acting in its behalf\npermission to use and distribute the software in accordance with the\nterms specified in this license.\n"
  },
  {
    "path": "src/cocotb/_vendor/tcl/tcl.h",
    "content": "/*\n * tcl.h --\n *\n *\tThis header file describes the externally-visible facilities of the\n *\tTcl interpreter.\n *\n * Copyright (c) 1987-1994 The Regents of the University of California.\n * Copyright (c) 1993-1996 Lucent Technologies.\n * Copyright (c) 1994-1998 Sun Microsystems, Inc.\n * Copyright (c) 1998-2000 by Scriptics Corporation.\n * Copyright (c) 2002 by Kevin B. Kenny.  All rights reserved.\n *\n * See the file \"license.terms\" for information on usage and redistribution of\n * this file, and for a DISCLAIMER OF ALL WARRANTIES.\n */\n\n#ifndef _TCL\n#define _TCL\n\n/*\n * For C++ compilers, use extern \"C\"\n */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n * The following defines are used to indicate the various release levels.\n */\n\n#define TCL_ALPHA_RELEASE\t0\n#define TCL_BETA_RELEASE\t1\n#define TCL_FINAL_RELEASE\t2\n\n/*\n * When version numbers change here, must also go into the following files and\n * update the version numbers:\n *\n * library/init.tcl\t(1 LOC patch)\n * unix/configure.in\t(2 LOC Major, 2 LOC minor, 1 LOC patch)\n * win/configure.in\t(as above)\n * win/tcl.m4\t\t(not patchlevel)\n * win/makefile.bc\t(not patchlevel) 2 LOC\n * README\t\t(sections 0 and 2, with and without separator)\n * macosx/Tcl.pbproj/project.pbxproj (not patchlevel) 1 LOC\n * macosx/Tcl.pbproj/default.pbxuser (not patchlevel) 1 LOC\n * macosx/Tcl.xcode/project.pbxproj (not patchlevel) 2 LOC\n * macosx/Tcl.xcode/default.pbxuser (not patchlevel) 1 LOC\n * macosx/Tcl-Common.xcconfig (not patchlevel) 1 LOC\n * win/README\t\t(not patchlevel) (sections 0 and 2)\n * unix/tcl.spec\t(1 LOC patch)\n * tools/tcl.hpj.in\t(not patchlevel, for windows installer)\n */\n\n#define TCL_MAJOR_VERSION   8\n#define TCL_MINOR_VERSION   6\n#define TCL_RELEASE_LEVEL   TCL_FINAL_RELEASE\n#define TCL_RELEASE_SERIAL  5\n\n#define TCL_VERSION\t    \"8.6\"\n#define TCL_PATCH_LEVEL\t    \"8.6.5\"\n\f\n/*\n *----------------------------------------------------------------------------\n * The following definitions set up the proper options for Windows compilers.\n * We use this method because there is no autoconf equivalent.\n */\n\n#ifdef _WIN32\n#   ifndef __WIN32__\n#\tdefine __WIN32__\n#   endif\n#   ifndef WIN32\n#\tdefine WIN32\n#   endif\n#endif\n\n/*\n * Utility macros: STRINGIFY takes an argument and wraps it in \"\" (double\n * quotation marks), JOIN joins two arguments.\n */\n\n#ifndef STRINGIFY\n#  define STRINGIFY(x) STRINGIFY1(x)\n#  define STRINGIFY1(x) #x\n#endif\n#ifndef JOIN\n#  define JOIN(a,b) JOIN1(a,b)\n#  define JOIN1(a,b) a##b\n#endif\n\n/*\n * A special definition used to allow this header file to be included from\n * windows resource files so that they can obtain version information.\n * RC_INVOKED is defined by default by the windows RC tool.\n *\n * Resource compilers don't like all the C stuff, like typedefs and function\n * declarations, that occur below, so block them out.\n */\n\n#ifndef RC_INVOKED\n\n/*\n * Special macro to define mutexes, that doesn't do anything if we are not\n * using threads.\n */\n\n#ifdef TCL_THREADS\n#define TCL_DECLARE_MUTEX(name) static Tcl_Mutex name;\n#else\n#define TCL_DECLARE_MUTEX(name)\n#endif\n\n/*\n * Tcl's public routine Tcl_FSSeek() uses the values SEEK_SET, SEEK_CUR, and\n * SEEK_END, all #define'd by stdio.h .\n *\n * Also, many extensions need stdio.h, and they've grown accustomed to tcl.h\n * providing it for them rather than #include-ing it themselves as they\n * should, so also for their sake, we keep the #include to be consistent with\n * prior Tcl releases.\n */\n\n#include <stdio.h>\n\n/*\n *----------------------------------------------------------------------------\n * Support for functions with a variable number of arguments.\n *\n * The following TCL_VARARGS* macros are to support old extensions\n * written for older versions of Tcl where the macros permitted\n * support for the varargs.h system as well as stdarg.h .\n *\n * New code should just directly be written to use stdarg.h conventions.\n */\n\n#include <stdarg.h>\n#ifndef TCL_NO_DEPRECATED\n#    define TCL_VARARGS(type, name) (type name, ...)\n#    define TCL_VARARGS_DEF(type, name) (type name, ...)\n#    define TCL_VARARGS_START(type, name, list) (va_start(list, name), name)\n#endif\n#if defined(__GNUC__) && (__GNUC__ > 2)\n#   define TCL_FORMAT_PRINTF(a,b) __attribute__ ((__format__ (__printf__, a, b)))\n#   define TCL_NORETURN __attribute__ ((noreturn))\n#   if defined(BUILD_tcl) || defined(BUILD_tk)\n#\tdefine TCL_NORETURN1 __attribute__ ((noreturn))\n#   else\n#\tdefine TCL_NORETURN1 /* nothing */\n#   endif\n#else\n#   define TCL_FORMAT_PRINTF(a,b)\n#   if defined(_MSC_VER) && (_MSC_VER >= 1310)\n#\tdefine TCL_NORETURN _declspec(noreturn)\n#   else\n#\tdefine TCL_NORETURN /* nothing */\n#   endif\n#   define TCL_NORETURN1 /* nothing */\n#endif\n\n/*\n * Allow a part of Tcl's API to be explicitly marked as deprecated.\n *\n * Used to make TIP 330/336 generate moans even if people use the\n * compatibility macros. Change your code, guys! We won't support you forever.\n */\n\n#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))\n#   if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5))\n#\tdefine TCL_DEPRECATED_API(msg)\t__attribute__ ((__deprecated__ (msg)))\n#   else\n#\tdefine TCL_DEPRECATED_API(msg)\t__attribute__ ((__deprecated__))\n#   endif\n#else\n#   define TCL_DEPRECATED_API(msg)\t/* nothing portable */\n#endif\n\n/*\n *----------------------------------------------------------------------------\n * Macros used to declare a function to be exported by a DLL. Used by Windows,\n * maps to no-op declarations on non-Windows systems. The default build on\n * windows is for a DLL, which causes the DLLIMPORT and DLLEXPORT macros to be\n * nonempty. To build a static library, the macro STATIC_BUILD should be\n * defined.\n *\n * Note: when building static but linking dynamically to MSVCRT we must still\n *       correctly decorate the C library imported function.  Use CRTIMPORT\n *       for this purpose.  _DLL is defined by the compiler when linking to\n *       MSVCRT.\n */\n\n#if (defined(_WIN32) && (defined(_MSC_VER) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x0550)) || defined(__LCC__) || defined(__WATCOMC__) || (defined(__GNUC__) && defined(__declspec))))\n#   define HAVE_DECLSPEC 1\n#   ifdef STATIC_BUILD\n#       define DLLIMPORT\n#       define DLLEXPORT\n#       ifdef _DLL\n#           define CRTIMPORT __declspec(dllimport)\n#       else\n#           define CRTIMPORT\n#       endif\n#   else\n#       define DLLIMPORT __declspec(dllimport)\n#       define DLLEXPORT __declspec(dllexport)\n#       define CRTIMPORT __declspec(dllimport)\n#   endif\n#else\n#   define DLLIMPORT\n#   if defined(__GNUC__) && __GNUC__ > 3\n#       define DLLEXPORT __attribute__ ((visibility(\"default\")))\n#   else\n#       define DLLEXPORT\n#   endif\n#   define CRTIMPORT\n#endif\n\n/*\n * These macros are used to control whether functions are being declared for\n * import or export. If a function is being declared while it is being built\n * to be included in a shared library, then it should have the DLLEXPORT\n * storage class. If is being declared for use by a module that is going to\n * link against the shared library, then it should have the DLLIMPORT storage\n * class. If the symbol is beind declared for a static build or for use from a\n * stub library, then the storage class should be empty.\n *\n * The convention is that a macro called BUILD_xxxx, where xxxx is the name of\n * a library we are building, is set on the compile line for sources that are\n * to be placed in the library. When this macro is set, the storage class will\n * be set to DLLEXPORT. At the end of the header file, the storage class will\n * be reset to DLLIMPORT.\n */\n\n#undef TCL_STORAGE_CLASS\n#ifdef BUILD_tcl\n#   define TCL_STORAGE_CLASS DLLEXPORT\n#else\n#   ifdef USE_TCL_STUBS\n#      define TCL_STORAGE_CLASS\n#   else\n#      define TCL_STORAGE_CLASS DLLIMPORT\n#   endif\n#endif\n\n/*\n * The following _ANSI_ARGS_ macro is to support old extensions\n * written for older versions of Tcl where it permitted support\n * for compilers written in the pre-prototype era of C.\n *\n * New code should use prototypes.\n */\n\n#ifndef TCL_NO_DEPRECATED\n#   undef _ANSI_ARGS_\n#   define _ANSI_ARGS_(x)\tx\n#endif\n\n/*\n * Definitions that allow this header file to be used either with or without\n * ANSI C features.\n */\n\n#ifndef INLINE\n#   define INLINE\n#endif\n\n#ifdef NO_CONST\n#   ifndef const\n#      define const\n#   endif\n#endif\n#ifndef CONST\n#   define CONST const\n#endif\n\n#ifdef USE_NON_CONST\n#   ifdef USE_COMPAT_CONST\n#      error define at most one of USE_NON_CONST and USE_COMPAT_CONST\n#   endif\n#   define CONST84\n#   define CONST84_RETURN\n#else\n#   ifdef USE_COMPAT_CONST\n#      define CONST84\n#      define CONST84_RETURN const\n#   else\n#      define CONST84 const\n#      define CONST84_RETURN const\n#   endif\n#endif\n\n#ifndef CONST86\n#      define CONST86 CONST84\n#endif\n\n/*\n * Make sure EXTERN isn't defined elsewhere.\n */\n\n#ifdef EXTERN\n#   undef EXTERN\n#endif /* EXTERN */\n\n#ifdef __cplusplus\n#   define EXTERN extern \"C\" TCL_STORAGE_CLASS\n#else\n#   define EXTERN extern TCL_STORAGE_CLASS\n#endif\n\n/*\n *----------------------------------------------------------------------------\n * The following code is copied from winnt.h. If we don't replicate it here,\n * then <windows.h> can't be included after tcl.h, since tcl.h also defines\n * VOID. This block is skipped under Cygwin and Mingw.\n */\n\n#if defined(_WIN32) && !defined(HAVE_WINNT_IGNORE_VOID)\n#ifndef VOID\n#define VOID void\ntypedef char CHAR;\ntypedef short SHORT;\ntypedef long LONG;\n#endif\n#endif /* _WIN32 && !HAVE_WINNT_IGNORE_VOID */\n\n/*\n * Macro to use instead of \"void\" for arguments that must have type \"void *\"\n * in ANSI C; maps them to type \"char *\" in non-ANSI systems.\n */\n\n#ifndef __VXWORKS__\n#   ifndef NO_VOID\n#\tdefine VOID void\n#   else\n#\tdefine VOID char\n#   endif\n#endif\n\n/*\n * Miscellaneous declarations.\n */\n\n#ifndef _CLIENTDATA\n#   ifndef NO_VOID\n\ttypedef void *ClientData;\n#   else\n\ttypedef int *ClientData;\n#   endif\n#   define _CLIENTDATA\n#endif\n\n/*\n * Darwin specific configure overrides (to support fat compiles, where\n * configure runs only once for multiple architectures):\n */\n\n#ifdef __APPLE__\n#   ifdef __LP64__\n#\tundef TCL_WIDE_INT_TYPE\n#\tdefine TCL_WIDE_INT_IS_LONG 1\n#\tdefine TCL_CFG_DO64BIT 1\n#    else /* !__LP64__ */\n#\tdefine TCL_WIDE_INT_TYPE long long\n#\tundef TCL_WIDE_INT_IS_LONG\n#\tundef TCL_CFG_DO64BIT\n#    endif /* __LP64__ */\n#    undef HAVE_STRUCT_STAT64\n#endif /* __APPLE__ */\n\n/*\n * Define Tcl_WideInt to be a type that is (at least) 64-bits wide, and define\n * Tcl_WideUInt to be the unsigned variant of that type (assuming that where\n * we have one, we can have the other.)\n *\n * Also defines the following macros:\n * TCL_WIDE_INT_IS_LONG - if wide ints are really longs (i.e. we're on a real\n *\t64-bit system.)\n * Tcl_WideAsLong - forgetful converter from wideInt to long.\n * Tcl_LongAsWide - sign-extending converter from long to wideInt.\n * Tcl_WideAsDouble - converter from wideInt to double.\n * Tcl_DoubleAsWide - converter from double to wideInt.\n *\n * The following invariant should hold for any long value 'longVal':\n *\tlongVal == Tcl_WideAsLong(Tcl_LongAsWide(longVal))\n *\n * Note on converting between Tcl_WideInt and strings. This implementation (in\n * tclObj.c) depends on the function\n * sprintf(...,\"%\" TCL_LL_MODIFIER \"d\",...).\n */\n\n#if !defined(TCL_WIDE_INT_TYPE)&&!defined(TCL_WIDE_INT_IS_LONG)\n#   if defined(_WIN32)\n#      define TCL_WIDE_INT_TYPE __int64\n#      ifdef __BORLANDC__\n#         define TCL_LL_MODIFIER\t\"L\"\n#      else /* __BORLANDC__ */\n#         define TCL_LL_MODIFIER\t\"I64\"\n#      endif /* __BORLANDC__ */\n#   elif defined(__GNUC__)\n#      define TCL_WIDE_INT_TYPE long long\n#      define TCL_LL_MODIFIER\t\"ll\"\n#   else /* ! _WIN32 && ! __GNUC__ */\n/*\n * Don't know what platform it is and configure hasn't discovered what is\n * going on for us. Try to guess...\n */\n#      include <limits.h>\n#      if (INT_MAX < LONG_MAX)\n#         define TCL_WIDE_INT_IS_LONG\t1\n#      else\n#         define TCL_WIDE_INT_TYPE long long\n#      endif\n#   endif /* _WIN32 */\n#endif /* !TCL_WIDE_INT_TYPE & !TCL_WIDE_INT_IS_LONG */\n#ifdef TCL_WIDE_INT_IS_LONG\n#   undef TCL_WIDE_INT_TYPE\n#   define TCL_WIDE_INT_TYPE\tlong\n#endif /* TCL_WIDE_INT_IS_LONG */\n\ntypedef TCL_WIDE_INT_TYPE\t\tTcl_WideInt;\ntypedef unsigned TCL_WIDE_INT_TYPE\tTcl_WideUInt;\n\n#ifdef TCL_WIDE_INT_IS_LONG\n#   define Tcl_WideAsLong(val)\t\t((long)(val))\n#   define Tcl_LongAsWide(val)\t\t((long)(val))\n#   define Tcl_WideAsDouble(val)\t((double)((long)(val)))\n#   define Tcl_DoubleAsWide(val)\t((long)((double)(val)))\n#   ifndef TCL_LL_MODIFIER\n#      define TCL_LL_MODIFIER\t\t\"l\"\n#   endif /* !TCL_LL_MODIFIER */\n#else /* TCL_WIDE_INT_IS_LONG */\n/*\n * The next short section of defines are only done when not running on Windows\n * or some other strange platform.\n */\n#   ifndef TCL_LL_MODIFIER\n#      define TCL_LL_MODIFIER\t\t\"ll\"\n#   endif /* !TCL_LL_MODIFIER */\n#   define Tcl_WideAsLong(val)\t\t((long)((Tcl_WideInt)(val)))\n#   define Tcl_LongAsWide(val)\t\t((Tcl_WideInt)((long)(val)))\n#   define Tcl_WideAsDouble(val)\t((double)((Tcl_WideInt)(val)))\n#   define Tcl_DoubleAsWide(val)\t((Tcl_WideInt)((double)(val)))\n#endif /* TCL_WIDE_INT_IS_LONG */\n\n#if defined(_WIN32)\n#   ifdef __BORLANDC__\n\ttypedef struct stati64 Tcl_StatBuf;\n#   elif defined(_WIN64)\n\ttypedef struct __stat64 Tcl_StatBuf;\n#   elif (defined(_MSC_VER) && (_MSC_VER < 1400)) || defined(_USE_32BIT_TIME_T)\n\ttypedef struct _stati64\tTcl_StatBuf;\n#   else\n\ttypedef struct _stat32i64 Tcl_StatBuf;\n#   endif /* _MSC_VER < 1400 */\n#elif defined(__CYGWIN__)\n    typedef struct {\n\tdev_t st_dev;\n\tunsigned short st_ino;\n\tunsigned short st_mode;\n\tshort st_nlink;\n\tshort st_uid;\n\tshort st_gid;\n\t/* Here is a 2-byte gap */\n\tdev_t st_rdev;\n\t/* Here is a 4-byte gap */\n\tlong long st_size;\n\tstruct {long tv_sec;} st_atim;\n\tstruct {long tv_sec;} st_mtim;\n\tstruct {long tv_sec;} st_ctim;\n\t/* Here is a 4-byte gap */\n    } Tcl_StatBuf;\n#elif defined(HAVE_STRUCT_STAT64) && !defined(__APPLE__)\n    typedef struct stat64 Tcl_StatBuf;\n#else\n    typedef struct stat Tcl_StatBuf;\n#endif\n\f\n/*\n *----------------------------------------------------------------------------\n * Data structures defined opaquely in this module. The definitions below just\n * provide dummy types. A few fields are made visible in Tcl_Interp\n * structures, namely those used for returning a string result from commands.\n * Direct access to the result field is discouraged in Tcl 8.0. The\n * interpreter result is either an object or a string, and the two values are\n * kept consistent unless some C code sets interp->result directly.\n * Programmers should use either the function Tcl_GetObjResult() or\n * Tcl_GetStringResult() to read the interpreter's result. See the SetResult\n * man page for details.\n *\n * Note: any change to the Tcl_Interp definition below must be mirrored in the\n * \"real\" definition in tclInt.h.\n *\n * Note: Tcl_ObjCmdProc functions do not directly set result and freeProc.\n * Instead, they set a Tcl_Obj member in the \"real\" structure that can be\n * accessed with Tcl_GetObjResult() and Tcl_SetObjResult().\n */\n\ntypedef struct Tcl_Interp\n#ifndef TCL_NO_DEPRECATED\n{\n    /* TIP #330: Strongly discourage extensions from using the string\n     * result. */\n#ifdef USE_INTERP_RESULT\n    char *result TCL_DEPRECATED_API(\"use Tcl_GetStringResult/Tcl_SetResult\");\n\t\t\t\t/* If the last command returned a string\n\t\t\t\t * result, this points to it. */\n    void (*freeProc) (char *blockPtr)\n\t    TCL_DEPRECATED_API(\"use Tcl_GetStringResult/Tcl_SetResult\");\n\t\t\t\t/* Zero means the string result is statically\n\t\t\t\t * allocated. TCL_DYNAMIC means it was\n\t\t\t\t * allocated with ckalloc and should be freed\n\t\t\t\t * with ckfree. Other values give the address\n\t\t\t\t * of function to invoke to free the result.\n\t\t\t\t * Tcl_Eval must free it before executing next\n\t\t\t\t * command. */\n#else\n    char *resultDontUse; /* Don't use in extensions! */\n    void (*freeProcDontUse) (char *); /* Don't use in extensions! */\n#endif\n#ifdef USE_INTERP_ERRORLINE\n    int errorLine TCL_DEPRECATED_API(\"use Tcl_GetErrorLine/Tcl_SetErrorLine\");\n\t\t\t\t/* When TCL_ERROR is returned, this gives the\n\t\t\t\t * line number within the command where the\n\t\t\t\t * error occurred (1 if first line). */\n#else\n    int errorLineDontUse; /* Don't use in extensions! */\n#endif\n}\n#endif /* TCL_NO_DEPRECATED */\nTcl_Interp;\n\ntypedef struct Tcl_AsyncHandler_ *Tcl_AsyncHandler;\ntypedef struct Tcl_Channel_ *Tcl_Channel;\ntypedef struct Tcl_ChannelTypeVersion_ *Tcl_ChannelTypeVersion;\ntypedef struct Tcl_Command_ *Tcl_Command;\ntypedef struct Tcl_Condition_ *Tcl_Condition;\ntypedef struct Tcl_Dict_ *Tcl_Dict;\ntypedef struct Tcl_EncodingState_ *Tcl_EncodingState;\ntypedef struct Tcl_Encoding_ *Tcl_Encoding;\ntypedef struct Tcl_Event Tcl_Event;\ntypedef struct Tcl_InterpState_ *Tcl_InterpState;\ntypedef struct Tcl_LoadHandle_ *Tcl_LoadHandle;\ntypedef struct Tcl_Mutex_ *Tcl_Mutex;\ntypedef struct Tcl_Pid_ *Tcl_Pid;\ntypedef struct Tcl_RegExp_ *Tcl_RegExp;\ntypedef struct Tcl_ThreadDataKey_ *Tcl_ThreadDataKey;\ntypedef struct Tcl_ThreadId_ *Tcl_ThreadId;\ntypedef struct Tcl_TimerToken_ *Tcl_TimerToken;\ntypedef struct Tcl_Trace_ *Tcl_Trace;\ntypedef struct Tcl_Var_ *Tcl_Var;\ntypedef struct Tcl_ZLibStream_ *Tcl_ZlibStream;\n\n/*\n *----------------------------------------------------------------------------\n * Definition of the interface to functions implementing threads. A function\n * following this definition is given to each call of 'Tcl_CreateThread' and\n * will be called as the main fuction of the new thread created by that call.\n */\n\n#if defined _WIN32\ntypedef unsigned (__stdcall Tcl_ThreadCreateProc) (ClientData clientData);\n#else\ntypedef void (Tcl_ThreadCreateProc) (ClientData clientData);\n#endif\n\n/*\n * Threading function return types used for abstracting away platform\n * differences when writing a Tcl_ThreadCreateProc. See the NewThread function\n * in generic/tclThreadTest.c for it's usage.\n */\n\n#if defined _WIN32\n#   define Tcl_ThreadCreateType\t\tunsigned __stdcall\n#   define TCL_THREAD_CREATE_RETURN\treturn 0\n#else\n#   define Tcl_ThreadCreateType\t\tvoid\n#   define TCL_THREAD_CREATE_RETURN\n#endif\n\n/*\n * Definition of values for default stacksize and the possible flags to be\n * given to Tcl_CreateThread.\n */\n\n#define TCL_THREAD_STACK_DEFAULT (0)    /* Use default size for stack. */\n#define TCL_THREAD_NOFLAGS\t (0000) /* Standard flags, default\n\t\t\t\t\t * behaviour. */\n#define TCL_THREAD_JOINABLE\t (0001) /* Mark the thread as joinable. */\n\n/*\n * Flag values passed to Tcl_StringCaseMatch.\n */\n\n#define TCL_MATCH_NOCASE\t(1<<0)\n\n/*\n * Flag values passed to Tcl_GetRegExpFromObj.\n */\n\n#define\tTCL_REG_BASIC\t\t000000\t/* BREs (convenience). */\n#define\tTCL_REG_EXTENDED\t000001\t/* EREs. */\n#define\tTCL_REG_ADVF\t\t000002\t/* Advanced features in EREs. */\n#define\tTCL_REG_ADVANCED\t000003\t/* AREs (which are also EREs). */\n#define\tTCL_REG_QUOTE\t\t000004\t/* No special characters, none. */\n#define\tTCL_REG_NOCASE\t\t000010\t/* Ignore case. */\n#define\tTCL_REG_NOSUB\t\t000020\t/* Don't care about subexpressions. */\n#define\tTCL_REG_EXPANDED\t000040\t/* Expanded format, white space &\n\t\t\t\t\t * comments. */\n#define\tTCL_REG_NLSTOP\t\t000100  /* \\n doesn't match . or [^ ] */\n#define\tTCL_REG_NLANCH\t\t000200  /* ^ matches after \\n, $ before. */\n#define\tTCL_REG_NEWLINE\t\t000300  /* Newlines are line terminators. */\n#define\tTCL_REG_CANMATCH\t001000  /* Report details on partial/limited\n\t\t\t\t\t * matches. */\n\n/*\n * Flags values passed to Tcl_RegExpExecObj.\n */\n\n#define\tTCL_REG_NOTBOL\t0001\t/* Beginning of string does not match ^.  */\n#define\tTCL_REG_NOTEOL\t0002\t/* End of string does not match $. */\n\n/*\n * Structures filled in by Tcl_RegExpInfo. Note that all offset values are\n * relative to the start of the match string, not the beginning of the entire\n * string.\n */\n\ntypedef struct Tcl_RegExpIndices {\n    long start;\t\t\t/* Character offset of first character in\n\t\t\t\t * match. */\n    long end;\t\t\t/* Character offset of first character after\n\t\t\t\t * the match. */\n} Tcl_RegExpIndices;\n\ntypedef struct Tcl_RegExpInfo {\n    int nsubs;\t\t\t/* Number of subexpressions in the compiled\n\t\t\t\t * expression. */\n    Tcl_RegExpIndices *matches;\t/* Array of nsubs match offset pairs. */\n    long extendStart;\t\t/* The offset at which a subsequent match\n\t\t\t\t * might begin. */\n    long reserved;\t\t/* Reserved for later use. */\n} Tcl_RegExpInfo;\n\n/*\n * Picky compilers complain if this typdef doesn't appear before the struct's\n * reference in tclDecls.h.\n */\n\ntypedef Tcl_StatBuf *Tcl_Stat_;\ntypedef struct stat *Tcl_OldStat_;\n\n/*\n *----------------------------------------------------------------------------\n * When a TCL command returns, the interpreter contains a result from the\n * command. Programmers are strongly encouraged to use one of the functions\n * Tcl_GetObjResult() or Tcl_GetStringResult() to read the interpreter's\n * result. See the SetResult man page for details. Besides this result, the\n * command function returns an integer code, which is one of the following:\n *\n * TCL_OK\t\tCommand completed normally; the interpreter's result\n *\t\t\tcontains the command's result.\n * TCL_ERROR\t\tThe command couldn't be completed successfully; the\n *\t\t\tinterpreter's result describes what went wrong.\n * TCL_RETURN\t\tThe command requests that the current function return;\n *\t\t\tthe interpreter's result contains the function's\n *\t\t\treturn value.\n * TCL_BREAK\t\tThe command requests that the innermost loop be\n *\t\t\texited; the interpreter's result is meaningless.\n * TCL_CONTINUE\t\tGo on to the next iteration of the current loop; the\n *\t\t\tinterpreter's result is meaningless.\n */\n\n#define TCL_OK\t\t\t0\n#define TCL_ERROR\t\t1\n#define TCL_RETURN\t\t2\n#define TCL_BREAK\t\t3\n#define TCL_CONTINUE\t\t4\n\n#define TCL_RESULT_SIZE\t\t200\n\n/*\n *----------------------------------------------------------------------------\n * Flags to control what substitutions are performed by Tcl_SubstObj():\n */\n\n#define TCL_SUBST_COMMANDS\t001\n#define TCL_SUBST_VARIABLES\t002\n#define TCL_SUBST_BACKSLASHES\t004\n#define TCL_SUBST_ALL\t\t007\n\n/*\n * Argument descriptors for math function callbacks in expressions:\n */\n\ntypedef enum {\n    TCL_INT, TCL_DOUBLE, TCL_EITHER, TCL_WIDE_INT\n} Tcl_ValueType;\n\ntypedef struct Tcl_Value {\n    Tcl_ValueType type;\t\t/* Indicates intValue or doubleValue is valid,\n\t\t\t\t * or both. */\n    long intValue;\t\t/* Integer value. */\n    double doubleValue;\t\t/* Double-precision floating value. */\n    Tcl_WideInt wideValue;\t/* Wide (min. 64-bit) integer value. */\n} Tcl_Value;\n\n/*\n * Forward declaration of Tcl_Obj to prevent an error when the forward\n * reference to Tcl_Obj is encountered in the function types declared below.\n */\n\nstruct Tcl_Obj;\n\n/*\n *----------------------------------------------------------------------------\n * Function types defined by Tcl:\n */\n\ntypedef int (Tcl_AppInitProc) (Tcl_Interp *interp);\ntypedef int (Tcl_AsyncProc) (ClientData clientData, Tcl_Interp *interp,\n\tint code);\ntypedef void (Tcl_ChannelProc) (ClientData clientData, int mask);\ntypedef void (Tcl_CloseProc) (ClientData data);\ntypedef void (Tcl_CmdDeleteProc) (ClientData clientData);\ntypedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp *interp,\n\tint argc, CONST84 char *argv[]);\ntypedef void (Tcl_CmdTraceProc) (ClientData clientData, Tcl_Interp *interp,\n\tint level, char *command, Tcl_CmdProc *proc,\n\tClientData cmdClientData, int argc, CONST84 char *argv[]);\ntypedef int (Tcl_CmdObjTraceProc) (ClientData clientData, Tcl_Interp *interp,\n\tint level, const char *command, Tcl_Command commandInfo, int objc,\n\tstruct Tcl_Obj *const *objv);\ntypedef void (Tcl_CmdObjTraceDeleteProc) (ClientData clientData);\ntypedef void (Tcl_DupInternalRepProc) (struct Tcl_Obj *srcPtr,\n\tstruct Tcl_Obj *dupPtr);\ntypedef int (Tcl_EncodingConvertProc) (ClientData clientData, const char *src,\n\tint srcLen, int flags, Tcl_EncodingState *statePtr, char *dst,\n\tint dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr);\ntypedef void (Tcl_EncodingFreeProc) (ClientData clientData);\ntypedef int (Tcl_EventProc) (Tcl_Event *evPtr, int flags);\ntypedef void (Tcl_EventCheckProc) (ClientData clientData, int flags);\ntypedef int (Tcl_EventDeleteProc) (Tcl_Event *evPtr, ClientData clientData);\ntypedef void (Tcl_EventSetupProc) (ClientData clientData, int flags);\ntypedef void (Tcl_ExitProc) (ClientData clientData);\ntypedef void (Tcl_FileProc) (ClientData clientData, int mask);\ntypedef void (Tcl_FileFreeProc) (ClientData clientData);\ntypedef void (Tcl_FreeInternalRepProc) (struct Tcl_Obj *objPtr);\ntypedef void (Tcl_FreeProc) (char *blockPtr);\ntypedef void (Tcl_IdleProc) (ClientData clientData);\ntypedef void (Tcl_InterpDeleteProc) (ClientData clientData,\n\tTcl_Interp *interp);\ntypedef int (Tcl_MathProc) (ClientData clientData, Tcl_Interp *interp,\n\tTcl_Value *args, Tcl_Value *resultPtr);\ntypedef void (Tcl_NamespaceDeleteProc) (ClientData clientData);\ntypedef int (Tcl_ObjCmdProc) (ClientData clientData, Tcl_Interp *interp,\n\tint objc, struct Tcl_Obj *const *objv);\ntypedef int (Tcl_PackageInitProc) (Tcl_Interp *interp);\ntypedef int (Tcl_PackageUnloadProc) (Tcl_Interp *interp, int flags);\ntypedef void (Tcl_PanicProc) (const char *format, ...);\ntypedef void (Tcl_TcpAcceptProc) (ClientData callbackData, Tcl_Channel chan,\n\tchar *address, int port);\ntypedef void (Tcl_TimerProc) (ClientData clientData);\ntypedef int (Tcl_SetFromAnyProc) (Tcl_Interp *interp, struct Tcl_Obj *objPtr);\ntypedef void (Tcl_UpdateStringProc) (struct Tcl_Obj *objPtr);\ntypedef char * (Tcl_VarTraceProc) (ClientData clientData, Tcl_Interp *interp,\n\tCONST84 char *part1, CONST84 char *part2, int flags);\ntypedef void (Tcl_CommandTraceProc) (ClientData clientData, Tcl_Interp *interp,\n\tconst char *oldName, const char *newName, int flags);\ntypedef void (Tcl_CreateFileHandlerProc) (int fd, int mask, Tcl_FileProc *proc,\n\tClientData clientData);\ntypedef void (Tcl_DeleteFileHandlerProc) (int fd);\ntypedef void (Tcl_AlertNotifierProc) (ClientData clientData);\ntypedef void (Tcl_ServiceModeHookProc) (int mode);\ntypedef ClientData (Tcl_InitNotifierProc) (void);\ntypedef void (Tcl_FinalizeNotifierProc) (ClientData clientData);\ntypedef void (Tcl_MainLoopProc) (void);\n\f\n/*\n *----------------------------------------------------------------------------\n * The following structure represents a type of object, which is a particular\n * internal representation for an object plus a set of functions that provide\n * standard operations on objects of that type.\n */\n\ntypedef struct Tcl_ObjType {\n    const char *name;\t\t/* Name of the type, e.g. \"int\". */\n    Tcl_FreeInternalRepProc *freeIntRepProc;\n\t\t\t\t/* Called to free any storage for the type's\n\t\t\t\t * internal rep. NULL if the internal rep does\n\t\t\t\t * not need freeing. */\n    Tcl_DupInternalRepProc *dupIntRepProc;\n\t\t\t\t/* Called to create a new object as a copy of\n\t\t\t\t * an existing object. */\n    Tcl_UpdateStringProc *updateStringProc;\n\t\t\t\t/* Called to update the string rep from the\n\t\t\t\t * type's internal representation. */\n    Tcl_SetFromAnyProc *setFromAnyProc;\n\t\t\t\t/* Called to convert the object's internal rep\n\t\t\t\t * to this type. Frees the internal rep of the\n\t\t\t\t * old type. Returns TCL_ERROR on failure. */\n} Tcl_ObjType;\n\n/*\n * One of the following structures exists for each object in the Tcl system.\n * An object stores a value as either a string, some internal representation,\n * or both.\n */\n\ntypedef struct Tcl_Obj {\n    int refCount;\t\t/* When 0 the object will be freed. */\n    char *bytes;\t\t/* This points to the first byte of the\n\t\t\t\t * object's string representation. The array\n\t\t\t\t * must be followed by a null byte (i.e., at\n\t\t\t\t * offset length) but may also contain\n\t\t\t\t * embedded null characters. The array's\n\t\t\t\t * storage is allocated by ckalloc. NULL means\n\t\t\t\t * the string rep is invalid and must be\n\t\t\t\t * regenerated from the internal rep.  Clients\n\t\t\t\t * should use Tcl_GetStringFromObj or\n\t\t\t\t * Tcl_GetString to get a pointer to the byte\n\t\t\t\t * array as a readonly value. */\n    int length;\t\t\t/* The number of bytes at *bytes, not\n\t\t\t\t * including the terminating null. */\n    const Tcl_ObjType *typePtr;\t/* Denotes the object's type. Always\n\t\t\t\t * corresponds to the type of the object's\n\t\t\t\t * internal rep. NULL indicates the object has\n\t\t\t\t * no internal rep (has no type). */\n    union {\t\t\t/* The internal representation: */\n\tlong longValue;\t\t/*   - an long integer value. */\n\tdouble doubleValue;\t/*   - a double-precision floating value. */\n\tvoid *otherValuePtr;\t/*   - another, type-specific value,\n\t                       not used internally any more. */\n\tTcl_WideInt wideValue;\t/*   - a long long value. */\n\tstruct {\t\t/*   - internal rep as two pointers.\n\t\t\t\t *     the main use of which is a bignum's\n\t\t\t\t *     tightly packed fields, where the alloc,\n\t\t\t\t *     used and signum flags are packed into\n\t\t\t\t *     ptr2 with everything else hung off ptr1. */\n\t    void *ptr1;\n\t    void *ptr2;\n\t} twoPtrValue;\n\tstruct {\t\t/*   - internal rep as a pointer and a long,\n\t                       not used internally any more. */\n\t    void *ptr;\n\t    unsigned long value;\n\t} ptrAndLongRep;\n    } internalRep;\n} Tcl_Obj;\n\n/*\n * Macros to increment and decrement a Tcl_Obj's reference count, and to test\n * whether an object is shared (i.e. has reference count > 1). Note: clients\n * should use Tcl_DecrRefCount() when they are finished using an object, and\n * should never call TclFreeObj() directly. TclFreeObj() is only defined and\n * made public in tcl.h to support Tcl_DecrRefCount's macro definition.\n */\n\nvoid\t\tTcl_IncrRefCount(Tcl_Obj *objPtr);\nvoid\t\tTcl_DecrRefCount(Tcl_Obj *objPtr);\nint\t\tTcl_IsShared(Tcl_Obj *objPtr);\n\f\n/*\n *----------------------------------------------------------------------------\n * The following structure contains the state needed by Tcl_SaveResult. No-one\n * outside of Tcl should access any of these fields. This structure is\n * typically allocated on the stack.\n */\n\ntypedef struct Tcl_SavedResult {\n    char *result;\n    Tcl_FreeProc *freeProc;\n    Tcl_Obj *objResultPtr;\n    char *appendResult;\n    int appendAvl;\n    int appendUsed;\n    char resultSpace[TCL_RESULT_SIZE+1];\n} Tcl_SavedResult;\n\n/*\n *----------------------------------------------------------------------------\n * The following definitions support Tcl's namespace facility. Note: the first\n * five fields must match exactly the fields in a Namespace structure (see\n * tclInt.h).\n */\n\ntypedef struct Tcl_Namespace {\n    char *name;\t\t\t/* The namespace's name within its parent\n\t\t\t\t * namespace. This contains no ::'s. The name\n\t\t\t\t * of the global namespace is \"\" although \"::\"\n\t\t\t\t * is an synonym. */\n    char *fullName;\t\t/* The namespace's fully qualified name. This\n\t\t\t\t * starts with ::. */\n    ClientData clientData;\t/* Arbitrary value associated with this\n\t\t\t\t * namespace. */\n    Tcl_NamespaceDeleteProc *deleteProc;\n\t\t\t\t/* Function invoked when deleting the\n\t\t\t\t * namespace to, e.g., free clientData. */\n    struct Tcl_Namespace *parentPtr;\n\t\t\t\t/* Points to the namespace that contains this\n\t\t\t\t * one. NULL if this is the global\n\t\t\t\t * namespace. */\n} Tcl_Namespace;\n\n/*\n *----------------------------------------------------------------------------\n * The following structure represents a call frame, or activation record. A\n * call frame defines a naming context for a procedure call: its local scope\n * (for local variables) and its namespace scope (used for non-local\n * variables; often the global :: namespace). A call frame can also define the\n * naming context for a namespace eval or namespace inscope command: the\n * namespace in which the command's code should execute. The Tcl_CallFrame\n * structures exist only while procedures or namespace eval/inscope's are\n * being executed, and provide a Tcl call stack.\n *\n * A call frame is initialized and pushed using Tcl_PushCallFrame and popped\n * using Tcl_PopCallFrame. Storage for a Tcl_CallFrame must be provided by the\n * Tcl_PushCallFrame caller, and callers typically allocate them on the C call\n * stack for efficiency. For this reason, Tcl_CallFrame is defined as a\n * structure and not as an opaque token. However, most Tcl_CallFrame fields\n * are hidden since applications should not access them directly; others are\n * declared as \"dummyX\".\n *\n * WARNING!! The structure definition must be kept consistent with the\n * CallFrame structure in tclInt.h. If you change one, change the other.\n */\n\ntypedef struct Tcl_CallFrame {\n    Tcl_Namespace *nsPtr;\n    int dummy1;\n    int dummy2;\n    void *dummy3;\n    void *dummy4;\n    void *dummy5;\n    int dummy6;\n    void *dummy7;\n    void *dummy8;\n    int dummy9;\n    void *dummy10;\n    void *dummy11;\n    void *dummy12;\n    void *dummy13;\n} Tcl_CallFrame;\n\n/*\n *----------------------------------------------------------------------------\n * Information about commands that is returned by Tcl_GetCommandInfo and\n * passed to Tcl_SetCommandInfo. objProc is an objc/objv object-based command\n * function while proc is a traditional Tcl argc/argv string-based function.\n * Tcl_CreateObjCommand and Tcl_CreateCommand ensure that both objProc and\n * proc are non-NULL and can be called to execute the command. However, it may\n * be faster to call one instead of the other. The member isNativeObjectProc\n * is set to 1 if an object-based function was registered by\n * Tcl_CreateObjCommand, and to 0 if a string-based function was registered by\n * Tcl_CreateCommand. The other function is typically set to a compatibility\n * wrapper that does string-to-object or object-to-string argument conversions\n * then calls the other function.\n */\n\ntypedef struct Tcl_CmdInfo {\n    int isNativeObjectProc;\t/* 1 if objProc was registered by a call to\n\t\t\t\t * Tcl_CreateObjCommand; 0 otherwise.\n\t\t\t\t * Tcl_SetCmdInfo does not modify this\n\t\t\t\t * field. */\n    Tcl_ObjCmdProc *objProc;\t/* Command's object-based function. */\n    ClientData objClientData;\t/* ClientData for object proc. */\n    Tcl_CmdProc *proc;\t\t/* Command's string-based function. */\n    ClientData clientData;\t/* ClientData for string proc. */\n    Tcl_CmdDeleteProc *deleteProc;\n\t\t\t\t/* Function to call when command is\n\t\t\t\t * deleted. */\n    ClientData deleteData;\t/* Value to pass to deleteProc (usually the\n\t\t\t\t * same as clientData). */\n    Tcl_Namespace *namespacePtr;/* Points to the namespace that contains this\n\t\t\t\t * command. Note that Tcl_SetCmdInfo will not\n\t\t\t\t * change a command's namespace; use\n\t\t\t\t * TclRenameCommand or Tcl_Eval (of 'rename')\n\t\t\t\t * to do that. */\n} Tcl_CmdInfo;\n\n/*\n *----------------------------------------------------------------------------\n * The structure defined below is used to hold dynamic strings. The only\n * fields that clients should use are string and length, accessible via the\n * macros Tcl_DStringValue and Tcl_DStringLength.\n */\n\n#define TCL_DSTRING_STATIC_SIZE 200\ntypedef struct Tcl_DString {\n    char *string;\t\t/* Points to beginning of string: either\n\t\t\t\t * staticSpace below or a malloced array. */\n    int length;\t\t\t/* Number of non-NULL characters in the\n\t\t\t\t * string. */\n    int spaceAvl;\t\t/* Total number of bytes available for the\n\t\t\t\t * string and its terminating NULL char. */\n    char staticSpace[TCL_DSTRING_STATIC_SIZE];\n\t\t\t\t/* Space to use in common case where string is\n\t\t\t\t * small. */\n} Tcl_DString;\n\n#define Tcl_DStringLength(dsPtr) ((dsPtr)->length)\n#define Tcl_DStringValue(dsPtr) ((dsPtr)->string)\n#define Tcl_DStringTrunc Tcl_DStringSetLength\n\n/*\n * Definitions for the maximum number of digits of precision that may be\n * specified in the \"tcl_precision\" variable, and the number of bytes of\n * buffer space required by Tcl_PrintDouble.\n */\n\n#define TCL_MAX_PREC\t\t17\n#define TCL_DOUBLE_SPACE\t(TCL_MAX_PREC+10)\n\n/*\n * Definition for a number of bytes of buffer space sufficient to hold the\n * string representation of an integer in base 10 (assuming the existence of\n * 64-bit integers).\n */\n\n#define TCL_INTEGER_SPACE\t24\n\n/*\n * Flag values passed to Tcl_ConvertElement.\n * TCL_DONT_USE_BRACES forces it not to enclose the element in braces, but to\n *\tuse backslash quoting instead.\n * TCL_DONT_QUOTE_HASH disables the default quoting of the '#' character. It\n *\tis safe to leave the hash unquoted when the element is not the first\n *\telement of a list, and this flag can be used by the caller to indicate\n *\tthat condition.\n */\n\n#define TCL_DONT_USE_BRACES\t1\n#define TCL_DONT_QUOTE_HASH\t8\n\n/*\n * Flag that may be passed to Tcl_GetIndexFromObj to force it to disallow\n * abbreviated strings.\n */\n\n#define TCL_EXACT\t1\n\n/*\n *----------------------------------------------------------------------------\n * Flag values passed to Tcl_RecordAndEval, Tcl_EvalObj, Tcl_EvalObjv.\n * WARNING: these bit choices must not conflict with the bit choices for\n * evalFlag bits in tclInt.h!\n *\n * Meanings:\n *\tTCL_NO_EVAL:\t\tJust record this command\n *\tTCL_EVAL_GLOBAL:\tExecute script in global namespace\n *\tTCL_EVAL_DIRECT:\tDo not compile this script\n *\tTCL_EVAL_INVOKE:\tMagical Tcl_EvalObjv mode for aliases/ensembles\n *\t\t\t\to Run in iPtr->lookupNsPtr or global namespace\n *\t\t\t\to Cut out of error traces\n *\t\t\t\to Don't reset the flags controlling ensemble\n *\t\t\t\t  error message rewriting.\n *\tTCL_CANCEL_UNWIND:\tMagical Tcl_CancelEval mode that causes the\n *\t\t\t\tstack for the script in progress to be\n *\t\t\t\tcompletely unwound.\n *\tTCL_EVAL_NOERR:\tDo no exception reporting at all, just return\n *\t\t\t\tas the caller will report.\n */\n\n#define TCL_NO_EVAL\t\t0x010000\n#define TCL_EVAL_GLOBAL\t\t0x020000\n#define TCL_EVAL_DIRECT\t\t0x040000\n#define TCL_EVAL_INVOKE\t\t0x080000\n#define TCL_CANCEL_UNWIND\t0x100000\n#define TCL_EVAL_NOERR          0x200000\n\n/*\n * Special freeProc values that may be passed to Tcl_SetResult (see the man\n * page for details):\n */\n\n#define TCL_VOLATILE\t\t((Tcl_FreeProc *) 1)\n#define TCL_STATIC\t\t((Tcl_FreeProc *) 0)\n#define TCL_DYNAMIC\t\t((Tcl_FreeProc *) 3)\n\n/*\n * Flag values passed to variable-related functions.\n * WARNING: these bit choices must not conflict with the bit choice for\n * TCL_CANCEL_UNWIND, above.\n */\n\n#define TCL_GLOBAL_ONLY\t\t 1\n#define TCL_NAMESPACE_ONLY\t 2\n#define TCL_APPEND_VALUE\t 4\n#define TCL_LIST_ELEMENT\t 8\n#define TCL_TRACE_READS\t\t 0x10\n#define TCL_TRACE_WRITES\t 0x20\n#define TCL_TRACE_UNSETS\t 0x40\n#define TCL_TRACE_DESTROYED\t 0x80\n#define TCL_INTERP_DESTROYED\t 0x100\n#define TCL_LEAVE_ERR_MSG\t 0x200\n#define TCL_TRACE_ARRAY\t\t 0x800\n#ifndef TCL_REMOVE_OBSOLETE_TRACES\n/* Required to support old variable/vdelete/vinfo traces. */\n#define TCL_TRACE_OLD_STYLE\t 0x1000\n#endif\n/* Indicate the semantics of the result of a trace. */\n#define TCL_TRACE_RESULT_DYNAMIC 0x8000\n#define TCL_TRACE_RESULT_OBJECT  0x10000\n\n/*\n * Flag values for ensemble commands.\n */\n\n#define TCL_ENSEMBLE_PREFIX 0x02/* Flag value to say whether to allow\n\t\t\t\t * unambiguous prefixes of commands or to\n\t\t\t\t * require exact matches for command names. */\n\n/*\n * Flag values passed to command-related functions.\n */\n\n#define TCL_TRACE_RENAME\t0x2000\n#define TCL_TRACE_DELETE\t0x4000\n\n#define TCL_ALLOW_INLINE_COMPILATION 0x20000\n\n/*\n * The TCL_PARSE_PART1 flag is deprecated and has no effect. The part1 is now\n * always parsed whenever the part2 is NULL. (This is to avoid a common error\n * when converting code to use the new object based APIs and forgetting to\n * give the flag)\n */\n\n#ifndef TCL_NO_DEPRECATED\n#   define TCL_PARSE_PART1\t0x400\n#endif\n\n/*\n * Types for linked variables:\n */\n\n#define TCL_LINK_INT\t\t1\n#define TCL_LINK_DOUBLE\t\t2\n#define TCL_LINK_BOOLEAN\t3\n#define TCL_LINK_STRING\t\t4\n#define TCL_LINK_WIDE_INT\t5\n#define TCL_LINK_CHAR\t\t6\n#define TCL_LINK_UCHAR\t\t7\n#define TCL_LINK_SHORT\t\t8\n#define TCL_LINK_USHORT\t\t9\n#define TCL_LINK_UINT\t\t10\n#define TCL_LINK_LONG\t\t11\n#define TCL_LINK_ULONG\t\t12\n#define TCL_LINK_FLOAT\t\t13\n#define TCL_LINK_WIDE_UINT\t14\n#define TCL_LINK_READ_ONLY\t0x80\n\f\n/*\n *----------------------------------------------------------------------------\n * Forward declarations of Tcl_HashTable and related types.\n */\n\ntypedef struct Tcl_HashKeyType Tcl_HashKeyType;\ntypedef struct Tcl_HashTable Tcl_HashTable;\ntypedef struct Tcl_HashEntry Tcl_HashEntry;\n\ntypedef unsigned (Tcl_HashKeyProc) (Tcl_HashTable *tablePtr, void *keyPtr);\ntypedef int (Tcl_CompareHashKeysProc) (void *keyPtr, Tcl_HashEntry *hPtr);\ntypedef Tcl_HashEntry * (Tcl_AllocHashEntryProc) (Tcl_HashTable *tablePtr,\n\tvoid *keyPtr);\ntypedef void (Tcl_FreeHashEntryProc) (Tcl_HashEntry *hPtr);\n\n/*\n * This flag controls whether the hash table stores the hash of a key, or\n * recalculates it. There should be no reason for turning this flag off as it\n * is completely binary and source compatible unless you directly access the\n * bucketPtr member of the Tcl_HashTableEntry structure. This member has been\n * removed and the space used to store the hash value.\n */\n\n#ifndef TCL_HASH_KEY_STORE_HASH\n#   define TCL_HASH_KEY_STORE_HASH 1\n#endif\n\n/*\n * Structure definition for an entry in a hash table. No-one outside Tcl\n * should access any of these fields directly; use the macros defined below.\n */\n\nstruct Tcl_HashEntry {\n    Tcl_HashEntry *nextPtr;\t/* Pointer to next entry in this hash bucket,\n\t\t\t\t * or NULL for end of chain. */\n    Tcl_HashTable *tablePtr;\t/* Pointer to table containing entry. */\n#if TCL_HASH_KEY_STORE_HASH\n    void *hash;\t\t\t/* Hash value, stored as pointer to ensure\n\t\t\t\t * that the offsets of the fields in this\n\t\t\t\t * structure are not changed. */\n#else\n    Tcl_HashEntry **bucketPtr;\t/* Pointer to bucket that points to first\n\t\t\t\t * entry in this entry's chain: used for\n\t\t\t\t * deleting the entry. */\n#endif\n    ClientData clientData;\t/* Application stores something here with\n\t\t\t\t * Tcl_SetHashValue. */\n    union {\t\t\t/* Key has one of these forms: */\n\tchar *oneWordValue;\t/* One-word value for key. */\n\tTcl_Obj *objPtr;\t/* Tcl_Obj * key value. */\n\tint words[1];\t\t/* Multiple integer words for key. The actual\n\t\t\t\t * size will be as large as necessary for this\n\t\t\t\t * table's keys. */\n\tchar string[1];\t\t/* String for key. The actual size will be as\n\t\t\t\t * large as needed to hold the key. */\n    } key;\t\t\t/* MUST BE LAST FIELD IN RECORD!! */\n};\n\n/*\n * Flags used in Tcl_HashKeyType.\n *\n * TCL_HASH_KEY_RANDOMIZE_HASH -\n *\t\t\t\tThere are some things, pointers for example\n *\t\t\t\twhich don't hash well because they do not use\n *\t\t\t\tthe lower bits. If this flag is set then the\n *\t\t\t\thash table will attempt to rectify this by\n *\t\t\t\trandomising the bits and then using the upper\n *\t\t\t\tN bits as the index into the table.\n * TCL_HASH_KEY_SYSTEM_HASH -\tIf this flag is set then all memory internally\n *                              allocated for the hash table that is not for an\n *                              entry will use the system heap.\n */\n\n#define TCL_HASH_KEY_RANDOMIZE_HASH 0x1\n#define TCL_HASH_KEY_SYSTEM_HASH    0x2\n\n/*\n * Structure definition for the methods associated with a hash table key type.\n */\n\n#define TCL_HASH_KEY_TYPE_VERSION 1\nstruct Tcl_HashKeyType {\n    int version;\t\t/* Version of the table. If this structure is\n\t\t\t\t * extended in future then the version can be\n\t\t\t\t * used to distinguish between different\n\t\t\t\t * structures. */\n    int flags;\t\t\t/* Flags, see above for details. */\n    Tcl_HashKeyProc *hashKeyProc;\n\t\t\t\t/* Calculates a hash value for the key. If\n\t\t\t\t * this is NULL then the pointer itself is\n\t\t\t\t * used as a hash value. */\n    Tcl_CompareHashKeysProc *compareKeysProc;\n\t\t\t\t/* Compares two keys and returns zero if they\n\t\t\t\t * do not match, and non-zero if they do. If\n\t\t\t\t * this is NULL then the pointers are\n\t\t\t\t * compared. */\n    Tcl_AllocHashEntryProc *allocEntryProc;\n\t\t\t\t/* Called to allocate memory for a new entry,\n\t\t\t\t * i.e. if the key is a string then this could\n\t\t\t\t * allocate a single block which contains\n\t\t\t\t * enough space for both the entry and the\n\t\t\t\t * string. Only the key field of the allocated\n\t\t\t\t * Tcl_HashEntry structure needs to be filled\n\t\t\t\t * in. If something else needs to be done to\n\t\t\t\t * the key, i.e. incrementing a reference\n\t\t\t\t * count then that should be done by this\n\t\t\t\t * function. If this is NULL then Tcl_Alloc is\n\t\t\t\t * used to allocate enough space for a\n\t\t\t\t * Tcl_HashEntry and the key pointer is\n\t\t\t\t * assigned to key.oneWordValue. */\n    Tcl_FreeHashEntryProc *freeEntryProc;\n\t\t\t\t/* Called to free memory associated with an\n\t\t\t\t * entry. If something else needs to be done\n\t\t\t\t * to the key, i.e. decrementing a reference\n\t\t\t\t * count then that should be done by this\n\t\t\t\t * function. If this is NULL then Tcl_Free is\n\t\t\t\t * used to free the Tcl_HashEntry. */\n};\n\n/*\n * Structure definition for a hash table.  Must be in tcl.h so clients can\n * allocate space for these structures, but clients should never access any\n * fields in this structure.\n */\n\n#define TCL_SMALL_HASH_TABLE 4\nstruct Tcl_HashTable {\n    Tcl_HashEntry **buckets;\t/* Pointer to bucket array. Each element\n\t\t\t\t * points to first entry in bucket's hash\n\t\t\t\t * chain, or NULL. */\n    Tcl_HashEntry *staticBuckets[TCL_SMALL_HASH_TABLE];\n\t\t\t\t/* Bucket array used for small tables (to\n\t\t\t\t * avoid mallocs and frees). */\n    int numBuckets;\t\t/* Total number of buckets allocated at\n\t\t\t\t * **bucketPtr. */\n    int numEntries;\t\t/* Total number of entries present in\n\t\t\t\t * table. */\n    int rebuildSize;\t\t/* Enlarge table when numEntries gets to be\n\t\t\t\t * this large. */\n    int downShift;\t\t/* Shift count used in hashing function.\n\t\t\t\t * Designed to use high-order bits of\n\t\t\t\t * randomized keys. */\n    int mask;\t\t\t/* Mask value used in hashing function. */\n    int keyType;\t\t/* Type of keys used in this table. It's\n\t\t\t\t * either TCL_CUSTOM_KEYS, TCL_STRING_KEYS,\n\t\t\t\t * TCL_ONE_WORD_KEYS, or an integer giving the\n\t\t\t\t * number of ints that is the size of the\n\t\t\t\t * key. */\n    Tcl_HashEntry *(*findProc) (Tcl_HashTable *tablePtr, const char *key);\n    Tcl_HashEntry *(*createProc) (Tcl_HashTable *tablePtr, const char *key,\n\t    int *newPtr);\n    const Tcl_HashKeyType *typePtr;\n\t\t\t\t/* Type of the keys used in the\n\t\t\t\t * Tcl_HashTable. */\n};\n\n/*\n * Structure definition for information used to keep track of searches through\n * hash tables:\n */\n\ntypedef struct Tcl_HashSearch {\n    Tcl_HashTable *tablePtr;\t/* Table being searched. */\n    int nextIndex;\t\t/* Index of next bucket to be enumerated after\n\t\t\t\t * present one. */\n    Tcl_HashEntry *nextEntryPtr;/* Next entry to be enumerated in the current\n\t\t\t\t * bucket. */\n} Tcl_HashSearch;\n\n/*\n * Acceptable key types for hash tables:\n *\n * TCL_STRING_KEYS:\t\tThe keys are strings, they are copied into the\n *\t\t\t\tentry.\n * TCL_ONE_WORD_KEYS:\t\tThe keys are pointers, the pointer is stored\n *\t\t\t\tin the entry.\n * TCL_CUSTOM_TYPE_KEYS:\tThe keys are arbitrary types which are copied\n *\t\t\t\tinto the entry.\n * TCL_CUSTOM_PTR_KEYS:\t\tThe keys are pointers to arbitrary types, the\n *\t\t\t\tpointer is stored in the entry.\n *\n * While maintaining binary compatability the above have to be distinct values\n * as they are used to differentiate between old versions of the hash table\n * which don't have a typePtr and new ones which do. Once binary compatability\n * is discarded in favour of making more wide spread changes TCL_STRING_KEYS\n * can be the same as TCL_CUSTOM_TYPE_KEYS, and TCL_ONE_WORD_KEYS can be the\n * same as TCL_CUSTOM_PTR_KEYS because they simply determine how the key is\n * accessed from the entry and not the behaviour.\n */\n\n#define TCL_STRING_KEYS\t\t(0)\n#define TCL_ONE_WORD_KEYS\t(1)\n#define TCL_CUSTOM_TYPE_KEYS\t(-2)\n#define TCL_CUSTOM_PTR_KEYS\t(-1)\n\n/*\n * Structure definition for information used to keep track of searches through\n * dictionaries. These fields should not be accessed by code outside\n * tclDictObj.c\n */\n\ntypedef struct {\n    void *next;\t\t\t/* Search position for underlying hash\n\t\t\t\t * table. */\n    int epoch;\t\t\t/* Epoch marker for dictionary being searched,\n\t\t\t\t * or -1 if search has terminated. */\n    Tcl_Dict dictionaryPtr;\t/* Reference to dictionary being searched. */\n} Tcl_DictSearch;\n\f\n/*\n *----------------------------------------------------------------------------\n * Flag values to pass to Tcl_DoOneEvent to disable searches for some kinds of\n * events:\n */\n\n#define TCL_DONT_WAIT\t\t(1<<1)\n#define TCL_WINDOW_EVENTS\t(1<<2)\n#define TCL_FILE_EVENTS\t\t(1<<3)\n#define TCL_TIMER_EVENTS\t(1<<4)\n#define TCL_IDLE_EVENTS\t\t(1<<5)\t/* WAS 0x10 ???? */\n#define TCL_ALL_EVENTS\t\t(~TCL_DONT_WAIT)\n\n/*\n * The following structure defines a generic event for the Tcl event system.\n * These are the things that are queued in calls to Tcl_QueueEvent and\n * serviced later by Tcl_DoOneEvent. There can be many different kinds of\n * events with different fields, corresponding to window events, timer events,\n * etc. The structure for a particular event consists of a Tcl_Event header\n * followed by additional information specific to that event.\n */\n\nstruct Tcl_Event {\n    Tcl_EventProc *proc;\t/* Function to call to service this event. */\n    struct Tcl_Event *nextPtr;\t/* Next in list of pending events, or NULL. */\n};\n\n/*\n * Positions to pass to Tcl_QueueEvent:\n */\n\ntypedef enum {\n    TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK\n} Tcl_QueuePosition;\n\n/*\n * Values to pass to Tcl_SetServiceMode to specify the behavior of notifier\n * event routines.\n */\n\n#define TCL_SERVICE_NONE 0\n#define TCL_SERVICE_ALL 1\n\n/*\n * The following structure keeps is used to hold a time value, either as an\n * absolute time (the number of seconds from the epoch) or as an elapsed time.\n * On Unix systems the epoch is Midnight Jan 1, 1970 GMT.\n */\n\ntypedef struct Tcl_Time {\n    long sec;\t\t\t/* Seconds. */\n    long usec;\t\t\t/* Microseconds. */\n} Tcl_Time;\n\ntypedef void (Tcl_SetTimerProc) (CONST86 Tcl_Time *timePtr);\ntypedef int (Tcl_WaitForEventProc) (CONST86 Tcl_Time *timePtr);\n\n/*\n * TIP #233 (Virtualized Time)\n */\n\ntypedef void (Tcl_GetTimeProc)   (Tcl_Time *timebuf, ClientData clientData);\ntypedef void (Tcl_ScaleTimeProc) (Tcl_Time *timebuf, ClientData clientData);\n\n/*\n *----------------------------------------------------------------------------\n * Bits to pass to Tcl_CreateFileHandler and Tcl_CreateChannelHandler to\n * indicate what sorts of events are of interest:\n */\n\n#define TCL_READABLE\t\t(1<<1)\n#define TCL_WRITABLE\t\t(1<<2)\n#define TCL_EXCEPTION\t\t(1<<3)\n\n/*\n * Flag values to pass to Tcl_OpenCommandChannel to indicate the disposition\n * of the stdio handles. TCL_STDIN, TCL_STDOUT, TCL_STDERR, are also used in\n * Tcl_GetStdChannel.\n */\n\n#define TCL_STDIN\t\t(1<<1)\n#define TCL_STDOUT\t\t(1<<2)\n#define TCL_STDERR\t\t(1<<3)\n#define TCL_ENFORCE_MODE\t(1<<4)\n\n/*\n * Bits passed to Tcl_DriverClose2Proc to indicate which side of a channel\n * should be closed.\n */\n\n#define TCL_CLOSE_READ\t\t(1<<1)\n#define TCL_CLOSE_WRITE\t\t(1<<2)\n\n/*\n * Value to use as the closeProc for a channel that supports the close2Proc\n * interface.\n */\n\n#define TCL_CLOSE2PROC\t\t((Tcl_DriverCloseProc *) 1)\n\n/*\n * Channel version tag. This was introduced in 8.3.2/8.4.\n */\n\n#define TCL_CHANNEL_VERSION_1\t((Tcl_ChannelTypeVersion) 0x1)\n#define TCL_CHANNEL_VERSION_2\t((Tcl_ChannelTypeVersion) 0x2)\n#define TCL_CHANNEL_VERSION_3\t((Tcl_ChannelTypeVersion) 0x3)\n#define TCL_CHANNEL_VERSION_4\t((Tcl_ChannelTypeVersion) 0x4)\n#define TCL_CHANNEL_VERSION_5\t((Tcl_ChannelTypeVersion) 0x5)\n\n/*\n * TIP #218: Channel Actions, Ids for Tcl_DriverThreadActionProc.\n */\n\n#define TCL_CHANNEL_THREAD_INSERT (0)\n#define TCL_CHANNEL_THREAD_REMOVE (1)\n\n/*\n * Typedefs for the various operations in a channel type:\n */\n\ntypedef int\t(Tcl_DriverBlockModeProc) (ClientData instanceData, int mode);\ntypedef int\t(Tcl_DriverCloseProc) (ClientData instanceData,\n\t\t\tTcl_Interp *interp);\ntypedef int\t(Tcl_DriverClose2Proc) (ClientData instanceData,\n\t\t\tTcl_Interp *interp, int flags);\ntypedef int\t(Tcl_DriverInputProc) (ClientData instanceData, char *buf,\n\t\t\tint toRead, int *errorCodePtr);\ntypedef int\t(Tcl_DriverOutputProc) (ClientData instanceData,\n\t\t\tCONST84 char *buf, int toWrite, int *errorCodePtr);\ntypedef int\t(Tcl_DriverSeekProc) (ClientData instanceData, long offset,\n\t\t\tint mode, int *errorCodePtr);\ntypedef int\t(Tcl_DriverSetOptionProc) (ClientData instanceData,\n\t\t\tTcl_Interp *interp, const char *optionName,\n\t\t\tconst char *value);\ntypedef int\t(Tcl_DriverGetOptionProc) (ClientData instanceData,\n\t\t\tTcl_Interp *interp, CONST84 char *optionName,\n\t\t\tTcl_DString *dsPtr);\ntypedef void\t(Tcl_DriverWatchProc) (ClientData instanceData, int mask);\ntypedef int\t(Tcl_DriverGetHandleProc) (ClientData instanceData,\n\t\t\tint direction, ClientData *handlePtr);\ntypedef int\t(Tcl_DriverFlushProc) (ClientData instanceData);\ntypedef int\t(Tcl_DriverHandlerProc) (ClientData instanceData,\n\t\t\tint interestMask);\ntypedef Tcl_WideInt (Tcl_DriverWideSeekProc) (ClientData instanceData,\n\t\t\tTcl_WideInt offset, int mode, int *errorCodePtr);\n/*\n * TIP #218, Channel Thread Actions\n */\ntypedef void\t(Tcl_DriverThreadActionProc) (ClientData instanceData,\n\t\t\tint action);\n/*\n * TIP #208, File Truncation (etc.)\n */\ntypedef int\t(Tcl_DriverTruncateProc) (ClientData instanceData,\n\t\t\tTcl_WideInt length);\n\n/*\n * struct Tcl_ChannelType:\n *\n * One such structure exists for each type (kind) of channel. It collects\n * together in one place all the functions that are part of the specific\n * channel type.\n *\n * It is recommend that the Tcl_Channel* functions are used to access elements\n * of this structure, instead of direct accessing.\n */\n\ntypedef struct Tcl_ChannelType {\n    const char *typeName;\t/* The name of the channel type in Tcl\n\t\t\t\t * commands. This storage is owned by channel\n\t\t\t\t * type. */\n    Tcl_ChannelTypeVersion version;\n\t\t\t\t/* Version of the channel type. */\n    Tcl_DriverCloseProc *closeProc;\n\t\t\t\t/* Function to call to close the channel, or\n\t\t\t\t * TCL_CLOSE2PROC if the close2Proc should be\n\t\t\t\t * used instead. */\n    Tcl_DriverInputProc *inputProc;\n\t\t\t\t/* Function to call for input on channel. */\n    Tcl_DriverOutputProc *outputProc;\n\t\t\t\t/* Function to call for output on channel. */\n    Tcl_DriverSeekProc *seekProc;\n\t\t\t\t/* Function to call to seek on the channel.\n\t\t\t\t * May be NULL. */\n    Tcl_DriverSetOptionProc *setOptionProc;\n\t\t\t\t/* Set an option on a channel. */\n    Tcl_DriverGetOptionProc *getOptionProc;\n\t\t\t\t/* Get an option from a channel. */\n    Tcl_DriverWatchProc *watchProc;\n\t\t\t\t/* Set up the notifier to watch for events on\n\t\t\t\t * this channel. */\n    Tcl_DriverGetHandleProc *getHandleProc;\n\t\t\t\t/* Get an OS handle from the channel or NULL\n\t\t\t\t * if not supported. */\n    Tcl_DriverClose2Proc *close2Proc;\n\t\t\t\t/* Function to call to close the channel if\n\t\t\t\t * the device supports closing the read &\n\t\t\t\t * write sides independently. */\n    Tcl_DriverBlockModeProc *blockModeProc;\n\t\t\t\t/* Set blocking mode for the raw channel. May\n\t\t\t\t * be NULL. */\n    /*\n     * Only valid in TCL_CHANNEL_VERSION_2 channels or later.\n     */\n    Tcl_DriverFlushProc *flushProc;\n\t\t\t\t/* Function to call to flush a channel. May be\n\t\t\t\t * NULL. */\n    Tcl_DriverHandlerProc *handlerProc;\n\t\t\t\t/* Function to call to handle a channel event.\n\t\t\t\t * This will be passed up the stacked channel\n\t\t\t\t * chain. */\n    /*\n     * Only valid in TCL_CHANNEL_VERSION_3 channels or later.\n     */\n    Tcl_DriverWideSeekProc *wideSeekProc;\n\t\t\t\t/* Function to call to seek on the channel\n\t\t\t\t * which can handle 64-bit offsets. May be\n\t\t\t\t * NULL, and must be NULL if seekProc is\n\t\t\t\t * NULL. */\n    /*\n     * Only valid in TCL_CHANNEL_VERSION_4 channels or later.\n     * TIP #218, Channel Thread Actions.\n     */\n    Tcl_DriverThreadActionProc *threadActionProc;\n\t\t\t\t/* Function to call to notify the driver of\n\t\t\t\t * thread specific activity for a channel. May\n\t\t\t\t * be NULL. */\n    /*\n     * Only valid in TCL_CHANNEL_VERSION_5 channels or later.\n     * TIP #208, File Truncation.\n     */\n    Tcl_DriverTruncateProc *truncateProc;\n\t\t\t\t/* Function to call to truncate the underlying\n\t\t\t\t * file to a particular length. May be NULL if\n\t\t\t\t * the channel does not support truncation. */\n} Tcl_ChannelType;\n\n/*\n * The following flags determine whether the blockModeProc above should set\n * the channel into blocking or nonblocking mode. They are passed as arguments\n * to the blockModeProc function in the above structure.\n */\n\n#define TCL_MODE_BLOCKING\t0\t/* Put channel into blocking mode. */\n#define TCL_MODE_NONBLOCKING\t1\t/* Put channel into nonblocking\n\t\t\t\t\t * mode. */\n\n/*\n *----------------------------------------------------------------------------\n * Enum for different types of file paths.\n */\n\ntypedef enum Tcl_PathType {\n    TCL_PATH_ABSOLUTE,\n    TCL_PATH_RELATIVE,\n    TCL_PATH_VOLUME_RELATIVE\n} Tcl_PathType;\n\n/*\n * The following structure is used to pass glob type data amongst the various\n * glob routines and Tcl_FSMatchInDirectory.\n */\n\ntypedef struct Tcl_GlobTypeData {\n    int type;\t\t\t/* Corresponds to bcdpfls as in 'find -t'. */\n    int perm;\t\t\t/* Corresponds to file permissions. */\n    Tcl_Obj *macType;\t\t/* Acceptable Mac type. */\n    Tcl_Obj *macCreator;\t/* Acceptable Mac creator. */\n} Tcl_GlobTypeData;\n\n/*\n * Type and permission definitions for glob command.\n */\n\n#define TCL_GLOB_TYPE_BLOCK\t\t(1<<0)\n#define TCL_GLOB_TYPE_CHAR\t\t(1<<1)\n#define TCL_GLOB_TYPE_DIR\t\t(1<<2)\n#define TCL_GLOB_TYPE_PIPE\t\t(1<<3)\n#define TCL_GLOB_TYPE_FILE\t\t(1<<4)\n#define TCL_GLOB_TYPE_LINK\t\t(1<<5)\n#define TCL_GLOB_TYPE_SOCK\t\t(1<<6)\n#define TCL_GLOB_TYPE_MOUNT\t\t(1<<7)\n\n#define TCL_GLOB_PERM_RONLY\t\t(1<<0)\n#define TCL_GLOB_PERM_HIDDEN\t\t(1<<1)\n#define TCL_GLOB_PERM_R\t\t\t(1<<2)\n#define TCL_GLOB_PERM_W\t\t\t(1<<3)\n#define TCL_GLOB_PERM_X\t\t\t(1<<4)\n\n/*\n * Flags for the unload callback function.\n */\n\n#define TCL_UNLOAD_DETACH_FROM_INTERPRETER\t(1<<0)\n#define TCL_UNLOAD_DETACH_FROM_PROCESS\t\t(1<<1)\n\n/*\n * Typedefs for the various filesystem operations:\n */\n\ntypedef int (Tcl_FSStatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf);\ntypedef int (Tcl_FSAccessProc) (Tcl_Obj *pathPtr, int mode);\ntypedef Tcl_Channel (Tcl_FSOpenFileChannelProc) (Tcl_Interp *interp,\n\tTcl_Obj *pathPtr, int mode, int permissions);\ntypedef int (Tcl_FSMatchInDirectoryProc) (Tcl_Interp *interp, Tcl_Obj *result,\n\tTcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types);\ntypedef Tcl_Obj * (Tcl_FSGetCwdProc) (Tcl_Interp *interp);\ntypedef int (Tcl_FSChdirProc) (Tcl_Obj *pathPtr);\ntypedef int (Tcl_FSLstatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf);\ntypedef int (Tcl_FSCreateDirectoryProc) (Tcl_Obj *pathPtr);\ntypedef int (Tcl_FSDeleteFileProc) (Tcl_Obj *pathPtr);\ntypedef int (Tcl_FSCopyDirectoryProc) (Tcl_Obj *srcPathPtr,\n\tTcl_Obj *destPathPtr, Tcl_Obj **errorPtr);\ntypedef int (Tcl_FSCopyFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr);\ntypedef int (Tcl_FSRemoveDirectoryProc) (Tcl_Obj *pathPtr, int recursive,\n\tTcl_Obj **errorPtr);\ntypedef int (Tcl_FSRenameFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr);\ntypedef void (Tcl_FSUnloadFileProc) (Tcl_LoadHandle loadHandle);\ntypedef Tcl_Obj * (Tcl_FSListVolumesProc) (void);\n/* We have to declare the utime structure here. */\nstruct utimbuf;\ntypedef int (Tcl_FSUtimeProc) (Tcl_Obj *pathPtr, struct utimbuf *tval);\ntypedef int (Tcl_FSNormalizePathProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr,\n\tint nextCheckpoint);\ntypedef int (Tcl_FSFileAttrsGetProc) (Tcl_Interp *interp, int index,\n\tTcl_Obj *pathPtr, Tcl_Obj **objPtrRef);\ntypedef const char *CONST86 * (Tcl_FSFileAttrStringsProc) (Tcl_Obj *pathPtr,\n\tTcl_Obj **objPtrRef);\ntypedef int (Tcl_FSFileAttrsSetProc) (Tcl_Interp *interp, int index,\n\tTcl_Obj *pathPtr, Tcl_Obj *objPtr);\ntypedef Tcl_Obj * (Tcl_FSLinkProc) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr,\n\tint linkType);\ntypedef int (Tcl_FSLoadFileProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr,\n\tTcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr);\ntypedef int (Tcl_FSPathInFilesystemProc) (Tcl_Obj *pathPtr,\n\tClientData *clientDataPtr);\ntypedef Tcl_Obj * (Tcl_FSFilesystemPathTypeProc) (Tcl_Obj *pathPtr);\ntypedef Tcl_Obj * (Tcl_FSFilesystemSeparatorProc) (Tcl_Obj *pathPtr);\ntypedef void (Tcl_FSFreeInternalRepProc) (ClientData clientData);\ntypedef ClientData (Tcl_FSDupInternalRepProc) (ClientData clientData);\ntypedef Tcl_Obj * (Tcl_FSInternalToNormalizedProc) (ClientData clientData);\ntypedef ClientData (Tcl_FSCreateInternalRepProc) (Tcl_Obj *pathPtr);\n\ntypedef struct Tcl_FSVersion_ *Tcl_FSVersion;\n\n/*\n *----------------------------------------------------------------------------\n * Data structures related to hooking into the filesystem\n */\n\n/*\n * Filesystem version tag.  This was introduced in 8.4.\n */\n\n#define TCL_FILESYSTEM_VERSION_1\t((Tcl_FSVersion) 0x1)\n\n/*\n * struct Tcl_Filesystem:\n *\n * One such structure exists for each type (kind) of filesystem. It collects\n * together in one place all the functions that are part of the specific\n * filesystem. Tcl always accesses the filesystem through one of these\n * structures.\n *\n * Not all entries need be non-NULL; any which are NULL are simply ignored.\n * However, a complete filesystem should provide all of these functions. The\n * explanations in the structure show the importance of each function.\n */\n\ntypedef struct Tcl_Filesystem {\n    const char *typeName;\t/* The name of the filesystem. */\n    int structureLength;\t/* Length of this structure, so future binary\n\t\t\t\t * compatibility can be assured. */\n    Tcl_FSVersion version;\t/* Version of the filesystem type. */\n    Tcl_FSPathInFilesystemProc *pathInFilesystemProc;\n\t\t\t\t/* Function to check whether a path is in this\n\t\t\t\t * filesystem. This is the most important\n\t\t\t\t * filesystem function. */\n    Tcl_FSDupInternalRepProc *dupInternalRepProc;\n\t\t\t\t/* Function to duplicate internal fs rep. May\n\t\t\t\t * be NULL (but then fs is less efficient). */\n    Tcl_FSFreeInternalRepProc *freeInternalRepProc;\n\t\t\t\t/* Function to free internal fs rep. Must be\n\t\t\t\t * implemented if internal representations\n\t\t\t\t * need freeing, otherwise it can be NULL. */\n    Tcl_FSInternalToNormalizedProc *internalToNormalizedProc;\n\t\t\t\t/* Function to convert internal representation\n\t\t\t\t * to a normalized path. Only required if the\n\t\t\t\t * fs creates pure path objects with no\n\t\t\t\t * string/path representation. */\n    Tcl_FSCreateInternalRepProc *createInternalRepProc;\n\t\t\t\t/* Function to create a filesystem-specific\n\t\t\t\t * internal representation. May be NULL if\n\t\t\t\t * paths have no internal representation, or\n\t\t\t\t * if the Tcl_FSPathInFilesystemProc for this\n\t\t\t\t * filesystem always immediately creates an\n\t\t\t\t * internal representation for paths it\n\t\t\t\t * accepts. */\n    Tcl_FSNormalizePathProc *normalizePathProc;\n\t\t\t\t/* Function to normalize a path.  Should be\n\t\t\t\t * implemented for all filesystems which can\n\t\t\t\t * have multiple string representations for\n\t\t\t\t * the same path object. */\n    Tcl_FSFilesystemPathTypeProc *filesystemPathTypeProc;\n\t\t\t\t/* Function to determine the type of a path in\n\t\t\t\t * this filesystem. May be NULL. */\n    Tcl_FSFilesystemSeparatorProc *filesystemSeparatorProc;\n\t\t\t\t/* Function to return the separator\n\t\t\t\t * character(s) for this filesystem. Must be\n\t\t\t\t * implemented. */\n    Tcl_FSStatProc *statProc;\t/* Function to process a 'Tcl_FSStat()' call.\n\t\t\t\t * Must be implemented for any reasonable\n\t\t\t\t * filesystem. */\n    Tcl_FSAccessProc *accessProc;\n\t\t\t\t/* Function to process a 'Tcl_FSAccess()'\n\t\t\t\t * call. Must be implemented for any\n\t\t\t\t * reasonable filesystem. */\n    Tcl_FSOpenFileChannelProc *openFileChannelProc;\n\t\t\t\t/* Function to process a\n\t\t\t\t * 'Tcl_FSOpenFileChannel()' call. Must be\n\t\t\t\t * implemented for any reasonable\n\t\t\t\t * filesystem. */\n    Tcl_FSMatchInDirectoryProc *matchInDirectoryProc;\n\t\t\t\t/* Function to process a\n\t\t\t\t * 'Tcl_FSMatchInDirectory()'.  If not\n\t\t\t\t * implemented, then glob and recursive copy\n\t\t\t\t * functionality will be lacking in the\n\t\t\t\t * filesystem. */\n    Tcl_FSUtimeProc *utimeProc;\t/* Function to process a 'Tcl_FSUtime()' call.\n\t\t\t\t * Required to allow setting (not reading) of\n\t\t\t\t * times with 'file mtime', 'file atime' and\n\t\t\t\t * the open-r/open-w/fcopy implementation of\n\t\t\t\t * 'file copy'. */\n    Tcl_FSLinkProc *linkProc;\t/* Function to process a 'Tcl_FSLink()' call.\n\t\t\t\t * Should be implemented only if the\n\t\t\t\t * filesystem supports links (reading or\n\t\t\t\t * creating). */\n    Tcl_FSListVolumesProc *listVolumesProc;\n\t\t\t\t/* Function to list any filesystem volumes\n\t\t\t\t * added by this filesystem. Should be\n\t\t\t\t * implemented only if the filesystem adds\n\t\t\t\t * volumes at the head of the filesystem. */\n    Tcl_FSFileAttrStringsProc *fileAttrStringsProc;\n\t\t\t\t/* Function to list all attributes strings\n\t\t\t\t * which are valid for this filesystem. If not\n\t\t\t\t * implemented the filesystem will not support\n\t\t\t\t * the 'file attributes' command. This allows\n\t\t\t\t * arbitrary additional information to be\n\t\t\t\t * attached to files in the filesystem. */\n    Tcl_FSFileAttrsGetProc *fileAttrsGetProc;\n\t\t\t\t/* Function to process a\n\t\t\t\t * 'Tcl_FSFileAttrsGet()' call, used by 'file\n\t\t\t\t * attributes'. */\n    Tcl_FSFileAttrsSetProc *fileAttrsSetProc;\n\t\t\t\t/* Function to process a\n\t\t\t\t * 'Tcl_FSFileAttrsSet()' call, used by 'file\n\t\t\t\t * attributes'.  */\n    Tcl_FSCreateDirectoryProc *createDirectoryProc;\n\t\t\t\t/* Function to process a\n\t\t\t\t * 'Tcl_FSCreateDirectory()' call. Should be\n\t\t\t\t * implemented unless the FS is read-only. */\n    Tcl_FSRemoveDirectoryProc *removeDirectoryProc;\n\t\t\t\t/* Function to process a\n\t\t\t\t * 'Tcl_FSRemoveDirectory()' call. Should be\n\t\t\t\t * implemented unless the FS is read-only. */\n    Tcl_FSDeleteFileProc *deleteFileProc;\n\t\t\t\t/* Function to process a 'Tcl_FSDeleteFile()'\n\t\t\t\t * call. Should be implemented unless the FS\n\t\t\t\t * is read-only. */\n    Tcl_FSCopyFileProc *copyFileProc;\n\t\t\t\t/* Function to process a 'Tcl_FSCopyFile()'\n\t\t\t\t * call. If not implemented Tcl will fall back\n\t\t\t\t * on open-r, open-w and fcopy as a copying\n\t\t\t\t * mechanism, for copying actions initiated in\n\t\t\t\t * Tcl (not C). */\n    Tcl_FSRenameFileProc *renameFileProc;\n\t\t\t\t/* Function to process a 'Tcl_FSRenameFile()'\n\t\t\t\t * call. If not implemented, Tcl will fall\n\t\t\t\t * back on a copy and delete mechanism, for\n\t\t\t\t * rename actions initiated in Tcl (not C). */\n    Tcl_FSCopyDirectoryProc *copyDirectoryProc;\n\t\t\t\t/* Function to process a\n\t\t\t\t * 'Tcl_FSCopyDirectory()' call. If not\n\t\t\t\t * implemented, Tcl will fall back on a\n\t\t\t\t * recursive create-dir, file copy mechanism,\n\t\t\t\t * for copying actions initiated in Tcl (not\n\t\t\t\t * C). */\n    Tcl_FSLstatProc *lstatProc;\t/* Function to process a 'Tcl_FSLstat()' call.\n\t\t\t\t * If not implemented, Tcl will attempt to use\n\t\t\t\t * the 'statProc' defined above instead. */\n    Tcl_FSLoadFileProc *loadFileProc;\n\t\t\t\t/* Function to process a 'Tcl_FSLoadFile()'\n\t\t\t\t * call. If not implemented, Tcl will fall\n\t\t\t\t * back on a copy to native-temp followed by a\n\t\t\t\t * Tcl_FSLoadFile on that temporary copy. */\n    Tcl_FSGetCwdProc *getCwdProc;\n\t\t\t\t/* Function to process a 'Tcl_FSGetCwd()'\n\t\t\t\t * call. Most filesystems need not implement\n\t\t\t\t * this. It will usually only be called once,\n\t\t\t\t * if 'getcwd' is called before 'chdir'. May\n\t\t\t\t * be NULL. */\n    Tcl_FSChdirProc *chdirProc;\t/* Function to process a 'Tcl_FSChdir()' call.\n\t\t\t\t * If filesystems do not implement this, it\n\t\t\t\t * will be emulated by a series of directory\n\t\t\t\t * access checks. Otherwise, virtual\n\t\t\t\t * filesystems which do implement it need only\n\t\t\t\t * respond with a positive return result if\n\t\t\t\t * the dirName is a valid directory in their\n\t\t\t\t * filesystem. They need not remember the\n\t\t\t\t * result, since that will be automatically\n\t\t\t\t * remembered for use by GetCwd. Real\n\t\t\t\t * filesystems should carry out the correct\n\t\t\t\t * action (i.e. call the correct system\n\t\t\t\t * 'chdir' api). If not implemented, then 'cd'\n\t\t\t\t * and 'pwd' will fail inside the\n\t\t\t\t * filesystem. */\n} Tcl_Filesystem;\n\n/*\n * The following definitions are used as values for the 'linkAction' flag to\n * Tcl_FSLink, or the linkProc of any filesystem. Any combination of flags can\n * be given. For link creation, the linkProc should create a link which\n * matches any of the types given.\n *\n * TCL_CREATE_SYMBOLIC_LINK -\tCreate a symbolic or soft link.\n * TCL_CREATE_HARD_LINK -\tCreate a hard link.\n */\n\n#define TCL_CREATE_SYMBOLIC_LINK\t0x01\n#define TCL_CREATE_HARD_LINK\t\t0x02\n\n/*\n *----------------------------------------------------------------------------\n * The following structure represents the Notifier functions that you can\n * override with the Tcl_SetNotifier call.\n */\n\ntypedef struct Tcl_NotifierProcs {\n    Tcl_SetTimerProc *setTimerProc;\n    Tcl_WaitForEventProc *waitForEventProc;\n    Tcl_CreateFileHandlerProc *createFileHandlerProc;\n    Tcl_DeleteFileHandlerProc *deleteFileHandlerProc;\n    Tcl_InitNotifierProc *initNotifierProc;\n    Tcl_FinalizeNotifierProc *finalizeNotifierProc;\n    Tcl_AlertNotifierProc *alertNotifierProc;\n    Tcl_ServiceModeHookProc *serviceModeHookProc;\n} Tcl_NotifierProcs;\n\f\n/*\n *----------------------------------------------------------------------------\n * The following data structures and declarations are for the new Tcl parser.\n *\n * For each word of a command, and for each piece of a word such as a variable\n * reference, one of the following structures is created to describe the\n * token.\n */\n\ntypedef struct Tcl_Token {\n    int type;\t\t\t/* Type of token, such as TCL_TOKEN_WORD; see\n\t\t\t\t * below for valid types. */\n    const char *start;\t\t/* First character in token. */\n    int size;\t\t\t/* Number of bytes in token. */\n    int numComponents;\t\t/* If this token is composed of other tokens,\n\t\t\t\t * this field tells how many of them there are\n\t\t\t\t * (including components of components, etc.).\n\t\t\t\t * The component tokens immediately follow\n\t\t\t\t * this one. */\n} Tcl_Token;\n\n/*\n * Type values defined for Tcl_Token structures. These values are defined as\n * mask bits so that it's easy to check for collections of types.\n *\n * TCL_TOKEN_WORD -\t\tThe token describes one word of a command,\n *\t\t\t\tfrom the first non-blank character of the word\n *\t\t\t\t(which may be \" or {) up to but not including\n *\t\t\t\tthe space, semicolon, or bracket that\n *\t\t\t\tterminates the word. NumComponents counts the\n *\t\t\t\ttotal number of sub-tokens that make up the\n *\t\t\t\tword. This includes, for example, sub-tokens\n *\t\t\t\tof TCL_TOKEN_VARIABLE tokens.\n * TCL_TOKEN_SIMPLE_WORD -\tThis token is just like TCL_TOKEN_WORD except\n *\t\t\t\tthat the word is guaranteed to consist of a\n *\t\t\t\tsingle TCL_TOKEN_TEXT sub-token.\n * TCL_TOKEN_TEXT -\t\tThe token describes a range of literal text\n *\t\t\t\tthat is part of a word. NumComponents is\n *\t\t\t\talways 0.\n * TCL_TOKEN_BS -\t\tThe token describes a backslash sequence that\n *\t\t\t\tmust be collapsed. NumComponents is always 0.\n * TCL_TOKEN_COMMAND -\t\tThe token describes a command whose result\n *\t\t\t\tmust be substituted into the word. The token\n *\t\t\t\tincludes the enclosing brackets. NumComponents\n *\t\t\t\tis always 0.\n * TCL_TOKEN_VARIABLE -\t\tThe token describes a variable substitution,\n *\t\t\t\tincluding the dollar sign, variable name, and\n *\t\t\t\tarray index (if there is one) up through the\n *\t\t\t\tright parentheses. NumComponents tells how\n *\t\t\t\tmany additional tokens follow to represent the\n *\t\t\t\tvariable name. The first token will be a\n *\t\t\t\tTCL_TOKEN_TEXT token that describes the\n *\t\t\t\tvariable name. If the variable is an array\n *\t\t\t\treference then there will be one or more\n *\t\t\t\tadditional tokens, of type TCL_TOKEN_TEXT,\n *\t\t\t\tTCL_TOKEN_BS, TCL_TOKEN_COMMAND, and\n *\t\t\t\tTCL_TOKEN_VARIABLE, that describe the array\n *\t\t\t\tindex; numComponents counts the total number\n *\t\t\t\tof nested tokens that make up the variable\n *\t\t\t\treference, including sub-tokens of\n *\t\t\t\tTCL_TOKEN_VARIABLE tokens.\n * TCL_TOKEN_SUB_EXPR -\t\tThe token describes one subexpression of an\n *\t\t\t\texpression, from the first non-blank character\n *\t\t\t\tof the subexpression up to but not including\n *\t\t\t\tthe space, brace, or bracket that terminates\n *\t\t\t\tthe subexpression. NumComponents counts the\n *\t\t\t\ttotal number of following subtokens that make\n *\t\t\t\tup the subexpression; this includes all\n *\t\t\t\tsubtokens for any nested TCL_TOKEN_SUB_EXPR\n *\t\t\t\ttokens. For example, a numeric value used as a\n *\t\t\t\tprimitive operand is described by a\n *\t\t\t\tTCL_TOKEN_SUB_EXPR token followed by a\n *\t\t\t\tTCL_TOKEN_TEXT token. A binary subexpression\n *\t\t\t\tis described by a TCL_TOKEN_SUB_EXPR token\n *\t\t\t\tfollowed by the TCL_TOKEN_OPERATOR token for\n *\t\t\t\tthe operator, then TCL_TOKEN_SUB_EXPR tokens\n *\t\t\t\tfor the left then the right operands.\n * TCL_TOKEN_OPERATOR -\t\tThe token describes one expression operator.\n *\t\t\t\tAn operator might be the name of a math\n *\t\t\t\tfunction such as \"abs\". A TCL_TOKEN_OPERATOR\n *\t\t\t\ttoken is always preceeded by one\n *\t\t\t\tTCL_TOKEN_SUB_EXPR token for the operator's\n *\t\t\t\tsubexpression, and is followed by zero or more\n *\t\t\t\tTCL_TOKEN_SUB_EXPR tokens for the operator's\n *\t\t\t\toperands. NumComponents is always 0.\n * TCL_TOKEN_EXPAND_WORD -\tThis token is just like TCL_TOKEN_WORD except\n *\t\t\t\tthat it marks a word that began with the\n *\t\t\t\tliteral character prefix \"{*}\". This word is\n *\t\t\t\tmarked to be expanded - that is, broken into\n *\t\t\t\twords after substitution is complete.\n */\n\n#define TCL_TOKEN_WORD\t\t1\n#define TCL_TOKEN_SIMPLE_WORD\t2\n#define TCL_TOKEN_TEXT\t\t4\n#define TCL_TOKEN_BS\t\t8\n#define TCL_TOKEN_COMMAND\t16\n#define TCL_TOKEN_VARIABLE\t32\n#define TCL_TOKEN_SUB_EXPR\t64\n#define TCL_TOKEN_OPERATOR\t128\n#define TCL_TOKEN_EXPAND_WORD\t256\n\n/*\n * Parsing error types. On any parsing error, one of these values will be\n * stored in the error field of the Tcl_Parse structure defined below.\n */\n\n#define TCL_PARSE_SUCCESS\t\t0\n#define TCL_PARSE_QUOTE_EXTRA\t\t1\n#define TCL_PARSE_BRACE_EXTRA\t\t2\n#define TCL_PARSE_MISSING_BRACE\t\t3\n#define TCL_PARSE_MISSING_BRACKET\t4\n#define TCL_PARSE_MISSING_PAREN\t\t5\n#define TCL_PARSE_MISSING_QUOTE\t\t6\n#define TCL_PARSE_MISSING_VAR_BRACE\t7\n#define TCL_PARSE_SYNTAX\t\t8\n#define TCL_PARSE_BAD_NUMBER\t\t9\n\n/*\n * A structure of the following type is filled in by Tcl_ParseCommand. It\n * describes a single command parsed from an input string.\n */\n\n#define NUM_STATIC_TOKENS 20\n\ntypedef struct Tcl_Parse {\n    const char *commentStart;\t/* Pointer to # that begins the first of one\n\t\t\t\t * or more comments preceding the command. */\n    int commentSize;\t\t/* Number of bytes in comments (up through\n\t\t\t\t * newline character that terminates the last\n\t\t\t\t * comment). If there were no comments, this\n\t\t\t\t * field is 0. */\n    const char *commandStart;\t/* First character in first word of\n\t\t\t\t * command. */\n    int commandSize;\t\t/* Number of bytes in command, including first\n\t\t\t\t * character of first word, up through the\n\t\t\t\t * terminating newline, close bracket, or\n\t\t\t\t * semicolon. */\n    int numWords;\t\t/* Total number of words in command. May be\n\t\t\t\t * 0. */\n    Tcl_Token *tokenPtr;\t/* Pointer to first token representing the\n\t\t\t\t * words of the command. Initially points to\n\t\t\t\t * staticTokens, but may change to point to\n\t\t\t\t * malloc-ed space if command exceeds space in\n\t\t\t\t * staticTokens. */\n    int numTokens;\t\t/* Total number of tokens in command. */\n    int tokensAvailable;\t/* Total number of tokens available at\n\t\t\t\t * *tokenPtr. */\n    int errorType;\t\t/* One of the parsing error types defined\n\t\t\t\t * above. */\n\n    /*\n     * The fields below are intended only for the private use of the parser.\n     * They should not be used by functions that invoke Tcl_ParseCommand.\n     */\n\n    const char *string;\t\t/* The original command string passed to\n\t\t\t\t * Tcl_ParseCommand. */\n    const char *end;\t\t/* Points to the character just after the last\n\t\t\t\t * one in the command string. */\n    Tcl_Interp *interp;\t\t/* Interpreter to use for error reporting, or\n\t\t\t\t * NULL. */\n    const char *term;\t\t/* Points to character in string that\n\t\t\t\t * terminated most recent token. Filled in by\n\t\t\t\t * ParseTokens. If an error occurs, points to\n\t\t\t\t * beginning of region where the error\n\t\t\t\t * occurred (e.g. the open brace if the close\n\t\t\t\t * brace is missing). */\n    int incomplete;\t\t/* This field is set to 1 by Tcl_ParseCommand\n\t\t\t\t * if the command appears to be incomplete.\n\t\t\t\t * This information is used by\n\t\t\t\t * Tcl_CommandComplete. */\n    Tcl_Token staticTokens[NUM_STATIC_TOKENS];\n\t\t\t\t/* Initial space for tokens for command. This\n\t\t\t\t * space should be large enough to accommodate\n\t\t\t\t * most commands; dynamic space is allocated\n\t\t\t\t * for very large commands that don't fit\n\t\t\t\t * here. */\n} Tcl_Parse;\n\f\n/*\n *----------------------------------------------------------------------------\n * The following structure represents a user-defined encoding. It collects\n * together all the functions that are used by the specific encoding.\n */\n\ntypedef struct Tcl_EncodingType {\n    const char *encodingName;\t/* The name of the encoding, e.g. \"euc-jp\".\n\t\t\t\t * This name is the unique key for this\n\t\t\t\t * encoding type. */\n    Tcl_EncodingConvertProc *toUtfProc;\n\t\t\t\t/* Function to convert from external encoding\n\t\t\t\t * into UTF-8. */\n    Tcl_EncodingConvertProc *fromUtfProc;\n\t\t\t\t/* Function to convert from UTF-8 into\n\t\t\t\t * external encoding. */\n    Tcl_EncodingFreeProc *freeProc;\n\t\t\t\t/* If non-NULL, function to call when this\n\t\t\t\t * encoding is deleted. */\n    ClientData clientData;\t/* Arbitrary value associated with encoding\n\t\t\t\t * type. Passed to conversion functions. */\n    int nullSize;\t\t/* Number of zero bytes that signify\n\t\t\t\t * end-of-string in this encoding. This number\n\t\t\t\t * is used to determine the source string\n\t\t\t\t * length when the srcLen argument is\n\t\t\t\t * negative. Must be 1 or 2. */\n} Tcl_EncodingType;\n\n/*\n * The following definitions are used as values for the conversion control\n * flags argument when converting text from one character set to another:\n *\n * TCL_ENCODING_START -\t\tSignifies that the source buffer is the first\n *\t\t\t\tblock in a (potentially multi-block) input\n *\t\t\t\tstream. Tells the conversion function to reset\n *\t\t\t\tto an initial state and perform any\n *\t\t\t\tinitialization that needs to occur before the\n *\t\t\t\tfirst byte is converted. If the source buffer\n *\t\t\t\tcontains the entire input stream to be\n *\t\t\t\tconverted, this flag should be set.\n * TCL_ENCODING_END -\t\tSignifies that the source buffer is the last\n *\t\t\t\tblock in a (potentially multi-block) input\n *\t\t\t\tstream. Tells the conversion routine to\n *\t\t\t\tperform any finalization that needs to occur\n *\t\t\t\tafter the last byte is converted and then to\n *\t\t\t\treset to an initial state. If the source\n *\t\t\t\tbuffer contains the entire input stream to be\n *\t\t\t\tconverted, this flag should be set.\n * TCL_ENCODING_STOPONERROR -\tIf set, then the converter will return\n *\t\t\t\timmediately upon encountering an invalid byte\n *\t\t\t\tsequence or a source character that has no\n *\t\t\t\tmapping in the target encoding. If clear, then\n *\t\t\t\tthe converter will skip the problem,\n *\t\t\t\tsubstituting one or more \"close\" characters in\n *\t\t\t\tthe destination buffer and then continue to\n *\t\t\t\tconvert the source.\n * TCL_ENCODING_NO_TERMINATE - \tIf set, Tcl_ExternalToUtf will not append a\n *\t\t\t\tterminating NUL byte.  Knowing that it will\n *\t\t\t\tnot need space to do so, it will fill all\n *\t\t\t\tdstLen bytes with encoded UTF-8 content, as\n *\t\t\t\tother circumstances permit.  If clear, the\n *\t\t\t\tdefault behavior is to reserve a byte in\n *\t\t\t\tthe dst space for NUL termination, and to\n *\t\t\t\tappend the NUL byte.\n * TCL_ENCODING_CHAR_LIMIT -\tIf set and dstCharsPtr is not NULL, then\n *\t\t\t\tTcl_ExternalToUtf takes the initial value\n *\t\t\t\tof *dstCharsPtr is taken as a limit of the\n *\t\t\t\tmaximum number of chars to produce in the\n *\t\t\t\tencoded UTF-8 content.  Otherwise, the\n *\t\t\t\tnumber of chars produced is controlled only\n *\t\t\t\tby other limiting factors.\n */\n\n#define TCL_ENCODING_START\t\t0x01\n#define TCL_ENCODING_END\t\t0x02\n#define TCL_ENCODING_STOPONERROR\t0x04\n#define TCL_ENCODING_NO_TERMINATE\t0x08\n#define TCL_ENCODING_CHAR_LIMIT\t\t0x10\n\n/*\n * The following definitions are the error codes returned by the conversion\n * routines:\n *\n * TCL_OK -\t\t\tAll characters were converted.\n * TCL_CONVERT_NOSPACE -\tThe output buffer would not have been large\n *\t\t\t\tenough for all of the converted data; as many\n *\t\t\t\tcharacters as could fit were converted though.\n * TCL_CONVERT_MULTIBYTE -\tThe last few bytes in the source string were\n *\t\t\t\tthe beginning of a multibyte sequence, but\n *\t\t\t\tmore bytes were needed to complete this\n *\t\t\t\tsequence. A subsequent call to the conversion\n *\t\t\t\troutine should pass the beginning of this\n *\t\t\t\tunconverted sequence plus additional bytes\n *\t\t\t\tfrom the source stream to properly convert the\n *\t\t\t\tformerly split-up multibyte sequence.\n * TCL_CONVERT_SYNTAX -\t\tThe source stream contained an invalid\n *\t\t\t\tcharacter sequence. This may occur if the\n *\t\t\t\tinput stream has been damaged or if the input\n *\t\t\t\tencoding method was misidentified. This error\n *\t\t\t\tis reported only if TCL_ENCODING_STOPONERROR\n *\t\t\t\twas specified.\n * TCL_CONVERT_UNKNOWN -\tThe source string contained a character that\n *\t\t\t\tcould not be represented in the target\n *\t\t\t\tencoding. This error is reported only if\n *\t\t\t\tTCL_ENCODING_STOPONERROR was specified.\n */\n\n#define TCL_CONVERT_MULTIBYTE\t(-1)\n#define TCL_CONVERT_SYNTAX\t(-2)\n#define TCL_CONVERT_UNKNOWN\t(-3)\n#define TCL_CONVERT_NOSPACE\t(-4)\n\n/*\n * The maximum number of bytes that are necessary to represent a single\n * Unicode character in UTF-8. The valid values should be 3, 4 or 6\n * (or perhaps 1 if we want to support a non-unicode enabled core). If 3 or\n * 4, then Tcl_UniChar must be 2-bytes in size (UCS-2) (the default). If 6,\n * then Tcl_UniChar must be 4-bytes in size (UCS-4). At this time UCS-2 mode\n * is the default and recommended mode. UCS-4 is experimental and not\n * recommended. It works for the core, but most extensions expect UCS-2.\n */\n\n#ifndef TCL_UTF_MAX\n#define TCL_UTF_MAX\t\t3\n#endif\n\n/*\n * This represents a Unicode character. Any changes to this should also be\n * reflected in regcustom.h.\n */\n\n#if TCL_UTF_MAX > 4\n    /*\n     * unsigned int isn't 100% accurate as it should be a strict 4-byte value\n     * (perhaps wchar_t). 64-bit systems may have troubles. The size of this\n     * value must be reflected correctly in regcustom.h and\n     * in tclEncoding.c.\n     * XXX: Tcl is currently UCS-2 and planning UTF-16 for the Unicode\n     * XXX: string rep that Tcl_UniChar represents.  Changing the size\n     * XXX: of Tcl_UniChar is /not/ supported.\n     */\ntypedef unsigned int Tcl_UniChar;\n#else\ntypedef unsigned short Tcl_UniChar;\n#endif\n\f\n/*\n *----------------------------------------------------------------------------\n * TIP #59: The following structure is used in calls 'Tcl_RegisterConfig' to\n * provide the system with the embedded configuration data.\n */\n\ntypedef struct Tcl_Config {\n    const char *key;\t\t/* Configuration key to register. ASCII\n\t\t\t\t * encoded, thus UTF-8. */\n    const char *value;\t\t/* The value associated with the key. System\n\t\t\t\t * encoding. */\n} Tcl_Config;\n\n/*\n *----------------------------------------------------------------------------\n * Flags for TIP#143 limits, detailing which limits are active in an\n * interpreter. Used for Tcl_{Add,Remove}LimitHandler type argument.\n */\n\n#define TCL_LIMIT_COMMANDS\t0x01\n#define TCL_LIMIT_TIME\t\t0x02\n\n/*\n * Structure containing information about a limit handler to be called when a\n * command- or time-limit is exceeded by an interpreter.\n */\n\ntypedef void (Tcl_LimitHandlerProc) (ClientData clientData, Tcl_Interp *interp);\ntypedef void (Tcl_LimitHandlerDeleteProc) (ClientData clientData);\n\n/*\n *----------------------------------------------------------------------------\n * Override definitions for libtommath.\n */\n\ntypedef struct mp_int mp_int;\n#define MP_INT_DECLARED\ntypedef unsigned int mp_digit;\n#define MP_DIGIT_DECLARED\n\n/*\n *----------------------------------------------------------------------------\n * Definitions needed for Tcl_ParseArgvObj routines.\n * Based on tkArgv.c.\n * Modifications from the original are copyright (c) Sam Bromley 2006\n */\n\ntypedef struct {\n    int type;\t\t\t/* Indicates the option type; see below. */\n    const char *keyStr;\t\t/* The key string that flags the option in the\n\t\t\t\t * argv array. */\n    void *srcPtr;\t\t/* Value to be used in setting dst; usage\n\t\t\t\t * depends on type.*/\n    void *dstPtr;\t\t/* Address of value to be modified; usage\n\t\t\t\t * depends on type.*/\n    const char *helpStr;\t/* Documentation message describing this\n\t\t\t\t * option. */\n    ClientData clientData;\t/* Word to pass to function callbacks. */\n} Tcl_ArgvInfo;\n\n/*\n * Legal values for the type field of a Tcl_ArgInfo: see the user\n * documentation for details.\n */\n\n#define TCL_ARGV_CONSTANT\t15\n#define TCL_ARGV_INT\t\t16\n#define TCL_ARGV_STRING\t\t17\n#define TCL_ARGV_REST\t\t18\n#define TCL_ARGV_FLOAT\t\t19\n#define TCL_ARGV_FUNC\t\t20\n#define TCL_ARGV_GENFUNC\t21\n#define TCL_ARGV_HELP\t\t22\n#define TCL_ARGV_END\t\t23\n\n/*\n * Types of callback functions for the TCL_ARGV_FUNC and TCL_ARGV_GENFUNC\n * argument types:\n */\n\ntypedef int (Tcl_ArgvFuncProc)(ClientData clientData, Tcl_Obj *objPtr,\n\tvoid *dstPtr);\ntypedef int (Tcl_ArgvGenFuncProc)(ClientData clientData, Tcl_Interp *interp,\n\tint objc, Tcl_Obj *const *objv, void *dstPtr);\n\n/*\n * Shorthand for commonly used argTable entries.\n */\n\n#define TCL_ARGV_AUTO_HELP \\\n    {TCL_ARGV_HELP,\t\"-help\",\tNULL,\tNULL, \\\n\t    \"Print summary of command-line options and abort\", NULL}\n#define TCL_ARGV_AUTO_REST \\\n    {TCL_ARGV_REST,\t\"--\",\t\tNULL,\tNULL, \\\n\t    \"Marks the end of the options\", NULL}\n#define TCL_ARGV_TABLE_END \\\n    {TCL_ARGV_END, NULL, NULL, NULL, NULL, NULL}\n\n/*\n *----------------------------------------------------------------------------\n * Definitions needed for Tcl_Zlib routines. [TIP #234]\n *\n * Constants for the format flags describing what sort of data format is\n * desired/expected for the Tcl_ZlibDeflate, Tcl_ZlibInflate and\n * Tcl_ZlibStreamInit functions.\n */\n\n#define TCL_ZLIB_FORMAT_RAW\t1\n#define TCL_ZLIB_FORMAT_ZLIB\t2\n#define TCL_ZLIB_FORMAT_GZIP\t4\n#define TCL_ZLIB_FORMAT_AUTO\t8\n\n/*\n * Constants that describe whether the stream is to operate in compressing or\n * decompressing mode.\n */\n\n#define TCL_ZLIB_STREAM_DEFLATE\t16\n#define TCL_ZLIB_STREAM_INFLATE\t32\n\n/*\n * Constants giving compression levels. Use of TCL_ZLIB_COMPRESS_DEFAULT is\n * recommended.\n */\n\n#define TCL_ZLIB_COMPRESS_NONE\t0\n#define TCL_ZLIB_COMPRESS_FAST\t1\n#define TCL_ZLIB_COMPRESS_BEST\t9\n#define TCL_ZLIB_COMPRESS_DEFAULT (-1)\n\n/*\n * Constants for types of flushing, used with Tcl_ZlibFlush.\n */\n\n#define TCL_ZLIB_NO_FLUSH\t0\n#define TCL_ZLIB_FLUSH\t\t2\n#define TCL_ZLIB_FULLFLUSH\t3\n#define TCL_ZLIB_FINALIZE\t4\n\n/*\n *----------------------------------------------------------------------------\n * Definitions needed for the Tcl_LoadFile function. [TIP #416]\n */\n\n#define TCL_LOAD_GLOBAL 1\n#define TCL_LOAD_LAZY 2\n\n/*\n *----------------------------------------------------------------------------\n * Single public declaration for NRE.\n */\n\ntypedef int (Tcl_NRPostProc) (ClientData data[], Tcl_Interp *interp,\n\t\t\t\tint result);\n\n/*\n *----------------------------------------------------------------------------\n * The following constant is used to test for older versions of Tcl in the\n * stubs tables.\n *\n * Jan Nijtman's plus patch uses 0xFCA1BACF, so we need to pick a different\n * value since the stubs tables don't match.\n */\n\n#define TCL_STUB_MAGIC\t\t((int) 0xFCA3BACF)\n\n/*\n * The following function is required to be defined in all stubs aware\n * extensions. The function is actually implemented in the stub library, not\n * the main Tcl library, although there is a trivial implementation in the\n * main library in case an extension is statically linked into an application.\n */\n\nconst char *\t\tTcl_InitStubs(Tcl_Interp *interp, const char *version,\n\t\t\t    int exact);\nconst char *\t\tTclTomMathInitializeStubs(Tcl_Interp *interp,\n\t\t\t    const char *version, int epoch, int revision);\n\n/*\n * When not using stubs, make it a macro.\n */\n\n#ifndef USE_TCL_STUBS\n#define Tcl_InitStubs(interp, version, exact) \\\n    Tcl_PkgInitStubsCheck(interp, version, exact)\n#endif\n\n/*\n * TODO - tommath stubs export goes here!\n */\n\n/*\n * Public functions that are not accessible via the stubs table.\n * Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171]\n */\n\n#define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \\\n\t    ((Tcl_CreateInterp)()))\nEXTERN void\t\tTcl_MainEx(int argc, char **argv,\n\t\t\t    Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);\nEXTERN const char *\tTcl_PkgInitStubsCheck(Tcl_Interp *interp,\n\t\t\t    const char *version, int exact);\nEXTERN void\t\tTcl_GetMemoryInfo(Tcl_DString *dsPtr);\n\f\n/*\n *----------------------------------------------------------------------------\n * Include the public function declarations that are accessible via the stubs\n * table.\n */\n\n#include \"tclDecls.h\"\n\n/*\n * Include platform specific public function declarations that are accessible\n * via the stubs table. Make all TclOO symbols MODULE_SCOPE (which only\n * has effect on building it as a shared library). See ticket [3010352].\n */\n\n#if defined(BUILD_tcl)\n#   undef TCLAPI\n#   define TCLAPI MODULE_SCOPE\n#endif\n\n#include \"tclPlatDecls.h\"\n\n/*\n *----------------------------------------------------------------------------\n * The following declarations either map ckalloc and ckfree to malloc and\n * free, or they map them to functions with all sorts of debugging hooks\n * defined in tclCkalloc.c.\n */\n\n#ifdef TCL_MEM_DEBUG\n\n#   define ckalloc(x) \\\n    ((void *) Tcl_DbCkalloc((unsigned)(x), __FILE__, __LINE__))\n#   define ckfree(x) \\\n    Tcl_DbCkfree((char *)(x), __FILE__, __LINE__)\n#   define ckrealloc(x,y) \\\n    ((void *) Tcl_DbCkrealloc((char *)(x), (unsigned)(y), __FILE__, __LINE__))\n#   define attemptckalloc(x) \\\n    ((void *) Tcl_AttemptDbCkalloc((unsigned)(x), __FILE__, __LINE__))\n#   define attemptckrealloc(x,y) \\\n    ((void *) Tcl_AttemptDbCkrealloc((char *)(x), (unsigned)(y), __FILE__, __LINE__))\n\n#else /* !TCL_MEM_DEBUG */\n\n/*\n * If we are not using the debugging allocator, we should call the Tcl_Alloc,\n * et al. routines in order to guarantee that every module is using the same\n * memory allocator both inside and outside of the Tcl library.\n */\n\n#   define ckalloc(x) \\\n    ((void *) Tcl_Alloc((unsigned)(x)))\n#   define ckfree(x) \\\n    Tcl_Free((char *)(x))\n#   define ckrealloc(x,y) \\\n    ((void *) Tcl_Realloc((char *)(x), (unsigned)(y)))\n#   define attemptckalloc(x) \\\n    ((void *) Tcl_AttemptAlloc((unsigned)(x)))\n#   define attemptckrealloc(x,y) \\\n    ((void *) Tcl_AttemptRealloc((char *)(x), (unsigned)(y)))\n#   undef  Tcl_InitMemory\n#   define Tcl_InitMemory(x)\n#   undef  Tcl_DumpActiveMemory\n#   define Tcl_DumpActiveMemory(x)\n#   undef  Tcl_ValidateAllMemory\n#   define Tcl_ValidateAllMemory(x,y)\n\n#endif /* !TCL_MEM_DEBUG */\n\n#ifdef TCL_MEM_DEBUG\n#   define Tcl_IncrRefCount(objPtr) \\\n\tTcl_DbIncrRefCount(objPtr, __FILE__, __LINE__)\n#   define Tcl_DecrRefCount(objPtr) \\\n\tTcl_DbDecrRefCount(objPtr, __FILE__, __LINE__)\n#   define Tcl_IsShared(objPtr) \\\n\tTcl_DbIsShared(objPtr, __FILE__, __LINE__)\n#else\n#   define Tcl_IncrRefCount(objPtr) \\\n\t++(objPtr)->refCount\n    /*\n     * Use do/while0 idiom for optimum correctness without compiler warnings.\n     * http://c2.com/cgi/wiki?TrivialDoWhileLoop\n     */\n#   define Tcl_DecrRefCount(objPtr) \\\n\tdo { \\\n\t    Tcl_Obj *_objPtr = (objPtr); \\\n\t    if ((_objPtr)->refCount-- <= 1) { \\\n\t\tTclFreeObj(_objPtr); \\\n\t    } \\\n\t} while(0)\n#   define Tcl_IsShared(objPtr) \\\n\t((objPtr)->refCount > 1)\n#endif\n\n/*\n * Macros and definitions that help to debug the use of Tcl objects. When\n * TCL_MEM_DEBUG is defined, the Tcl_New declarations are overridden to call\n * debugging versions of the object creation functions.\n */\n\n#ifdef TCL_MEM_DEBUG\n#  undef  Tcl_NewBignumObj\n#  define Tcl_NewBignumObj(val) \\\n     Tcl_DbNewBignumObj(val, __FILE__, __LINE__)\n#  undef  Tcl_NewBooleanObj\n#  define Tcl_NewBooleanObj(val) \\\n     Tcl_DbNewBooleanObj(val, __FILE__, __LINE__)\n#  undef  Tcl_NewByteArrayObj\n#  define Tcl_NewByteArrayObj(bytes, len) \\\n     Tcl_DbNewByteArrayObj(bytes, len, __FILE__, __LINE__)\n#  undef  Tcl_NewDoubleObj\n#  define Tcl_NewDoubleObj(val) \\\n     Tcl_DbNewDoubleObj(val, __FILE__, __LINE__)\n#  undef  Tcl_NewIntObj\n#  define Tcl_NewIntObj(val) \\\n     Tcl_DbNewLongObj(val, __FILE__, __LINE__)\n#  undef  Tcl_NewListObj\n#  define Tcl_NewListObj(objc, objv) \\\n     Tcl_DbNewListObj(objc, objv, __FILE__, __LINE__)\n#  undef  Tcl_NewLongObj\n#  define Tcl_NewLongObj(val) \\\n     Tcl_DbNewLongObj(val, __FILE__, __LINE__)\n#  undef  Tcl_NewObj\n#  define Tcl_NewObj() \\\n     Tcl_DbNewObj(__FILE__, __LINE__)\n#  undef  Tcl_NewStringObj\n#  define Tcl_NewStringObj(bytes, len) \\\n     Tcl_DbNewStringObj(bytes, len, __FILE__, __LINE__)\n#  undef  Tcl_NewWideIntObj\n#  define Tcl_NewWideIntObj(val) \\\n     Tcl_DbNewWideIntObj(val, __FILE__, __LINE__)\n#endif /* TCL_MEM_DEBUG */\n\n/*\n *----------------------------------------------------------------------------\n * Macros for clients to use to access fields of hash entries:\n */\n\n#define Tcl_GetHashValue(h) ((h)->clientData)\n#define Tcl_SetHashValue(h, value) ((h)->clientData = (ClientData) (value))\n#define Tcl_GetHashKey(tablePtr, h) \\\n\t((void *) (((tablePtr)->keyType == TCL_ONE_WORD_KEYS || \\\n\t\t    (tablePtr)->keyType == TCL_CUSTOM_PTR_KEYS) \\\n\t\t   ? (h)->key.oneWordValue \\\n\t\t   : (h)->key.string))\n\n/*\n * Macros to use for clients to use to invoke find and create functions for\n * hash tables:\n */\n\n#undef  Tcl_FindHashEntry\n#define Tcl_FindHashEntry(tablePtr, key) \\\n\t(*((tablePtr)->findProc))(tablePtr, (const char *)(key))\n#undef  Tcl_CreateHashEntry\n#define Tcl_CreateHashEntry(tablePtr, key, newPtr) \\\n\t(*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr)\n\n/*\n *----------------------------------------------------------------------------\n * Macros that eliminate the overhead of the thread synchronization functions\n * when compiling without thread support.\n */\n\n#ifndef TCL_THREADS\n#undef  Tcl_MutexLock\n#define Tcl_MutexLock(mutexPtr)\n#undef  Tcl_MutexUnlock\n#define Tcl_MutexUnlock(mutexPtr)\n#undef  Tcl_MutexFinalize\n#define Tcl_MutexFinalize(mutexPtr)\n#undef  Tcl_ConditionNotify\n#define Tcl_ConditionNotify(condPtr)\n#undef  Tcl_ConditionWait\n#define Tcl_ConditionWait(condPtr, mutexPtr, timePtr)\n#undef  Tcl_ConditionFinalize\n#define Tcl_ConditionFinalize(condPtr)\n#endif /* TCL_THREADS */\n\n/*\n *----------------------------------------------------------------------------\n * Deprecated Tcl functions:\n */\n\n#ifndef TCL_NO_DEPRECATED\n/*\n * These function have been renamed. The old names are deprecated, but we\n * define these macros for backwards compatibilty.\n */\n\n#   define Tcl_Ckalloc\t\tTcl_Alloc\n#   define Tcl_Ckfree\t\tTcl_Free\n#   define Tcl_Ckrealloc\tTcl_Realloc\n#   define Tcl_Return\t\tTcl_SetResult\n#   define Tcl_TildeSubst\tTcl_TranslateFileName\n#   define panic\t\tTcl_Panic\n#   define panicVA\t\tTcl_PanicVA\n#endif /* !TCL_NO_DEPRECATED */\n\n/*\n *----------------------------------------------------------------------------\n * Convenience declaration of Tcl_AppInit for backwards compatibility. This\n * function is not *implemented* by the tcl library, so the storage class is\n * neither DLLEXPORT nor DLLIMPORT.\n */\n\nextern Tcl_AppInitProc Tcl_AppInit;\n\n#endif /* RC_INVOKED */\n\n/*\n * end block for C++\n */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _TCL */\n\f\n/*\n * Local Variables:\n * mode: c\n * c-basic-offset: 4\n * fill-column: 78\n * End:\n */\n"
  },
  {
    "path": "src/cocotb/_vendor/tcl/tclDecls.h",
    "content": "/*\n * tclDecls.h --\n *\n *\tDeclarations of functions in the platform independent public Tcl API.\n *\n * Copyright (c) 1998-1999 by Scriptics Corporation.\n *\n * See the file \"license.terms\" for information on usage and redistribution\n * of this file, and for a DISCLAIMER OF ALL WARRANTIES.\n */\n\n#ifndef _TCLDECLS\n#define _TCLDECLS\n\n#undef TCL_STORAGE_CLASS\n#ifdef BUILD_tcl\n#   define TCL_STORAGE_CLASS DLLEXPORT\n#else\n#   ifdef USE_TCL_STUBS\n#      define TCL_STORAGE_CLASS\n#   else\n#      define TCL_STORAGE_CLASS DLLIMPORT\n#   endif\n#endif\n\n/*\n * WARNING: This file is automatically generated by the tools/genStubs.tcl\n * script.  Any modifications to the function declarations below should be made\n * in the generic/tcl.decls script.\n */\n\n/* !BEGIN!: Do not edit below this line. */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n * Exported function declarations:\n */\n\n/* 0 */\nEXTERN int\t\tTcl_PkgProvideEx(Tcl_Interp *interp,\n\t\t\t\tconst char *name, const char *version,\n\t\t\t\tconst void *clientData);\n/* 1 */\nEXTERN CONST84_RETURN char * Tcl_PkgRequireEx(Tcl_Interp *interp,\n\t\t\t\tconst char *name, const char *version,\n\t\t\t\tint exact, void *clientDataPtr);\n/* 2 */\nEXTERN TCL_NORETURN void Tcl_Panic(const char *format, ...) TCL_FORMAT_PRINTF(1, 2);\n/* 3 */\nEXTERN char *\t\tTcl_Alloc(unsigned int size);\n/* 4 */\nEXTERN void\t\tTcl_Free(char *ptr);\n/* 5 */\nEXTERN char *\t\tTcl_Realloc(char *ptr, unsigned int size);\n/* 6 */\nEXTERN char *\t\tTcl_DbCkalloc(unsigned int size, const char *file,\n\t\t\t\tint line);\n/* 7 */\nEXTERN void\t\tTcl_DbCkfree(char *ptr, const char *file, int line);\n/* 8 */\nEXTERN char *\t\tTcl_DbCkrealloc(char *ptr, unsigned int size,\n\t\t\t\tconst char *file, int line);\n#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */\n/* 9 */\nEXTERN void\t\tTcl_CreateFileHandler(int fd, int mask,\n\t\t\t\tTcl_FileProc *proc, ClientData clientData);\n#endif /* UNIX */\n#ifdef MAC_OSX_TCL /* MACOSX */\n/* 9 */\nEXTERN void\t\tTcl_CreateFileHandler(int fd, int mask,\n\t\t\t\tTcl_FileProc *proc, ClientData clientData);\n#endif /* MACOSX */\n#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */\n/* 10 */\nEXTERN void\t\tTcl_DeleteFileHandler(int fd);\n#endif /* UNIX */\n#ifdef MAC_OSX_TCL /* MACOSX */\n/* 10 */\nEXTERN void\t\tTcl_DeleteFileHandler(int fd);\n#endif /* MACOSX */\n/* 11 */\nEXTERN void\t\tTcl_SetTimer(const Tcl_Time *timePtr);\n/* 12 */\nEXTERN void\t\tTcl_Sleep(int ms);\n/* 13 */\nEXTERN int\t\tTcl_WaitForEvent(const Tcl_Time *timePtr);\n/* 14 */\nEXTERN int\t\tTcl_AppendAllObjTypes(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr);\n/* 15 */\nEXTERN void\t\tTcl_AppendStringsToObj(Tcl_Obj *objPtr, ...);\n/* 16 */\nEXTERN void\t\tTcl_AppendToObj(Tcl_Obj *objPtr, const char *bytes,\n\t\t\t\tint length);\n/* 17 */\nEXTERN Tcl_Obj *\tTcl_ConcatObj(int objc, Tcl_Obj *const objv[]);\n/* 18 */\nEXTERN int\t\tTcl_ConvertToType(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, const Tcl_ObjType *typePtr);\n/* 19 */\nEXTERN void\t\tTcl_DbDecrRefCount(Tcl_Obj *objPtr, const char *file,\n\t\t\t\tint line);\n/* 20 */\nEXTERN void\t\tTcl_DbIncrRefCount(Tcl_Obj *objPtr, const char *file,\n\t\t\t\tint line);\n/* 21 */\nEXTERN int\t\tTcl_DbIsShared(Tcl_Obj *objPtr, const char *file,\n\t\t\t\tint line);\n/* 22 */\nEXTERN Tcl_Obj *\tTcl_DbNewBooleanObj(int boolValue, const char *file,\n\t\t\t\tint line);\n/* 23 */\nEXTERN Tcl_Obj *\tTcl_DbNewByteArrayObj(const unsigned char *bytes,\n\t\t\t\tint length, const char *file, int line);\n/* 24 */\nEXTERN Tcl_Obj *\tTcl_DbNewDoubleObj(double doubleValue,\n\t\t\t\tconst char *file, int line);\n/* 25 */\nEXTERN Tcl_Obj *\tTcl_DbNewListObj(int objc, Tcl_Obj *const *objv,\n\t\t\t\tconst char *file, int line);\n/* 26 */\nEXTERN Tcl_Obj *\tTcl_DbNewLongObj(long longValue, const char *file,\n\t\t\t\tint line);\n/* 27 */\nEXTERN Tcl_Obj *\tTcl_DbNewObj(const char *file, int line);\n/* 28 */\nEXTERN Tcl_Obj *\tTcl_DbNewStringObj(const char *bytes, int length,\n\t\t\t\tconst char *file, int line);\n/* 29 */\nEXTERN Tcl_Obj *\tTcl_DuplicateObj(Tcl_Obj *objPtr);\n/* 30 */\nEXTERN void\t\tTclFreeObj(Tcl_Obj *objPtr);\n/* 31 */\nEXTERN int\t\tTcl_GetBoolean(Tcl_Interp *interp, const char *src,\n\t\t\t\tint *boolPtr);\n/* 32 */\nEXTERN int\t\tTcl_GetBooleanFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, int *boolPtr);\n/* 33 */\nEXTERN unsigned char *\tTcl_GetByteArrayFromObj(Tcl_Obj *objPtr,\n\t\t\t\tint *lengthPtr);\n/* 34 */\nEXTERN int\t\tTcl_GetDouble(Tcl_Interp *interp, const char *src,\n\t\t\t\tdouble *doublePtr);\n/* 35 */\nEXTERN int\t\tTcl_GetDoubleFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, double *doublePtr);\n/* 36 */\nEXTERN int\t\tTcl_GetIndexFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr,\n\t\t\t\tCONST84 char *const *tablePtr,\n\t\t\t\tconst char *msg, int flags, int *indexPtr);\n/* 37 */\nEXTERN int\t\tTcl_GetInt(Tcl_Interp *interp, const char *src,\n\t\t\t\tint *intPtr);\n/* 38 */\nEXTERN int\t\tTcl_GetIntFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, int *intPtr);\n/* 39 */\nEXTERN int\t\tTcl_GetLongFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, long *longPtr);\n/* 40 */\nEXTERN CONST86 Tcl_ObjType * Tcl_GetObjType(const char *typeName);\n/* 41 */\nEXTERN char *\t\tTcl_GetStringFromObj(Tcl_Obj *objPtr, int *lengthPtr);\n/* 42 */\nEXTERN void\t\tTcl_InvalidateStringRep(Tcl_Obj *objPtr);\n/* 43 */\nEXTERN int\t\tTcl_ListObjAppendList(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *listPtr, Tcl_Obj *elemListPtr);\n/* 44 */\nEXTERN int\t\tTcl_ListObjAppendElement(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *listPtr, Tcl_Obj *objPtr);\n/* 45 */\nEXTERN int\t\tTcl_ListObjGetElements(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *listPtr, int *objcPtr,\n\t\t\t\tTcl_Obj ***objvPtr);\n/* 46 */\nEXTERN int\t\tTcl_ListObjIndex(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *listPtr, int index,\n\t\t\t\tTcl_Obj **objPtrPtr);\n/* 47 */\nEXTERN int\t\tTcl_ListObjLength(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *listPtr, int *lengthPtr);\n/* 48 */\nEXTERN int\t\tTcl_ListObjReplace(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *listPtr, int first, int count,\n\t\t\t\tint objc, Tcl_Obj *const objv[]);\n/* 49 */\nEXTERN Tcl_Obj *\tTcl_NewBooleanObj(int boolValue);\n/* 50 */\nEXTERN Tcl_Obj *\tTcl_NewByteArrayObj(const unsigned char *bytes,\n\t\t\t\tint length);\n/* 51 */\nEXTERN Tcl_Obj *\tTcl_NewDoubleObj(double doubleValue);\n/* 52 */\nEXTERN Tcl_Obj *\tTcl_NewIntObj(int intValue);\n/* 53 */\nEXTERN Tcl_Obj *\tTcl_NewListObj(int objc, Tcl_Obj *const objv[]);\n/* 54 */\nEXTERN Tcl_Obj *\tTcl_NewLongObj(long longValue);\n/* 55 */\nEXTERN Tcl_Obj *\tTcl_NewObj(void);\n/* 56 */\nEXTERN Tcl_Obj *\tTcl_NewStringObj(const char *bytes, int length);\n/* 57 */\nEXTERN void\t\tTcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue);\n/* 58 */\nEXTERN unsigned char *\tTcl_SetByteArrayLength(Tcl_Obj *objPtr, int length);\n/* 59 */\nEXTERN void\t\tTcl_SetByteArrayObj(Tcl_Obj *objPtr,\n\t\t\t\tconst unsigned char *bytes, int length);\n/* 60 */\nEXTERN void\t\tTcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue);\n/* 61 */\nEXTERN void\t\tTcl_SetIntObj(Tcl_Obj *objPtr, int intValue);\n/* 62 */\nEXTERN void\t\tTcl_SetListObj(Tcl_Obj *objPtr, int objc,\n\t\t\t\tTcl_Obj *const objv[]);\n/* 63 */\nEXTERN void\t\tTcl_SetLongObj(Tcl_Obj *objPtr, long longValue);\n/* 64 */\nEXTERN void\t\tTcl_SetObjLength(Tcl_Obj *objPtr, int length);\n/* 65 */\nEXTERN void\t\tTcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes,\n\t\t\t\tint length);\n/* 66 */\nEXTERN void\t\tTcl_AddErrorInfo(Tcl_Interp *interp,\n\t\t\t\tconst char *message);\n/* 67 */\nEXTERN void\t\tTcl_AddObjErrorInfo(Tcl_Interp *interp,\n\t\t\t\tconst char *message, int length);\n/* 68 */\nEXTERN void\t\tTcl_AllowExceptions(Tcl_Interp *interp);\n/* 69 */\nEXTERN void\t\tTcl_AppendElement(Tcl_Interp *interp,\n\t\t\t\tconst char *element);\n/* 70 */\nEXTERN void\t\tTcl_AppendResult(Tcl_Interp *interp, ...);\n/* 71 */\nEXTERN Tcl_AsyncHandler\t Tcl_AsyncCreate(Tcl_AsyncProc *proc,\n\t\t\t\tClientData clientData);\n/* 72 */\nEXTERN void\t\tTcl_AsyncDelete(Tcl_AsyncHandler async);\n/* 73 */\nEXTERN int\t\tTcl_AsyncInvoke(Tcl_Interp *interp, int code);\n/* 74 */\nEXTERN void\t\tTcl_AsyncMark(Tcl_AsyncHandler async);\n/* 75 */\nEXTERN int\t\tTcl_AsyncReady(void);\n/* 76 */\nEXTERN void\t\tTcl_BackgroundError(Tcl_Interp *interp);\n/* 77 */\nEXTERN char\t\tTcl_Backslash(const char *src, int *readPtr);\n/* 78 */\nEXTERN int\t\tTcl_BadChannelOption(Tcl_Interp *interp,\n\t\t\t\tconst char *optionName,\n\t\t\t\tconst char *optionList);\n/* 79 */\nEXTERN void\t\tTcl_CallWhenDeleted(Tcl_Interp *interp,\n\t\t\t\tTcl_InterpDeleteProc *proc,\n\t\t\t\tClientData clientData);\n/* 80 */\nEXTERN void\t\tTcl_CancelIdleCall(Tcl_IdleProc *idleProc,\n\t\t\t\tClientData clientData);\n/* 81 */\nEXTERN int\t\tTcl_Close(Tcl_Interp *interp, Tcl_Channel chan);\n/* 82 */\nEXTERN int\t\tTcl_CommandComplete(const char *cmd);\n/* 83 */\nEXTERN char *\t\tTcl_Concat(int argc, CONST84 char *const *argv);\n/* 84 */\nEXTERN int\t\tTcl_ConvertElement(const char *src, char *dst,\n\t\t\t\tint flags);\n/* 85 */\nEXTERN int\t\tTcl_ConvertCountedElement(const char *src,\n\t\t\t\tint length, char *dst, int flags);\n/* 86 */\nEXTERN int\t\tTcl_CreateAlias(Tcl_Interp *slave,\n\t\t\t\tconst char *slaveCmd, Tcl_Interp *target,\n\t\t\t\tconst char *targetCmd, int argc,\n\t\t\t\tCONST84 char *const *argv);\n/* 87 */\nEXTERN int\t\tTcl_CreateAliasObj(Tcl_Interp *slave,\n\t\t\t\tconst char *slaveCmd, Tcl_Interp *target,\n\t\t\t\tconst char *targetCmd, int objc,\n\t\t\t\tTcl_Obj *const objv[]);\n/* 88 */\nEXTERN Tcl_Channel\tTcl_CreateChannel(const Tcl_ChannelType *typePtr,\n\t\t\t\tconst char *chanName,\n\t\t\t\tClientData instanceData, int mask);\n/* 89 */\nEXTERN void\t\tTcl_CreateChannelHandler(Tcl_Channel chan, int mask,\n\t\t\t\tTcl_ChannelProc *proc, ClientData clientData);\n/* 90 */\nEXTERN void\t\tTcl_CreateCloseHandler(Tcl_Channel chan,\n\t\t\t\tTcl_CloseProc *proc, ClientData clientData);\n/* 91 */\nEXTERN Tcl_Command\tTcl_CreateCommand(Tcl_Interp *interp,\n\t\t\t\tconst char *cmdName, Tcl_CmdProc *proc,\n\t\t\t\tClientData clientData,\n\t\t\t\tTcl_CmdDeleteProc *deleteProc);\n/* 92 */\nEXTERN void\t\tTcl_CreateEventSource(Tcl_EventSetupProc *setupProc,\n\t\t\t\tTcl_EventCheckProc *checkProc,\n\t\t\t\tClientData clientData);\n/* 93 */\nEXTERN void\t\tTcl_CreateExitHandler(Tcl_ExitProc *proc,\n\t\t\t\tClientData clientData);\n/* 94 */\nEXTERN Tcl_Interp *\tTcl_CreateInterp(void);\n/* 95 */\nEXTERN void\t\tTcl_CreateMathFunc(Tcl_Interp *interp,\n\t\t\t\tconst char *name, int numArgs,\n\t\t\t\tTcl_ValueType *argTypes, Tcl_MathProc *proc,\n\t\t\t\tClientData clientData);\n/* 96 */\nEXTERN Tcl_Command\tTcl_CreateObjCommand(Tcl_Interp *interp,\n\t\t\t\tconst char *cmdName, Tcl_ObjCmdProc *proc,\n\t\t\t\tClientData clientData,\n\t\t\t\tTcl_CmdDeleteProc *deleteProc);\n/* 97 */\nEXTERN Tcl_Interp *\tTcl_CreateSlave(Tcl_Interp *interp,\n\t\t\t\tconst char *slaveName, int isSafe);\n/* 98 */\nEXTERN Tcl_TimerToken\tTcl_CreateTimerHandler(int milliseconds,\n\t\t\t\tTcl_TimerProc *proc, ClientData clientData);\n/* 99 */\nEXTERN Tcl_Trace\tTcl_CreateTrace(Tcl_Interp *interp, int level,\n\t\t\t\tTcl_CmdTraceProc *proc,\n\t\t\t\tClientData clientData);\n/* 100 */\nEXTERN void\t\tTcl_DeleteAssocData(Tcl_Interp *interp,\n\t\t\t\tconst char *name);\n/* 101 */\nEXTERN void\t\tTcl_DeleteChannelHandler(Tcl_Channel chan,\n\t\t\t\tTcl_ChannelProc *proc, ClientData clientData);\n/* 102 */\nEXTERN void\t\tTcl_DeleteCloseHandler(Tcl_Channel chan,\n\t\t\t\tTcl_CloseProc *proc, ClientData clientData);\n/* 103 */\nEXTERN int\t\tTcl_DeleteCommand(Tcl_Interp *interp,\n\t\t\t\tconst char *cmdName);\n/* 104 */\nEXTERN int\t\tTcl_DeleteCommandFromToken(Tcl_Interp *interp,\n\t\t\t\tTcl_Command command);\n/* 105 */\nEXTERN void\t\tTcl_DeleteEvents(Tcl_EventDeleteProc *proc,\n\t\t\t\tClientData clientData);\n/* 106 */\nEXTERN void\t\tTcl_DeleteEventSource(Tcl_EventSetupProc *setupProc,\n\t\t\t\tTcl_EventCheckProc *checkProc,\n\t\t\t\tClientData clientData);\n/* 107 */\nEXTERN void\t\tTcl_DeleteExitHandler(Tcl_ExitProc *proc,\n\t\t\t\tClientData clientData);\n/* 108 */\nEXTERN void\t\tTcl_DeleteHashEntry(Tcl_HashEntry *entryPtr);\n/* 109 */\nEXTERN void\t\tTcl_DeleteHashTable(Tcl_HashTable *tablePtr);\n/* 110 */\nEXTERN void\t\tTcl_DeleteInterp(Tcl_Interp *interp);\n/* 111 */\nEXTERN void\t\tTcl_DetachPids(int numPids, Tcl_Pid *pidPtr);\n/* 112 */\nEXTERN void\t\tTcl_DeleteTimerHandler(Tcl_TimerToken token);\n/* 113 */\nEXTERN void\t\tTcl_DeleteTrace(Tcl_Interp *interp, Tcl_Trace trace);\n/* 114 */\nEXTERN void\t\tTcl_DontCallWhenDeleted(Tcl_Interp *interp,\n\t\t\t\tTcl_InterpDeleteProc *proc,\n\t\t\t\tClientData clientData);\n/* 115 */\nEXTERN int\t\tTcl_DoOneEvent(int flags);\n/* 116 */\nEXTERN void\t\tTcl_DoWhenIdle(Tcl_IdleProc *proc,\n\t\t\t\tClientData clientData);\n/* 117 */\nEXTERN char *\t\tTcl_DStringAppend(Tcl_DString *dsPtr,\n\t\t\t\tconst char *bytes, int length);\n/* 118 */\nEXTERN char *\t\tTcl_DStringAppendElement(Tcl_DString *dsPtr,\n\t\t\t\tconst char *element);\n/* 119 */\nEXTERN void\t\tTcl_DStringEndSublist(Tcl_DString *dsPtr);\n/* 120 */\nEXTERN void\t\tTcl_DStringFree(Tcl_DString *dsPtr);\n/* 121 */\nEXTERN void\t\tTcl_DStringGetResult(Tcl_Interp *interp,\n\t\t\t\tTcl_DString *dsPtr);\n/* 122 */\nEXTERN void\t\tTcl_DStringInit(Tcl_DString *dsPtr);\n/* 123 */\nEXTERN void\t\tTcl_DStringResult(Tcl_Interp *interp,\n\t\t\t\tTcl_DString *dsPtr);\n/* 124 */\nEXTERN void\t\tTcl_DStringSetLength(Tcl_DString *dsPtr, int length);\n/* 125 */\nEXTERN void\t\tTcl_DStringStartSublist(Tcl_DString *dsPtr);\n/* 126 */\nEXTERN int\t\tTcl_Eof(Tcl_Channel chan);\n/* 127 */\nEXTERN CONST84_RETURN char * Tcl_ErrnoId(void);\n/* 128 */\nEXTERN CONST84_RETURN char * Tcl_ErrnoMsg(int err);\n/* 129 */\nEXTERN int\t\tTcl_Eval(Tcl_Interp *interp, const char *script);\n/* 130 */\nEXTERN int\t\tTcl_EvalFile(Tcl_Interp *interp,\n\t\t\t\tconst char *fileName);\n/* 131 */\nEXTERN int\t\tTcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr);\n/* 132 */\nEXTERN void\t\tTcl_EventuallyFree(ClientData clientData,\n\t\t\t\tTcl_FreeProc *freeProc);\n/* 133 */\nEXTERN TCL_NORETURN void Tcl_Exit(int status);\n/* 134 */\nEXTERN int\t\tTcl_ExposeCommand(Tcl_Interp *interp,\n\t\t\t\tconst char *hiddenCmdToken,\n\t\t\t\tconst char *cmdName);\n/* 135 */\nEXTERN int\t\tTcl_ExprBoolean(Tcl_Interp *interp, const char *expr,\n\t\t\t\tint *ptr);\n/* 136 */\nEXTERN int\t\tTcl_ExprBooleanObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, int *ptr);\n/* 137 */\nEXTERN int\t\tTcl_ExprDouble(Tcl_Interp *interp, const char *expr,\n\t\t\t\tdouble *ptr);\n/* 138 */\nEXTERN int\t\tTcl_ExprDoubleObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, double *ptr);\n/* 139 */\nEXTERN int\t\tTcl_ExprLong(Tcl_Interp *interp, const char *expr,\n\t\t\t\tlong *ptr);\n/* 140 */\nEXTERN int\t\tTcl_ExprLongObj(Tcl_Interp *interp, Tcl_Obj *objPtr,\n\t\t\t\tlong *ptr);\n/* 141 */\nEXTERN int\t\tTcl_ExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr,\n\t\t\t\tTcl_Obj **resultPtrPtr);\n/* 142 */\nEXTERN int\t\tTcl_ExprString(Tcl_Interp *interp, const char *expr);\n/* 143 */\nEXTERN void\t\tTcl_Finalize(void);\n/* 144 */\nEXTERN void\t\tTcl_FindExecutable(const char *argv0);\n/* 145 */\nEXTERN Tcl_HashEntry *\tTcl_FirstHashEntry(Tcl_HashTable *tablePtr,\n\t\t\t\tTcl_HashSearch *searchPtr);\n/* 146 */\nEXTERN int\t\tTcl_Flush(Tcl_Channel chan);\n/* 147 */\nEXTERN void\t\tTcl_FreeResult(Tcl_Interp *interp);\n/* 148 */\nEXTERN int\t\tTcl_GetAlias(Tcl_Interp *interp,\n\t\t\t\tconst char *slaveCmd,\n\t\t\t\tTcl_Interp **targetInterpPtr,\n\t\t\t\tCONST84 char **targetCmdPtr, int *argcPtr,\n\t\t\t\tCONST84 char ***argvPtr);\n/* 149 */\nEXTERN int\t\tTcl_GetAliasObj(Tcl_Interp *interp,\n\t\t\t\tconst char *slaveCmd,\n\t\t\t\tTcl_Interp **targetInterpPtr,\n\t\t\t\tCONST84 char **targetCmdPtr, int *objcPtr,\n\t\t\t\tTcl_Obj ***objv);\n/* 150 */\nEXTERN ClientData\tTcl_GetAssocData(Tcl_Interp *interp,\n\t\t\t\tconst char *name,\n\t\t\t\tTcl_InterpDeleteProc **procPtr);\n/* 151 */\nEXTERN Tcl_Channel\tTcl_GetChannel(Tcl_Interp *interp,\n\t\t\t\tconst char *chanName, int *modePtr);\n/* 152 */\nEXTERN int\t\tTcl_GetChannelBufferSize(Tcl_Channel chan);\n/* 153 */\nEXTERN int\t\tTcl_GetChannelHandle(Tcl_Channel chan, int direction,\n\t\t\t\tClientData *handlePtr);\n/* 154 */\nEXTERN ClientData\tTcl_GetChannelInstanceData(Tcl_Channel chan);\n/* 155 */\nEXTERN int\t\tTcl_GetChannelMode(Tcl_Channel chan);\n/* 156 */\nEXTERN CONST84_RETURN char * Tcl_GetChannelName(Tcl_Channel chan);\n/* 157 */\nEXTERN int\t\tTcl_GetChannelOption(Tcl_Interp *interp,\n\t\t\t\tTcl_Channel chan, const char *optionName,\n\t\t\t\tTcl_DString *dsPtr);\n/* 158 */\nEXTERN CONST86 Tcl_ChannelType * Tcl_GetChannelType(Tcl_Channel chan);\n/* 159 */\nEXTERN int\t\tTcl_GetCommandInfo(Tcl_Interp *interp,\n\t\t\t\tconst char *cmdName, Tcl_CmdInfo *infoPtr);\n/* 160 */\nEXTERN CONST84_RETURN char * Tcl_GetCommandName(Tcl_Interp *interp,\n\t\t\t\tTcl_Command command);\n/* 161 */\nEXTERN int\t\tTcl_GetErrno(void);\n/* 162 */\nEXTERN CONST84_RETURN char * Tcl_GetHostName(void);\n/* 163 */\nEXTERN int\t\tTcl_GetInterpPath(Tcl_Interp *askInterp,\n\t\t\t\tTcl_Interp *slaveInterp);\n/* 164 */\nEXTERN Tcl_Interp *\tTcl_GetMaster(Tcl_Interp *interp);\n/* 165 */\nEXTERN const char *\tTcl_GetNameOfExecutable(void);\n/* 166 */\nEXTERN Tcl_Obj *\tTcl_GetObjResult(Tcl_Interp *interp);\n#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */\n/* 167 */\nEXTERN int\t\tTcl_GetOpenFile(Tcl_Interp *interp,\n\t\t\t\tconst char *chanID, int forWriting,\n\t\t\t\tint checkUsage, ClientData *filePtr);\n#endif /* UNIX */\n#ifdef MAC_OSX_TCL /* MACOSX */\n/* 167 */\nEXTERN int\t\tTcl_GetOpenFile(Tcl_Interp *interp,\n\t\t\t\tconst char *chanID, int forWriting,\n\t\t\t\tint checkUsage, ClientData *filePtr);\n#endif /* MACOSX */\n/* 168 */\nEXTERN Tcl_PathType\tTcl_GetPathType(const char *path);\n/* 169 */\nEXTERN int\t\tTcl_Gets(Tcl_Channel chan, Tcl_DString *dsPtr);\n/* 170 */\nEXTERN int\t\tTcl_GetsObj(Tcl_Channel chan, Tcl_Obj *objPtr);\n/* 171 */\nEXTERN int\t\tTcl_GetServiceMode(void);\n/* 172 */\nEXTERN Tcl_Interp *\tTcl_GetSlave(Tcl_Interp *interp,\n\t\t\t\tconst char *slaveName);\n/* 173 */\nEXTERN Tcl_Channel\tTcl_GetStdChannel(int type);\n/* 174 */\nEXTERN CONST84_RETURN char * Tcl_GetStringResult(Tcl_Interp *interp);\n/* 175 */\nEXTERN CONST84_RETURN char * Tcl_GetVar(Tcl_Interp *interp,\n\t\t\t\tconst char *varName, int flags);\n/* 176 */\nEXTERN CONST84_RETURN char * Tcl_GetVar2(Tcl_Interp *interp,\n\t\t\t\tconst char *part1, const char *part2,\n\t\t\t\tint flags);\n/* 177 */\nEXTERN int\t\tTcl_GlobalEval(Tcl_Interp *interp,\n\t\t\t\tconst char *command);\n/* 178 */\nEXTERN int\t\tTcl_GlobalEvalObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr);\n/* 179 */\nEXTERN int\t\tTcl_HideCommand(Tcl_Interp *interp,\n\t\t\t\tconst char *cmdName,\n\t\t\t\tconst char *hiddenCmdToken);\n/* 180 */\nEXTERN int\t\tTcl_Init(Tcl_Interp *interp);\n/* 181 */\nEXTERN void\t\tTcl_InitHashTable(Tcl_HashTable *tablePtr,\n\t\t\t\tint keyType);\n/* 182 */\nEXTERN int\t\tTcl_InputBlocked(Tcl_Channel chan);\n/* 183 */\nEXTERN int\t\tTcl_InputBuffered(Tcl_Channel chan);\n/* 184 */\nEXTERN int\t\tTcl_InterpDeleted(Tcl_Interp *interp);\n/* 185 */\nEXTERN int\t\tTcl_IsSafe(Tcl_Interp *interp);\n/* 186 */\nEXTERN char *\t\tTcl_JoinPath(int argc, CONST84 char *const *argv,\n\t\t\t\tTcl_DString *resultPtr);\n/* 187 */\nEXTERN int\t\tTcl_LinkVar(Tcl_Interp *interp, const char *varName,\n\t\t\t\tchar *addr, int type);\n/* Slot 188 is reserved */\n/* 189 */\nEXTERN Tcl_Channel\tTcl_MakeFileChannel(ClientData handle, int mode);\n/* 190 */\nEXTERN int\t\tTcl_MakeSafe(Tcl_Interp *interp);\n/* 191 */\nEXTERN Tcl_Channel\tTcl_MakeTcpClientChannel(ClientData tcpSocket);\n/* 192 */\nEXTERN char *\t\tTcl_Merge(int argc, CONST84 char *const *argv);\n/* 193 */\nEXTERN Tcl_HashEntry *\tTcl_NextHashEntry(Tcl_HashSearch *searchPtr);\n/* 194 */\nEXTERN void\t\tTcl_NotifyChannel(Tcl_Channel channel, int mask);\n/* 195 */\nEXTERN Tcl_Obj *\tTcl_ObjGetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr,\n\t\t\t\tTcl_Obj *part2Ptr, int flags);\n/* 196 */\nEXTERN Tcl_Obj *\tTcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr,\n\t\t\t\tTcl_Obj *part2Ptr, Tcl_Obj *newValuePtr,\n\t\t\t\tint flags);\n/* 197 */\nEXTERN Tcl_Channel\tTcl_OpenCommandChannel(Tcl_Interp *interp, int argc,\n\t\t\t\tCONST84 char **argv, int flags);\n/* 198 */\nEXTERN Tcl_Channel\tTcl_OpenFileChannel(Tcl_Interp *interp,\n\t\t\t\tconst char *fileName, const char *modeString,\n\t\t\t\tint permissions);\n/* 199 */\nEXTERN Tcl_Channel\tTcl_OpenTcpClient(Tcl_Interp *interp, int port,\n\t\t\t\tconst char *address, const char *myaddr,\n\t\t\t\tint myport, int async);\n/* 200 */\nEXTERN Tcl_Channel\tTcl_OpenTcpServer(Tcl_Interp *interp, int port,\n\t\t\t\tconst char *host,\n\t\t\t\tTcl_TcpAcceptProc *acceptProc,\n\t\t\t\tClientData callbackData);\n/* 201 */\nEXTERN void\t\tTcl_Preserve(ClientData data);\n/* 202 */\nEXTERN void\t\tTcl_PrintDouble(Tcl_Interp *interp, double value,\n\t\t\t\tchar *dst);\n/* 203 */\nEXTERN int\t\tTcl_PutEnv(const char *assignment);\n/* 204 */\nEXTERN CONST84_RETURN char * Tcl_PosixError(Tcl_Interp *interp);\n/* 205 */\nEXTERN void\t\tTcl_QueueEvent(Tcl_Event *evPtr,\n\t\t\t\tTcl_QueuePosition position);\n/* 206 */\nEXTERN int\t\tTcl_Read(Tcl_Channel chan, char *bufPtr, int toRead);\n/* 207 */\nEXTERN void\t\tTcl_ReapDetachedProcs(void);\n/* 208 */\nEXTERN int\t\tTcl_RecordAndEval(Tcl_Interp *interp,\n\t\t\t\tconst char *cmd, int flags);\n/* 209 */\nEXTERN int\t\tTcl_RecordAndEvalObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *cmdPtr, int flags);\n/* 210 */\nEXTERN void\t\tTcl_RegisterChannel(Tcl_Interp *interp,\n\t\t\t\tTcl_Channel chan);\n/* 211 */\nEXTERN void\t\tTcl_RegisterObjType(const Tcl_ObjType *typePtr);\n/* 212 */\nEXTERN Tcl_RegExp\tTcl_RegExpCompile(Tcl_Interp *interp,\n\t\t\t\tconst char *pattern);\n/* 213 */\nEXTERN int\t\tTcl_RegExpExec(Tcl_Interp *interp, Tcl_RegExp regexp,\n\t\t\t\tconst char *text, const char *start);\n/* 214 */\nEXTERN int\t\tTcl_RegExpMatch(Tcl_Interp *interp, const char *text,\n\t\t\t\tconst char *pattern);\n/* 215 */\nEXTERN void\t\tTcl_RegExpRange(Tcl_RegExp regexp, int index,\n\t\t\t\tCONST84 char **startPtr,\n\t\t\t\tCONST84 char **endPtr);\n/* 216 */\nEXTERN void\t\tTcl_Release(ClientData clientData);\n/* 217 */\nEXTERN void\t\tTcl_ResetResult(Tcl_Interp *interp);\n/* 218 */\nEXTERN int\t\tTcl_ScanElement(const char *src, int *flagPtr);\n/* 219 */\nEXTERN int\t\tTcl_ScanCountedElement(const char *src, int length,\n\t\t\t\tint *flagPtr);\n/* 220 */\nEXTERN int\t\tTcl_SeekOld(Tcl_Channel chan, int offset, int mode);\n/* 221 */\nEXTERN int\t\tTcl_ServiceAll(void);\n/* 222 */\nEXTERN int\t\tTcl_ServiceEvent(int flags);\n/* 223 */\nEXTERN void\t\tTcl_SetAssocData(Tcl_Interp *interp,\n\t\t\t\tconst char *name, Tcl_InterpDeleteProc *proc,\n\t\t\t\tClientData clientData);\n/* 224 */\nEXTERN void\t\tTcl_SetChannelBufferSize(Tcl_Channel chan, int sz);\n/* 225 */\nEXTERN int\t\tTcl_SetChannelOption(Tcl_Interp *interp,\n\t\t\t\tTcl_Channel chan, const char *optionName,\n\t\t\t\tconst char *newValue);\n/* 226 */\nEXTERN int\t\tTcl_SetCommandInfo(Tcl_Interp *interp,\n\t\t\t\tconst char *cmdName,\n\t\t\t\tconst Tcl_CmdInfo *infoPtr);\n/* 227 */\nEXTERN void\t\tTcl_SetErrno(int err);\n/* 228 */\nEXTERN void\t\tTcl_SetErrorCode(Tcl_Interp *interp, ...);\n/* 229 */\nEXTERN void\t\tTcl_SetMaxBlockTime(const Tcl_Time *timePtr);\n/* 230 */\nEXTERN void\t\tTcl_SetPanicProc(\n\t\t\t\tTCL_NORETURN1 Tcl_PanicProc *panicProc);\n/* 231 */\nEXTERN int\t\tTcl_SetRecursionLimit(Tcl_Interp *interp, int depth);\n/* 232 */\nEXTERN void\t\tTcl_SetResult(Tcl_Interp *interp, char *result,\n\t\t\t\tTcl_FreeProc *freeProc);\n/* 233 */\nEXTERN int\t\tTcl_SetServiceMode(int mode);\n/* 234 */\nEXTERN void\t\tTcl_SetObjErrorCode(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *errorObjPtr);\n/* 235 */\nEXTERN void\t\tTcl_SetObjResult(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *resultObjPtr);\n/* 236 */\nEXTERN void\t\tTcl_SetStdChannel(Tcl_Channel channel, int type);\n/* 237 */\nEXTERN CONST84_RETURN char * Tcl_SetVar(Tcl_Interp *interp,\n\t\t\t\tconst char *varName, const char *newValue,\n\t\t\t\tint flags);\n/* 238 */\nEXTERN CONST84_RETURN char * Tcl_SetVar2(Tcl_Interp *interp,\n\t\t\t\tconst char *part1, const char *part2,\n\t\t\t\tconst char *newValue, int flags);\n/* 239 */\nEXTERN CONST84_RETURN char * Tcl_SignalId(int sig);\n/* 240 */\nEXTERN CONST84_RETURN char * Tcl_SignalMsg(int sig);\n/* 241 */\nEXTERN void\t\tTcl_SourceRCFile(Tcl_Interp *interp);\n/* 242 */\nEXTERN int\t\tTcl_SplitList(Tcl_Interp *interp,\n\t\t\t\tconst char *listStr, int *argcPtr,\n\t\t\t\tCONST84 char ***argvPtr);\n/* 243 */\nEXTERN void\t\tTcl_SplitPath(const char *path, int *argcPtr,\n\t\t\t\tCONST84 char ***argvPtr);\n/* 244 */\nEXTERN void\t\tTcl_StaticPackage(Tcl_Interp *interp,\n\t\t\t\tconst char *pkgName,\n\t\t\t\tTcl_PackageInitProc *initProc,\n\t\t\t\tTcl_PackageInitProc *safeInitProc);\n/* 245 */\nEXTERN int\t\tTcl_StringMatch(const char *str, const char *pattern);\n/* 246 */\nEXTERN int\t\tTcl_TellOld(Tcl_Channel chan);\n/* 247 */\nEXTERN int\t\tTcl_TraceVar(Tcl_Interp *interp, const char *varName,\n\t\t\t\tint flags, Tcl_VarTraceProc *proc,\n\t\t\t\tClientData clientData);\n/* 248 */\nEXTERN int\t\tTcl_TraceVar2(Tcl_Interp *interp, const char *part1,\n\t\t\t\tconst char *part2, int flags,\n\t\t\t\tTcl_VarTraceProc *proc,\n\t\t\t\tClientData clientData);\n/* 249 */\nEXTERN char *\t\tTcl_TranslateFileName(Tcl_Interp *interp,\n\t\t\t\tconst char *name, Tcl_DString *bufferPtr);\n/* 250 */\nEXTERN int\t\tTcl_Ungets(Tcl_Channel chan, const char *str,\n\t\t\t\tint len, int atHead);\n/* 251 */\nEXTERN void\t\tTcl_UnlinkVar(Tcl_Interp *interp,\n\t\t\t\tconst char *varName);\n/* 252 */\nEXTERN int\t\tTcl_UnregisterChannel(Tcl_Interp *interp,\n\t\t\t\tTcl_Channel chan);\n/* 253 */\nEXTERN int\t\tTcl_UnsetVar(Tcl_Interp *interp, const char *varName,\n\t\t\t\tint flags);\n/* 254 */\nEXTERN int\t\tTcl_UnsetVar2(Tcl_Interp *interp, const char *part1,\n\t\t\t\tconst char *part2, int flags);\n/* 255 */\nEXTERN void\t\tTcl_UntraceVar(Tcl_Interp *interp,\n\t\t\t\tconst char *varName, int flags,\n\t\t\t\tTcl_VarTraceProc *proc,\n\t\t\t\tClientData clientData);\n/* 256 */\nEXTERN void\t\tTcl_UntraceVar2(Tcl_Interp *interp,\n\t\t\t\tconst char *part1, const char *part2,\n\t\t\t\tint flags, Tcl_VarTraceProc *proc,\n\t\t\t\tClientData clientData);\n/* 257 */\nEXTERN void\t\tTcl_UpdateLinkedVar(Tcl_Interp *interp,\n\t\t\t\tconst char *varName);\n/* 258 */\nEXTERN int\t\tTcl_UpVar(Tcl_Interp *interp, const char *frameName,\n\t\t\t\tconst char *varName, const char *localName,\n\t\t\t\tint flags);\n/* 259 */\nEXTERN int\t\tTcl_UpVar2(Tcl_Interp *interp, const char *frameName,\n\t\t\t\tconst char *part1, const char *part2,\n\t\t\t\tconst char *localName, int flags);\n/* 260 */\nEXTERN int\t\tTcl_VarEval(Tcl_Interp *interp, ...);\n/* 261 */\nEXTERN ClientData\tTcl_VarTraceInfo(Tcl_Interp *interp,\n\t\t\t\tconst char *varName, int flags,\n\t\t\t\tTcl_VarTraceProc *procPtr,\n\t\t\t\tClientData prevClientData);\n/* 262 */\nEXTERN ClientData\tTcl_VarTraceInfo2(Tcl_Interp *interp,\n\t\t\t\tconst char *part1, const char *part2,\n\t\t\t\tint flags, Tcl_VarTraceProc *procPtr,\n\t\t\t\tClientData prevClientData);\n/* 263 */\nEXTERN int\t\tTcl_Write(Tcl_Channel chan, const char *s, int slen);\n/* 264 */\nEXTERN void\t\tTcl_WrongNumArgs(Tcl_Interp *interp, int objc,\n\t\t\t\tTcl_Obj *const objv[], const char *message);\n/* 265 */\nEXTERN int\t\tTcl_DumpActiveMemory(const char *fileName);\n/* 266 */\nEXTERN void\t\tTcl_ValidateAllMemory(const char *file, int line);\n/* 267 */\nEXTERN void\t\tTcl_AppendResultVA(Tcl_Interp *interp,\n\t\t\t\tva_list argList);\n/* 268 */\nEXTERN void\t\tTcl_AppendStringsToObjVA(Tcl_Obj *objPtr,\n\t\t\t\tva_list argList);\n/* 269 */\nEXTERN char *\t\tTcl_HashStats(Tcl_HashTable *tablePtr);\n/* 270 */\nEXTERN CONST84_RETURN char * Tcl_ParseVar(Tcl_Interp *interp,\n\t\t\t\tconst char *start, CONST84 char **termPtr);\n/* 271 */\nEXTERN CONST84_RETURN char * Tcl_PkgPresent(Tcl_Interp *interp,\n\t\t\t\tconst char *name, const char *version,\n\t\t\t\tint exact);\n/* 272 */\nEXTERN CONST84_RETURN char * Tcl_PkgPresentEx(Tcl_Interp *interp,\n\t\t\t\tconst char *name, const char *version,\n\t\t\t\tint exact, void *clientDataPtr);\n/* 273 */\nEXTERN int\t\tTcl_PkgProvide(Tcl_Interp *interp, const char *name,\n\t\t\t\tconst char *version);\n/* 274 */\nEXTERN CONST84_RETURN char * Tcl_PkgRequire(Tcl_Interp *interp,\n\t\t\t\tconst char *name, const char *version,\n\t\t\t\tint exact);\n/* 275 */\nEXTERN void\t\tTcl_SetErrorCodeVA(Tcl_Interp *interp,\n\t\t\t\tva_list argList);\n/* 276 */\nEXTERN int\t\tTcl_VarEvalVA(Tcl_Interp *interp, va_list argList);\n/* 277 */\nEXTERN Tcl_Pid\t\tTcl_WaitPid(Tcl_Pid pid, int *statPtr, int options);\n/* 278 */\nEXTERN TCL_NORETURN void Tcl_PanicVA(const char *format, va_list argList);\n/* 279 */\nEXTERN void\t\tTcl_GetVersion(int *major, int *minor,\n\t\t\t\tint *patchLevel, int *type);\n/* 280 */\nEXTERN void\t\tTcl_InitMemory(Tcl_Interp *interp);\n/* 281 */\nEXTERN Tcl_Channel\tTcl_StackChannel(Tcl_Interp *interp,\n\t\t\t\tconst Tcl_ChannelType *typePtr,\n\t\t\t\tClientData instanceData, int mask,\n\t\t\t\tTcl_Channel prevChan);\n/* 282 */\nEXTERN int\t\tTcl_UnstackChannel(Tcl_Interp *interp,\n\t\t\t\tTcl_Channel chan);\n/* 283 */\nEXTERN Tcl_Channel\tTcl_GetStackedChannel(Tcl_Channel chan);\n/* 284 */\nEXTERN void\t\tTcl_SetMainLoop(Tcl_MainLoopProc *proc);\n/* Slot 285 is reserved */\n/* 286 */\nEXTERN void\t\tTcl_AppendObjToObj(Tcl_Obj *objPtr,\n\t\t\t\tTcl_Obj *appendObjPtr);\n/* 287 */\nEXTERN Tcl_Encoding\tTcl_CreateEncoding(const Tcl_EncodingType *typePtr);\n/* 288 */\nEXTERN void\t\tTcl_CreateThreadExitHandler(Tcl_ExitProc *proc,\n\t\t\t\tClientData clientData);\n/* 289 */\nEXTERN void\t\tTcl_DeleteThreadExitHandler(Tcl_ExitProc *proc,\n\t\t\t\tClientData clientData);\n/* 290 */\nEXTERN void\t\tTcl_DiscardResult(Tcl_SavedResult *statePtr);\n/* 291 */\nEXTERN int\t\tTcl_EvalEx(Tcl_Interp *interp, const char *script,\n\t\t\t\tint numBytes, int flags);\n/* 292 */\nEXTERN int\t\tTcl_EvalObjv(Tcl_Interp *interp, int objc,\n\t\t\t\tTcl_Obj *const objv[], int flags);\n/* 293 */\nEXTERN int\t\tTcl_EvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr,\n\t\t\t\tint flags);\n/* 294 */\nEXTERN void\t\tTcl_ExitThread(int status);\n/* 295 */\nEXTERN int\t\tTcl_ExternalToUtf(Tcl_Interp *interp,\n\t\t\t\tTcl_Encoding encoding, const char *src,\n\t\t\t\tint srcLen, int flags,\n\t\t\t\tTcl_EncodingState *statePtr, char *dst,\n\t\t\t\tint dstLen, int *srcReadPtr,\n\t\t\t\tint *dstWrotePtr, int *dstCharsPtr);\n/* 296 */\nEXTERN char *\t\tTcl_ExternalToUtfDString(Tcl_Encoding encoding,\n\t\t\t\tconst char *src, int srcLen,\n\t\t\t\tTcl_DString *dsPtr);\n/* 297 */\nEXTERN void\t\tTcl_FinalizeThread(void);\n/* 298 */\nEXTERN void\t\tTcl_FinalizeNotifier(ClientData clientData);\n/* 299 */\nEXTERN void\t\tTcl_FreeEncoding(Tcl_Encoding encoding);\n/* 300 */\nEXTERN Tcl_ThreadId\tTcl_GetCurrentThread(void);\n/* 301 */\nEXTERN Tcl_Encoding\tTcl_GetEncoding(Tcl_Interp *interp, const char *name);\n/* 302 */\nEXTERN CONST84_RETURN char * Tcl_GetEncodingName(Tcl_Encoding encoding);\n/* 303 */\nEXTERN void\t\tTcl_GetEncodingNames(Tcl_Interp *interp);\n/* 304 */\nEXTERN int\t\tTcl_GetIndexFromObjStruct(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, const void *tablePtr,\n\t\t\t\tint offset, const char *msg, int flags,\n\t\t\t\tint *indexPtr);\n/* 305 */\nEXTERN void *\t\tTcl_GetThreadData(Tcl_ThreadDataKey *keyPtr,\n\t\t\t\tint size);\n/* 306 */\nEXTERN Tcl_Obj *\tTcl_GetVar2Ex(Tcl_Interp *interp, const char *part1,\n\t\t\t\tconst char *part2, int flags);\n/* 307 */\nEXTERN ClientData\tTcl_InitNotifier(void);\n/* 308 */\nEXTERN void\t\tTcl_MutexLock(Tcl_Mutex *mutexPtr);\n/* 309 */\nEXTERN void\t\tTcl_MutexUnlock(Tcl_Mutex *mutexPtr);\n/* 310 */\nEXTERN void\t\tTcl_ConditionNotify(Tcl_Condition *condPtr);\n/* 311 */\nEXTERN void\t\tTcl_ConditionWait(Tcl_Condition *condPtr,\n\t\t\t\tTcl_Mutex *mutexPtr, const Tcl_Time *timePtr);\n/* 312 */\nEXTERN int\t\tTcl_NumUtfChars(const char *src, int length);\n/* 313 */\nEXTERN int\t\tTcl_ReadChars(Tcl_Channel channel, Tcl_Obj *objPtr,\n\t\t\t\tint charsToRead, int appendFlag);\n/* 314 */\nEXTERN void\t\tTcl_RestoreResult(Tcl_Interp *interp,\n\t\t\t\tTcl_SavedResult *statePtr);\n/* 315 */\nEXTERN void\t\tTcl_SaveResult(Tcl_Interp *interp,\n\t\t\t\tTcl_SavedResult *statePtr);\n/* 316 */\nEXTERN int\t\tTcl_SetSystemEncoding(Tcl_Interp *interp,\n\t\t\t\tconst char *name);\n/* 317 */\nEXTERN Tcl_Obj *\tTcl_SetVar2Ex(Tcl_Interp *interp, const char *part1,\n\t\t\t\tconst char *part2, Tcl_Obj *newValuePtr,\n\t\t\t\tint flags);\n/* 318 */\nEXTERN void\t\tTcl_ThreadAlert(Tcl_ThreadId threadId);\n/* 319 */\nEXTERN void\t\tTcl_ThreadQueueEvent(Tcl_ThreadId threadId,\n\t\t\t\tTcl_Event *evPtr, Tcl_QueuePosition position);\n/* 320 */\nEXTERN Tcl_UniChar\tTcl_UniCharAtIndex(const char *src, int index);\n/* 321 */\nEXTERN Tcl_UniChar\tTcl_UniCharToLower(int ch);\n/* 322 */\nEXTERN Tcl_UniChar\tTcl_UniCharToTitle(int ch);\n/* 323 */\nEXTERN Tcl_UniChar\tTcl_UniCharToUpper(int ch);\n/* 324 */\nEXTERN int\t\tTcl_UniCharToUtf(int ch, char *buf);\n/* 325 */\nEXTERN CONST84_RETURN char * Tcl_UtfAtIndex(const char *src, int index);\n/* 326 */\nEXTERN int\t\tTcl_UtfCharComplete(const char *src, int length);\n/* 327 */\nEXTERN int\t\tTcl_UtfBackslash(const char *src, int *readPtr,\n\t\t\t\tchar *dst);\n/* 328 */\nEXTERN CONST84_RETURN char * Tcl_UtfFindFirst(const char *src, int ch);\n/* 329 */\nEXTERN CONST84_RETURN char * Tcl_UtfFindLast(const char *src, int ch);\n/* 330 */\nEXTERN CONST84_RETURN char * Tcl_UtfNext(const char *src);\n/* 331 */\nEXTERN CONST84_RETURN char * Tcl_UtfPrev(const char *src, const char *start);\n/* 332 */\nEXTERN int\t\tTcl_UtfToExternal(Tcl_Interp *interp,\n\t\t\t\tTcl_Encoding encoding, const char *src,\n\t\t\t\tint srcLen, int flags,\n\t\t\t\tTcl_EncodingState *statePtr, char *dst,\n\t\t\t\tint dstLen, int *srcReadPtr,\n\t\t\t\tint *dstWrotePtr, int *dstCharsPtr);\n/* 333 */\nEXTERN char *\t\tTcl_UtfToExternalDString(Tcl_Encoding encoding,\n\t\t\t\tconst char *src, int srcLen,\n\t\t\t\tTcl_DString *dsPtr);\n/* 334 */\nEXTERN int\t\tTcl_UtfToLower(char *src);\n/* 335 */\nEXTERN int\t\tTcl_UtfToTitle(char *src);\n/* 336 */\nEXTERN int\t\tTcl_UtfToUniChar(const char *src, Tcl_UniChar *chPtr);\n/* 337 */\nEXTERN int\t\tTcl_UtfToUpper(char *src);\n/* 338 */\nEXTERN int\t\tTcl_WriteChars(Tcl_Channel chan, const char *src,\n\t\t\t\tint srcLen);\n/* 339 */\nEXTERN int\t\tTcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr);\n/* 340 */\nEXTERN char *\t\tTcl_GetString(Tcl_Obj *objPtr);\n/* 341 */\nEXTERN CONST84_RETURN char * Tcl_GetDefaultEncodingDir(void);\n/* 342 */\nEXTERN void\t\tTcl_SetDefaultEncodingDir(const char *path);\n/* 343 */\nEXTERN void\t\tTcl_AlertNotifier(ClientData clientData);\n/* 344 */\nEXTERN void\t\tTcl_ServiceModeHook(int mode);\n/* 345 */\nEXTERN int\t\tTcl_UniCharIsAlnum(int ch);\n/* 346 */\nEXTERN int\t\tTcl_UniCharIsAlpha(int ch);\n/* 347 */\nEXTERN int\t\tTcl_UniCharIsDigit(int ch);\n/* 348 */\nEXTERN int\t\tTcl_UniCharIsLower(int ch);\n/* 349 */\nEXTERN int\t\tTcl_UniCharIsSpace(int ch);\n/* 350 */\nEXTERN int\t\tTcl_UniCharIsUpper(int ch);\n/* 351 */\nEXTERN int\t\tTcl_UniCharIsWordChar(int ch);\n/* 352 */\nEXTERN int\t\tTcl_UniCharLen(const Tcl_UniChar *uniStr);\n/* 353 */\nEXTERN int\t\tTcl_UniCharNcmp(const Tcl_UniChar *ucs,\n\t\t\t\tconst Tcl_UniChar *uct,\n\t\t\t\tunsigned long numChars);\n/* 354 */\nEXTERN char *\t\tTcl_UniCharToUtfDString(const Tcl_UniChar *uniStr,\n\t\t\t\tint uniLength, Tcl_DString *dsPtr);\n/* 355 */\nEXTERN Tcl_UniChar *\tTcl_UtfToUniCharDString(const char *src, int length,\n\t\t\t\tTcl_DString *dsPtr);\n/* 356 */\nEXTERN Tcl_RegExp\tTcl_GetRegExpFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *patObj, int flags);\n/* 357 */\nEXTERN Tcl_Obj *\tTcl_EvalTokens(Tcl_Interp *interp,\n\t\t\t\tTcl_Token *tokenPtr, int count);\n/* 358 */\nEXTERN void\t\tTcl_FreeParse(Tcl_Parse *parsePtr);\n/* 359 */\nEXTERN void\t\tTcl_LogCommandInfo(Tcl_Interp *interp,\n\t\t\t\tconst char *script, const char *command,\n\t\t\t\tint length);\n/* 360 */\nEXTERN int\t\tTcl_ParseBraces(Tcl_Interp *interp,\n\t\t\t\tconst char *start, int numBytes,\n\t\t\t\tTcl_Parse *parsePtr, int append,\n\t\t\t\tCONST84 char **termPtr);\n/* 361 */\nEXTERN int\t\tTcl_ParseCommand(Tcl_Interp *interp,\n\t\t\t\tconst char *start, int numBytes, int nested,\n\t\t\t\tTcl_Parse *parsePtr);\n/* 362 */\nEXTERN int\t\tTcl_ParseExpr(Tcl_Interp *interp, const char *start,\n\t\t\t\tint numBytes, Tcl_Parse *parsePtr);\n/* 363 */\nEXTERN int\t\tTcl_ParseQuotedString(Tcl_Interp *interp,\n\t\t\t\tconst char *start, int numBytes,\n\t\t\t\tTcl_Parse *parsePtr, int append,\n\t\t\t\tCONST84 char **termPtr);\n/* 364 */\nEXTERN int\t\tTcl_ParseVarName(Tcl_Interp *interp,\n\t\t\t\tconst char *start, int numBytes,\n\t\t\t\tTcl_Parse *parsePtr, int append);\n/* 365 */\nEXTERN char *\t\tTcl_GetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr);\n/* 366 */\nEXTERN int\t\tTcl_Chdir(const char *dirName);\n/* 367 */\nEXTERN int\t\tTcl_Access(const char *path, int mode);\n/* 368 */\nEXTERN int\t\tTcl_Stat(const char *path, struct stat *bufPtr);\n/* 369 */\nEXTERN int\t\tTcl_UtfNcmp(const char *s1, const char *s2,\n\t\t\t\tunsigned long n);\n/* 370 */\nEXTERN int\t\tTcl_UtfNcasecmp(const char *s1, const char *s2,\n\t\t\t\tunsigned long n);\n/* 371 */\nEXTERN int\t\tTcl_StringCaseMatch(const char *str,\n\t\t\t\tconst char *pattern, int nocase);\n/* 372 */\nEXTERN int\t\tTcl_UniCharIsControl(int ch);\n/* 373 */\nEXTERN int\t\tTcl_UniCharIsGraph(int ch);\n/* 374 */\nEXTERN int\t\tTcl_UniCharIsPrint(int ch);\n/* 375 */\nEXTERN int\t\tTcl_UniCharIsPunct(int ch);\n/* 376 */\nEXTERN int\t\tTcl_RegExpExecObj(Tcl_Interp *interp,\n\t\t\t\tTcl_RegExp regexp, Tcl_Obj *textObj,\n\t\t\t\tint offset, int nmatches, int flags);\n/* 377 */\nEXTERN void\t\tTcl_RegExpGetInfo(Tcl_RegExp regexp,\n\t\t\t\tTcl_RegExpInfo *infoPtr);\n/* 378 */\nEXTERN Tcl_Obj *\tTcl_NewUnicodeObj(const Tcl_UniChar *unicode,\n\t\t\t\tint numChars);\n/* 379 */\nEXTERN void\t\tTcl_SetUnicodeObj(Tcl_Obj *objPtr,\n\t\t\t\tconst Tcl_UniChar *unicode, int numChars);\n/* 380 */\nEXTERN int\t\tTcl_GetCharLength(Tcl_Obj *objPtr);\n/* 381 */\nEXTERN Tcl_UniChar\tTcl_GetUniChar(Tcl_Obj *objPtr, int index);\n/* 382 */\nEXTERN Tcl_UniChar *\tTcl_GetUnicode(Tcl_Obj *objPtr);\n/* 383 */\nEXTERN Tcl_Obj *\tTcl_GetRange(Tcl_Obj *objPtr, int first, int last);\n/* 384 */\nEXTERN void\t\tTcl_AppendUnicodeToObj(Tcl_Obj *objPtr,\n\t\t\t\tconst Tcl_UniChar *unicode, int length);\n/* 385 */\nEXTERN int\t\tTcl_RegExpMatchObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *textObj, Tcl_Obj *patternObj);\n/* 386 */\nEXTERN void\t\tTcl_SetNotifier(Tcl_NotifierProcs *notifierProcPtr);\n/* 387 */\nEXTERN Tcl_Mutex *\tTcl_GetAllocMutex(void);\n/* 388 */\nEXTERN int\t\tTcl_GetChannelNames(Tcl_Interp *interp);\n/* 389 */\nEXTERN int\t\tTcl_GetChannelNamesEx(Tcl_Interp *interp,\n\t\t\t\tconst char *pattern);\n/* 390 */\nEXTERN int\t\tTcl_ProcObjCmd(ClientData clientData,\n\t\t\t\tTcl_Interp *interp, int objc,\n\t\t\t\tTcl_Obj *const objv[]);\n/* 391 */\nEXTERN void\t\tTcl_ConditionFinalize(Tcl_Condition *condPtr);\n/* 392 */\nEXTERN void\t\tTcl_MutexFinalize(Tcl_Mutex *mutex);\n/* 393 */\nEXTERN int\t\tTcl_CreateThread(Tcl_ThreadId *idPtr,\n\t\t\t\tTcl_ThreadCreateProc *proc,\n\t\t\t\tClientData clientData, int stackSize,\n\t\t\t\tint flags);\n/* 394 */\nEXTERN int\t\tTcl_ReadRaw(Tcl_Channel chan, char *dst,\n\t\t\t\tint bytesToRead);\n/* 395 */\nEXTERN int\t\tTcl_WriteRaw(Tcl_Channel chan, const char *src,\n\t\t\t\tint srcLen);\n/* 396 */\nEXTERN Tcl_Channel\tTcl_GetTopChannel(Tcl_Channel chan);\n/* 397 */\nEXTERN int\t\tTcl_ChannelBuffered(Tcl_Channel chan);\n/* 398 */\nEXTERN CONST84_RETURN char * Tcl_ChannelName(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 399 */\nEXTERN Tcl_ChannelTypeVersion Tcl_ChannelVersion(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 400 */\nEXTERN Tcl_DriverBlockModeProc * Tcl_ChannelBlockModeProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 401 */\nEXTERN Tcl_DriverCloseProc * Tcl_ChannelCloseProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 402 */\nEXTERN Tcl_DriverClose2Proc * Tcl_ChannelClose2Proc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 403 */\nEXTERN Tcl_DriverInputProc * Tcl_ChannelInputProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 404 */\nEXTERN Tcl_DriverOutputProc * Tcl_ChannelOutputProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 405 */\nEXTERN Tcl_DriverSeekProc * Tcl_ChannelSeekProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 406 */\nEXTERN Tcl_DriverSetOptionProc * Tcl_ChannelSetOptionProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 407 */\nEXTERN Tcl_DriverGetOptionProc * Tcl_ChannelGetOptionProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 408 */\nEXTERN Tcl_DriverWatchProc * Tcl_ChannelWatchProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 409 */\nEXTERN Tcl_DriverGetHandleProc * Tcl_ChannelGetHandleProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 410 */\nEXTERN Tcl_DriverFlushProc * Tcl_ChannelFlushProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 411 */\nEXTERN Tcl_DriverHandlerProc * Tcl_ChannelHandlerProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 412 */\nEXTERN int\t\tTcl_JoinThread(Tcl_ThreadId threadId, int *result);\n/* 413 */\nEXTERN int\t\tTcl_IsChannelShared(Tcl_Channel channel);\n/* 414 */\nEXTERN int\t\tTcl_IsChannelRegistered(Tcl_Interp *interp,\n\t\t\t\tTcl_Channel channel);\n/* 415 */\nEXTERN void\t\tTcl_CutChannel(Tcl_Channel channel);\n/* 416 */\nEXTERN void\t\tTcl_SpliceChannel(Tcl_Channel channel);\n/* 417 */\nEXTERN void\t\tTcl_ClearChannelHandlers(Tcl_Channel channel);\n/* 418 */\nEXTERN int\t\tTcl_IsChannelExisting(const char *channelName);\n/* 419 */\nEXTERN int\t\tTcl_UniCharNcasecmp(const Tcl_UniChar *ucs,\n\t\t\t\tconst Tcl_UniChar *uct,\n\t\t\t\tunsigned long numChars);\n/* 420 */\nEXTERN int\t\tTcl_UniCharCaseMatch(const Tcl_UniChar *uniStr,\n\t\t\t\tconst Tcl_UniChar *uniPattern, int nocase);\n/* 421 */\nEXTERN Tcl_HashEntry *\tTcl_FindHashEntry(Tcl_HashTable *tablePtr,\n\t\t\t\tconst void *key);\n/* 422 */\nEXTERN Tcl_HashEntry *\tTcl_CreateHashEntry(Tcl_HashTable *tablePtr,\n\t\t\t\tconst void *key, int *newPtr);\n/* 423 */\nEXTERN void\t\tTcl_InitCustomHashTable(Tcl_HashTable *tablePtr,\n\t\t\t\tint keyType, const Tcl_HashKeyType *typePtr);\n/* 424 */\nEXTERN void\t\tTcl_InitObjHashTable(Tcl_HashTable *tablePtr);\n/* 425 */\nEXTERN ClientData\tTcl_CommandTraceInfo(Tcl_Interp *interp,\n\t\t\t\tconst char *varName, int flags,\n\t\t\t\tTcl_CommandTraceProc *procPtr,\n\t\t\t\tClientData prevClientData);\n/* 426 */\nEXTERN int\t\tTcl_TraceCommand(Tcl_Interp *interp,\n\t\t\t\tconst char *varName, int flags,\n\t\t\t\tTcl_CommandTraceProc *proc,\n\t\t\t\tClientData clientData);\n/* 427 */\nEXTERN void\t\tTcl_UntraceCommand(Tcl_Interp *interp,\n\t\t\t\tconst char *varName, int flags,\n\t\t\t\tTcl_CommandTraceProc *proc,\n\t\t\t\tClientData clientData);\n/* 428 */\nEXTERN char *\t\tTcl_AttemptAlloc(unsigned int size);\n/* 429 */\nEXTERN char *\t\tTcl_AttemptDbCkalloc(unsigned int size,\n\t\t\t\tconst char *file, int line);\n/* 430 */\nEXTERN char *\t\tTcl_AttemptRealloc(char *ptr, unsigned int size);\n/* 431 */\nEXTERN char *\t\tTcl_AttemptDbCkrealloc(char *ptr, unsigned int size,\n\t\t\t\tconst char *file, int line);\n/* 432 */\nEXTERN int\t\tTcl_AttemptSetObjLength(Tcl_Obj *objPtr, int length);\n/* 433 */\nEXTERN Tcl_ThreadId\tTcl_GetChannelThread(Tcl_Channel channel);\n/* 434 */\nEXTERN Tcl_UniChar *\tTcl_GetUnicodeFromObj(Tcl_Obj *objPtr,\n\t\t\t\tint *lengthPtr);\n/* 435 */\nEXTERN int\t\tTcl_GetMathFuncInfo(Tcl_Interp *interp,\n\t\t\t\tconst char *name, int *numArgsPtr,\n\t\t\t\tTcl_ValueType **argTypesPtr,\n\t\t\t\tTcl_MathProc **procPtr,\n\t\t\t\tClientData *clientDataPtr);\n/* 436 */\nEXTERN Tcl_Obj *\tTcl_ListMathFuncs(Tcl_Interp *interp,\n\t\t\t\tconst char *pattern);\n/* 437 */\nEXTERN Tcl_Obj *\tTcl_SubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr,\n\t\t\t\tint flags);\n/* 438 */\nEXTERN int\t\tTcl_DetachChannel(Tcl_Interp *interp,\n\t\t\t\tTcl_Channel channel);\n/* 439 */\nEXTERN int\t\tTcl_IsStandardChannel(Tcl_Channel channel);\n/* 440 */\nEXTERN int\t\tTcl_FSCopyFile(Tcl_Obj *srcPathPtr,\n\t\t\t\tTcl_Obj *destPathPtr);\n/* 441 */\nEXTERN int\t\tTcl_FSCopyDirectory(Tcl_Obj *srcPathPtr,\n\t\t\t\tTcl_Obj *destPathPtr, Tcl_Obj **errorPtr);\n/* 442 */\nEXTERN int\t\tTcl_FSCreateDirectory(Tcl_Obj *pathPtr);\n/* 443 */\nEXTERN int\t\tTcl_FSDeleteFile(Tcl_Obj *pathPtr);\n/* 444 */\nEXTERN int\t\tTcl_FSLoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,\n\t\t\t\tconst char *sym1, const char *sym2,\n\t\t\t\tTcl_PackageInitProc **proc1Ptr,\n\t\t\t\tTcl_PackageInitProc **proc2Ptr,\n\t\t\t\tTcl_LoadHandle *handlePtr,\n\t\t\t\tTcl_FSUnloadFileProc **unloadProcPtr);\n/* 445 */\nEXTERN int\t\tTcl_FSMatchInDirectory(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *result, Tcl_Obj *pathPtr,\n\t\t\t\tconst char *pattern, Tcl_GlobTypeData *types);\n/* 446 */\nEXTERN Tcl_Obj *\tTcl_FSLink(Tcl_Obj *pathPtr, Tcl_Obj *toPtr,\n\t\t\t\tint linkAction);\n/* 447 */\nEXTERN int\t\tTcl_FSRemoveDirectory(Tcl_Obj *pathPtr,\n\t\t\t\tint recursive, Tcl_Obj **errorPtr);\n/* 448 */\nEXTERN int\t\tTcl_FSRenameFile(Tcl_Obj *srcPathPtr,\n\t\t\t\tTcl_Obj *destPathPtr);\n/* 449 */\nEXTERN int\t\tTcl_FSLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf);\n/* 450 */\nEXTERN int\t\tTcl_FSUtime(Tcl_Obj *pathPtr, struct utimbuf *tval);\n/* 451 */\nEXTERN int\t\tTcl_FSFileAttrsGet(Tcl_Interp *interp, int index,\n\t\t\t\tTcl_Obj *pathPtr, Tcl_Obj **objPtrRef);\n/* 452 */\nEXTERN int\t\tTcl_FSFileAttrsSet(Tcl_Interp *interp, int index,\n\t\t\t\tTcl_Obj *pathPtr, Tcl_Obj *objPtr);\n/* 453 */\nEXTERN const char *CONST86 * Tcl_FSFileAttrStrings(Tcl_Obj *pathPtr,\n\t\t\t\tTcl_Obj **objPtrRef);\n/* 454 */\nEXTERN int\t\tTcl_FSStat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf);\n/* 455 */\nEXTERN int\t\tTcl_FSAccess(Tcl_Obj *pathPtr, int mode);\n/* 456 */\nEXTERN Tcl_Channel\tTcl_FSOpenFileChannel(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *pathPtr, const char *modeString,\n\t\t\t\tint permissions);\n/* 457 */\nEXTERN Tcl_Obj *\tTcl_FSGetCwd(Tcl_Interp *interp);\n/* 458 */\nEXTERN int\t\tTcl_FSChdir(Tcl_Obj *pathPtr);\n/* 459 */\nEXTERN int\t\tTcl_FSConvertToPathType(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *pathPtr);\n/* 460 */\nEXTERN Tcl_Obj *\tTcl_FSJoinPath(Tcl_Obj *listObj, int elements);\n/* 461 */\nEXTERN Tcl_Obj *\tTcl_FSSplitPath(Tcl_Obj *pathPtr, int *lenPtr);\n/* 462 */\nEXTERN int\t\tTcl_FSEqualPaths(Tcl_Obj *firstPtr,\n\t\t\t\tTcl_Obj *secondPtr);\n/* 463 */\nEXTERN Tcl_Obj *\tTcl_FSGetNormalizedPath(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *pathPtr);\n/* 464 */\nEXTERN Tcl_Obj *\tTcl_FSJoinToPath(Tcl_Obj *pathPtr, int objc,\n\t\t\t\tTcl_Obj *const objv[]);\n/* 465 */\nEXTERN ClientData\tTcl_FSGetInternalRep(Tcl_Obj *pathPtr,\n\t\t\t\tconst Tcl_Filesystem *fsPtr);\n/* 466 */\nEXTERN Tcl_Obj *\tTcl_FSGetTranslatedPath(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *pathPtr);\n/* 467 */\nEXTERN int\t\tTcl_FSEvalFile(Tcl_Interp *interp, Tcl_Obj *fileName);\n/* 468 */\nEXTERN Tcl_Obj *\tTcl_FSNewNativePath(\n\t\t\t\tconst Tcl_Filesystem *fromFilesystem,\n\t\t\t\tClientData clientData);\n/* 469 */\nEXTERN const void *\tTcl_FSGetNativePath(Tcl_Obj *pathPtr);\n/* 470 */\nEXTERN Tcl_Obj *\tTcl_FSFileSystemInfo(Tcl_Obj *pathPtr);\n/* 471 */\nEXTERN Tcl_Obj *\tTcl_FSPathSeparator(Tcl_Obj *pathPtr);\n/* 472 */\nEXTERN Tcl_Obj *\tTcl_FSListVolumes(void);\n/* 473 */\nEXTERN int\t\tTcl_FSRegister(ClientData clientData,\n\t\t\t\tconst Tcl_Filesystem *fsPtr);\n/* 474 */\nEXTERN int\t\tTcl_FSUnregister(const Tcl_Filesystem *fsPtr);\n/* 475 */\nEXTERN ClientData\tTcl_FSData(const Tcl_Filesystem *fsPtr);\n/* 476 */\nEXTERN const char *\tTcl_FSGetTranslatedStringPath(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *pathPtr);\n/* 477 */\nEXTERN CONST86 Tcl_Filesystem * Tcl_FSGetFileSystemForPath(Tcl_Obj *pathPtr);\n/* 478 */\nEXTERN Tcl_PathType\tTcl_FSGetPathType(Tcl_Obj *pathPtr);\n/* 479 */\nEXTERN int\t\tTcl_OutputBuffered(Tcl_Channel chan);\n/* 480 */\nEXTERN void\t\tTcl_FSMountsChanged(const Tcl_Filesystem *fsPtr);\n/* 481 */\nEXTERN int\t\tTcl_EvalTokensStandard(Tcl_Interp *interp,\n\t\t\t\tTcl_Token *tokenPtr, int count);\n/* 482 */\nEXTERN void\t\tTcl_GetTime(Tcl_Time *timeBuf);\n/* 483 */\nEXTERN Tcl_Trace\tTcl_CreateObjTrace(Tcl_Interp *interp, int level,\n\t\t\t\tint flags, Tcl_CmdObjTraceProc *objProc,\n\t\t\t\tClientData clientData,\n\t\t\t\tTcl_CmdObjTraceDeleteProc *delProc);\n/* 484 */\nEXTERN int\t\tTcl_GetCommandInfoFromToken(Tcl_Command token,\n\t\t\t\tTcl_CmdInfo *infoPtr);\n/* 485 */\nEXTERN int\t\tTcl_SetCommandInfoFromToken(Tcl_Command token,\n\t\t\t\tconst Tcl_CmdInfo *infoPtr);\n/* 486 */\nEXTERN Tcl_Obj *\tTcl_DbNewWideIntObj(Tcl_WideInt wideValue,\n\t\t\t\tconst char *file, int line);\n/* 487 */\nEXTERN int\t\tTcl_GetWideIntFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, Tcl_WideInt *widePtr);\n/* 488 */\nEXTERN Tcl_Obj *\tTcl_NewWideIntObj(Tcl_WideInt wideValue);\n/* 489 */\nEXTERN void\t\tTcl_SetWideIntObj(Tcl_Obj *objPtr,\n\t\t\t\tTcl_WideInt wideValue);\n/* 490 */\nEXTERN Tcl_StatBuf *\tTcl_AllocStatBuf(void);\n/* 491 */\nEXTERN Tcl_WideInt\tTcl_Seek(Tcl_Channel chan, Tcl_WideInt offset,\n\t\t\t\tint mode);\n/* 492 */\nEXTERN Tcl_WideInt\tTcl_Tell(Tcl_Channel chan);\n/* 493 */\nEXTERN Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 494 */\nEXTERN int\t\tTcl_DictObjPut(Tcl_Interp *interp, Tcl_Obj *dictPtr,\n\t\t\t\tTcl_Obj *keyPtr, Tcl_Obj *valuePtr);\n/* 495 */\nEXTERN int\t\tTcl_DictObjGet(Tcl_Interp *interp, Tcl_Obj *dictPtr,\n\t\t\t\tTcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr);\n/* 496 */\nEXTERN int\t\tTcl_DictObjRemove(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *dictPtr, Tcl_Obj *keyPtr);\n/* 497 */\nEXTERN int\t\tTcl_DictObjSize(Tcl_Interp *interp, Tcl_Obj *dictPtr,\n\t\t\t\tint *sizePtr);\n/* 498 */\nEXTERN int\t\tTcl_DictObjFirst(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *dictPtr, Tcl_DictSearch *searchPtr,\n\t\t\t\tTcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr,\n\t\t\t\tint *donePtr);\n/* 499 */\nEXTERN void\t\tTcl_DictObjNext(Tcl_DictSearch *searchPtr,\n\t\t\t\tTcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr,\n\t\t\t\tint *donePtr);\n/* 500 */\nEXTERN void\t\tTcl_DictObjDone(Tcl_DictSearch *searchPtr);\n/* 501 */\nEXTERN int\t\tTcl_DictObjPutKeyList(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *dictPtr, int keyc,\n\t\t\t\tTcl_Obj *const *keyv, Tcl_Obj *valuePtr);\n/* 502 */\nEXTERN int\t\tTcl_DictObjRemoveKeyList(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *dictPtr, int keyc,\n\t\t\t\tTcl_Obj *const *keyv);\n/* 503 */\nEXTERN Tcl_Obj *\tTcl_NewDictObj(void);\n/* 504 */\nEXTERN Tcl_Obj *\tTcl_DbNewDictObj(const char *file, int line);\n/* 505 */\nEXTERN void\t\tTcl_RegisterConfig(Tcl_Interp *interp,\n\t\t\t\tconst char *pkgName,\n\t\t\t\tconst Tcl_Config *configuration,\n\t\t\t\tconst char *valEncoding);\n/* 506 */\nEXTERN Tcl_Namespace *\tTcl_CreateNamespace(Tcl_Interp *interp,\n\t\t\t\tconst char *name, ClientData clientData,\n\t\t\t\tTcl_NamespaceDeleteProc *deleteProc);\n/* 507 */\nEXTERN void\t\tTcl_DeleteNamespace(Tcl_Namespace *nsPtr);\n/* 508 */\nEXTERN int\t\tTcl_AppendExportList(Tcl_Interp *interp,\n\t\t\t\tTcl_Namespace *nsPtr, Tcl_Obj *objPtr);\n/* 509 */\nEXTERN int\t\tTcl_Export(Tcl_Interp *interp, Tcl_Namespace *nsPtr,\n\t\t\t\tconst char *pattern, int resetListFirst);\n/* 510 */\nEXTERN int\t\tTcl_Import(Tcl_Interp *interp, Tcl_Namespace *nsPtr,\n\t\t\t\tconst char *pattern, int allowOverwrite);\n/* 511 */\nEXTERN int\t\tTcl_ForgetImport(Tcl_Interp *interp,\n\t\t\t\tTcl_Namespace *nsPtr, const char *pattern);\n/* 512 */\nEXTERN Tcl_Namespace *\tTcl_GetCurrentNamespace(Tcl_Interp *interp);\n/* 513 */\nEXTERN Tcl_Namespace *\tTcl_GetGlobalNamespace(Tcl_Interp *interp);\n/* 514 */\nEXTERN Tcl_Namespace *\tTcl_FindNamespace(Tcl_Interp *interp,\n\t\t\t\tconst char *name,\n\t\t\t\tTcl_Namespace *contextNsPtr, int flags);\n/* 515 */\nEXTERN Tcl_Command\tTcl_FindCommand(Tcl_Interp *interp, const char *name,\n\t\t\t\tTcl_Namespace *contextNsPtr, int flags);\n/* 516 */\nEXTERN Tcl_Command\tTcl_GetCommandFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr);\n/* 517 */\nEXTERN void\t\tTcl_GetCommandFullName(Tcl_Interp *interp,\n\t\t\t\tTcl_Command command, Tcl_Obj *objPtr);\n/* 518 */\nEXTERN int\t\tTcl_FSEvalFileEx(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *fileName, const char *encodingName);\n/* 519 */\nEXTERN Tcl_ExitProc *\tTcl_SetExitProc(TCL_NORETURN1 Tcl_ExitProc *proc);\n/* 520 */\nEXTERN void\t\tTcl_LimitAddHandler(Tcl_Interp *interp, int type,\n\t\t\t\tTcl_LimitHandlerProc *handlerProc,\n\t\t\t\tClientData clientData,\n\t\t\t\tTcl_LimitHandlerDeleteProc *deleteProc);\n/* 521 */\nEXTERN void\t\tTcl_LimitRemoveHandler(Tcl_Interp *interp, int type,\n\t\t\t\tTcl_LimitHandlerProc *handlerProc,\n\t\t\t\tClientData clientData);\n/* 522 */\nEXTERN int\t\tTcl_LimitReady(Tcl_Interp *interp);\n/* 523 */\nEXTERN int\t\tTcl_LimitCheck(Tcl_Interp *interp);\n/* 524 */\nEXTERN int\t\tTcl_LimitExceeded(Tcl_Interp *interp);\n/* 525 */\nEXTERN void\t\tTcl_LimitSetCommands(Tcl_Interp *interp,\n\t\t\t\tint commandLimit);\n/* 526 */\nEXTERN void\t\tTcl_LimitSetTime(Tcl_Interp *interp,\n\t\t\t\tTcl_Time *timeLimitPtr);\n/* 527 */\nEXTERN void\t\tTcl_LimitSetGranularity(Tcl_Interp *interp, int type,\n\t\t\t\tint granularity);\n/* 528 */\nEXTERN int\t\tTcl_LimitTypeEnabled(Tcl_Interp *interp, int type);\n/* 529 */\nEXTERN int\t\tTcl_LimitTypeExceeded(Tcl_Interp *interp, int type);\n/* 530 */\nEXTERN void\t\tTcl_LimitTypeSet(Tcl_Interp *interp, int type);\n/* 531 */\nEXTERN void\t\tTcl_LimitTypeReset(Tcl_Interp *interp, int type);\n/* 532 */\nEXTERN int\t\tTcl_LimitGetCommands(Tcl_Interp *interp);\n/* 533 */\nEXTERN void\t\tTcl_LimitGetTime(Tcl_Interp *interp,\n\t\t\t\tTcl_Time *timeLimitPtr);\n/* 534 */\nEXTERN int\t\tTcl_LimitGetGranularity(Tcl_Interp *interp, int type);\n/* 535 */\nEXTERN Tcl_InterpState\tTcl_SaveInterpState(Tcl_Interp *interp, int status);\n/* 536 */\nEXTERN int\t\tTcl_RestoreInterpState(Tcl_Interp *interp,\n\t\t\t\tTcl_InterpState state);\n/* 537 */\nEXTERN void\t\tTcl_DiscardInterpState(Tcl_InterpState state);\n/* 538 */\nEXTERN int\t\tTcl_SetReturnOptions(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *options);\n/* 539 */\nEXTERN Tcl_Obj *\tTcl_GetReturnOptions(Tcl_Interp *interp, int result);\n/* 540 */\nEXTERN int\t\tTcl_IsEnsemble(Tcl_Command token);\n/* 541 */\nEXTERN Tcl_Command\tTcl_CreateEnsemble(Tcl_Interp *interp,\n\t\t\t\tconst char *name,\n\t\t\t\tTcl_Namespace *namespacePtr, int flags);\n/* 542 */\nEXTERN Tcl_Command\tTcl_FindEnsemble(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *cmdNameObj, int flags);\n/* 543 */\nEXTERN int\t\tTcl_SetEnsembleSubcommandList(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, Tcl_Obj *subcmdList);\n/* 544 */\nEXTERN int\t\tTcl_SetEnsembleMappingDict(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, Tcl_Obj *mapDict);\n/* 545 */\nEXTERN int\t\tTcl_SetEnsembleUnknownHandler(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, Tcl_Obj *unknownList);\n/* 546 */\nEXTERN int\t\tTcl_SetEnsembleFlags(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, int flags);\n/* 547 */\nEXTERN int\t\tTcl_GetEnsembleSubcommandList(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, Tcl_Obj **subcmdListPtr);\n/* 548 */\nEXTERN int\t\tTcl_GetEnsembleMappingDict(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, Tcl_Obj **mapDictPtr);\n/* 549 */\nEXTERN int\t\tTcl_GetEnsembleUnknownHandler(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, Tcl_Obj **unknownListPtr);\n/* 550 */\nEXTERN int\t\tTcl_GetEnsembleFlags(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, int *flagsPtr);\n/* 551 */\nEXTERN int\t\tTcl_GetEnsembleNamespace(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token,\n\t\t\t\tTcl_Namespace **namespacePtrPtr);\n/* 552 */\nEXTERN void\t\tTcl_SetTimeProc(Tcl_GetTimeProc *getProc,\n\t\t\t\tTcl_ScaleTimeProc *scaleProc,\n\t\t\t\tClientData clientData);\n/* 553 */\nEXTERN void\t\tTcl_QueryTimeProc(Tcl_GetTimeProc **getProc,\n\t\t\t\tTcl_ScaleTimeProc **scaleProc,\n\t\t\t\tClientData *clientData);\n/* 554 */\nEXTERN Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 555 */\nEXTERN Tcl_Obj *\tTcl_NewBignumObj(mp_int *value);\n/* 556 */\nEXTERN Tcl_Obj *\tTcl_DbNewBignumObj(mp_int *value, const char *file,\n\t\t\t\tint line);\n/* 557 */\nEXTERN void\t\tTcl_SetBignumObj(Tcl_Obj *obj, mp_int *value);\n/* 558 */\nEXTERN int\t\tTcl_GetBignumFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *obj, mp_int *value);\n/* 559 */\nEXTERN int\t\tTcl_TakeBignumFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *obj, mp_int *value);\n/* 560 */\nEXTERN int\t\tTcl_TruncateChannel(Tcl_Channel chan,\n\t\t\t\tTcl_WideInt length);\n/* 561 */\nEXTERN Tcl_DriverTruncateProc * Tcl_ChannelTruncateProc(\n\t\t\t\tconst Tcl_ChannelType *chanTypePtr);\n/* 562 */\nEXTERN void\t\tTcl_SetChannelErrorInterp(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *msg);\n/* 563 */\nEXTERN void\t\tTcl_GetChannelErrorInterp(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj **msg);\n/* 564 */\nEXTERN void\t\tTcl_SetChannelError(Tcl_Channel chan, Tcl_Obj *msg);\n/* 565 */\nEXTERN void\t\tTcl_GetChannelError(Tcl_Channel chan, Tcl_Obj **msg);\n/* 566 */\nEXTERN int\t\tTcl_InitBignumFromDouble(Tcl_Interp *interp,\n\t\t\t\tdouble initval, mp_int *toInit);\n/* 567 */\nEXTERN Tcl_Obj *\tTcl_GetNamespaceUnknownHandler(Tcl_Interp *interp,\n\t\t\t\tTcl_Namespace *nsPtr);\n/* 568 */\nEXTERN int\t\tTcl_SetNamespaceUnknownHandler(Tcl_Interp *interp,\n\t\t\t\tTcl_Namespace *nsPtr, Tcl_Obj *handlerPtr);\n/* 569 */\nEXTERN int\t\tTcl_GetEncodingFromObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, Tcl_Encoding *encodingPtr);\n/* 570 */\nEXTERN Tcl_Obj *\tTcl_GetEncodingSearchPath(void);\n/* 571 */\nEXTERN int\t\tTcl_SetEncodingSearchPath(Tcl_Obj *searchPath);\n/* 572 */\nEXTERN const char *\tTcl_GetEncodingNameFromEnvironment(\n\t\t\t\tTcl_DString *bufPtr);\n/* 573 */\nEXTERN int\t\tTcl_PkgRequireProc(Tcl_Interp *interp,\n\t\t\t\tconst char *name, int objc,\n\t\t\t\tTcl_Obj *const objv[], void *clientDataPtr);\n/* 574 */\nEXTERN void\t\tTcl_AppendObjToErrorInfo(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr);\n/* 575 */\nEXTERN void\t\tTcl_AppendLimitedToObj(Tcl_Obj *objPtr,\n\t\t\t\tconst char *bytes, int length, int limit,\n\t\t\t\tconst char *ellipsis);\n/* 576 */\nEXTERN Tcl_Obj *\tTcl_Format(Tcl_Interp *interp, const char *format,\n\t\t\t\tint objc, Tcl_Obj *const objv[]);\n/* 577 */\nEXTERN int\t\tTcl_AppendFormatToObj(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *objPtr, const char *format,\n\t\t\t\tint objc, Tcl_Obj *const objv[]);\n/* 578 */\nEXTERN Tcl_Obj *\tTcl_ObjPrintf(const char *format, ...) TCL_FORMAT_PRINTF(1, 2);\n/* 579 */\nEXTERN void\t\tTcl_AppendPrintfToObj(Tcl_Obj *objPtr,\n\t\t\t\tconst char *format, ...) TCL_FORMAT_PRINTF(2, 3);\n/* 580 */\nEXTERN int\t\tTcl_CancelEval(Tcl_Interp *interp,\n\t\t\t\tTcl_Obj *resultObjPtr, ClientData clientData,\n\t\t\t\tint flags);\n/* 581 */\nEXTERN int\t\tTcl_Canceled(Tcl_Interp *interp, int flags);\n/* 582 */\nEXTERN int\t\tTcl_CreatePipe(Tcl_Interp *interp,\n\t\t\t\tTcl_Channel *rchan, Tcl_Channel *wchan,\n\t\t\t\tint flags);\n/* 583 */\nEXTERN Tcl_Command\tTcl_NRCreateCommand(Tcl_Interp *interp,\n\t\t\t\tconst char *cmdName, Tcl_ObjCmdProc *proc,\n\t\t\t\tTcl_ObjCmdProc *nreProc,\n\t\t\t\tClientData clientData,\n\t\t\t\tTcl_CmdDeleteProc *deleteProc);\n/* 584 */\nEXTERN int\t\tTcl_NREvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr,\n\t\t\t\tint flags);\n/* 585 */\nEXTERN int\t\tTcl_NREvalObjv(Tcl_Interp *interp, int objc,\n\t\t\t\tTcl_Obj *const objv[], int flags);\n/* 586 */\nEXTERN int\t\tTcl_NRCmdSwap(Tcl_Interp *interp, Tcl_Command cmd,\n\t\t\t\tint objc, Tcl_Obj *const objv[], int flags);\n/* 587 */\nEXTERN void\t\tTcl_NRAddCallback(Tcl_Interp *interp,\n\t\t\t\tTcl_NRPostProc *postProcPtr,\n\t\t\t\tClientData data0, ClientData data1,\n\t\t\t\tClientData data2, ClientData data3);\n/* 588 */\nEXTERN int\t\tTcl_NRCallObjProc(Tcl_Interp *interp,\n\t\t\t\tTcl_ObjCmdProc *objProc,\n\t\t\t\tClientData clientData, int objc,\n\t\t\t\tTcl_Obj *const objv[]);\n/* 589 */\nEXTERN unsigned\t\tTcl_GetFSDeviceFromStat(const Tcl_StatBuf *statPtr);\n/* 590 */\nEXTERN unsigned\t\tTcl_GetFSInodeFromStat(const Tcl_StatBuf *statPtr);\n/* 591 */\nEXTERN unsigned\t\tTcl_GetModeFromStat(const Tcl_StatBuf *statPtr);\n/* 592 */\nEXTERN int\t\tTcl_GetLinkCountFromStat(const Tcl_StatBuf *statPtr);\n/* 593 */\nEXTERN int\t\tTcl_GetUserIdFromStat(const Tcl_StatBuf *statPtr);\n/* 594 */\nEXTERN int\t\tTcl_GetGroupIdFromStat(const Tcl_StatBuf *statPtr);\n/* 595 */\nEXTERN int\t\tTcl_GetDeviceTypeFromStat(const Tcl_StatBuf *statPtr);\n/* 596 */\nEXTERN Tcl_WideInt\tTcl_GetAccessTimeFromStat(const Tcl_StatBuf *statPtr);\n/* 597 */\nEXTERN Tcl_WideInt\tTcl_GetModificationTimeFromStat(\n\t\t\t\tconst Tcl_StatBuf *statPtr);\n/* 598 */\nEXTERN Tcl_WideInt\tTcl_GetChangeTimeFromStat(const Tcl_StatBuf *statPtr);\n/* 599 */\nEXTERN Tcl_WideUInt\tTcl_GetSizeFromStat(const Tcl_StatBuf *statPtr);\n/* 600 */\nEXTERN Tcl_WideUInt\tTcl_GetBlocksFromStat(const Tcl_StatBuf *statPtr);\n/* 601 */\nEXTERN unsigned\t\tTcl_GetBlockSizeFromStat(const Tcl_StatBuf *statPtr);\n/* 602 */\nEXTERN int\t\tTcl_SetEnsembleParameterList(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, Tcl_Obj *paramList);\n/* 603 */\nEXTERN int\t\tTcl_GetEnsembleParameterList(Tcl_Interp *interp,\n\t\t\t\tTcl_Command token, Tcl_Obj **paramListPtr);\n/* 604 */\nEXTERN int\t\tTcl_ParseArgsObjv(Tcl_Interp *interp,\n\t\t\t\tconst Tcl_ArgvInfo *argTable, int *objcPtr,\n\t\t\t\tTcl_Obj *const *objv, Tcl_Obj ***remObjv);\n/* 605 */\nEXTERN int\t\tTcl_GetErrorLine(Tcl_Interp *interp);\n/* 606 */\nEXTERN void\t\tTcl_SetErrorLine(Tcl_Interp *interp, int lineNum);\n/* 607 */\nEXTERN void\t\tTcl_TransferResult(Tcl_Interp *sourceInterp,\n\t\t\t\tint result, Tcl_Interp *targetInterp);\n/* 608 */\nEXTERN int\t\tTcl_InterpActive(Tcl_Interp *interp);\n/* 609 */\nEXTERN void\t\tTcl_BackgroundException(Tcl_Interp *interp, int code);\n/* 610 */\nEXTERN int\t\tTcl_ZlibDeflate(Tcl_Interp *interp, int format,\n\t\t\t\tTcl_Obj *data, int level,\n\t\t\t\tTcl_Obj *gzipHeaderDictObj);\n/* 611 */\nEXTERN int\t\tTcl_ZlibInflate(Tcl_Interp *interp, int format,\n\t\t\t\tTcl_Obj *data, int buffersize,\n\t\t\t\tTcl_Obj *gzipHeaderDictObj);\n/* 612 */\nEXTERN unsigned int\tTcl_ZlibCRC32(unsigned int crc,\n\t\t\t\tconst unsigned char *buf, int len);\n/* 613 */\nEXTERN unsigned int\tTcl_ZlibAdler32(unsigned int adler,\n\t\t\t\tconst unsigned char *buf, int len);\n/* 614 */\nEXTERN int\t\tTcl_ZlibStreamInit(Tcl_Interp *interp, int mode,\n\t\t\t\tint format, int level, Tcl_Obj *dictObj,\n\t\t\t\tTcl_ZlibStream *zshandle);\n/* 615 */\nEXTERN Tcl_Obj *\tTcl_ZlibStreamGetCommandName(Tcl_ZlibStream zshandle);\n/* 616 */\nEXTERN int\t\tTcl_ZlibStreamEof(Tcl_ZlibStream zshandle);\n/* 617 */\nEXTERN int\t\tTcl_ZlibStreamChecksum(Tcl_ZlibStream zshandle);\n/* 618 */\nEXTERN int\t\tTcl_ZlibStreamPut(Tcl_ZlibStream zshandle,\n\t\t\t\tTcl_Obj *data, int flush);\n/* 619 */\nEXTERN int\t\tTcl_ZlibStreamGet(Tcl_ZlibStream zshandle,\n\t\t\t\tTcl_Obj *data, int count);\n/* 620 */\nEXTERN int\t\tTcl_ZlibStreamClose(Tcl_ZlibStream zshandle);\n/* 621 */\nEXTERN int\t\tTcl_ZlibStreamReset(Tcl_ZlibStream zshandle);\n/* 622 */\nEXTERN void\t\tTcl_SetStartupScript(Tcl_Obj *path,\n\t\t\t\tconst char *encoding);\n/* 623 */\nEXTERN Tcl_Obj *\tTcl_GetStartupScript(const char **encodingPtr);\n/* 624 */\nEXTERN int\t\tTcl_CloseEx(Tcl_Interp *interp, Tcl_Channel chan,\n\t\t\t\tint flags);\n/* 625 */\nEXTERN int\t\tTcl_NRExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr,\n\t\t\t\tTcl_Obj *resultPtr);\n/* 626 */\nEXTERN int\t\tTcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr,\n\t\t\t\tint flags);\n/* 627 */\nEXTERN int\t\tTcl_LoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,\n\t\t\t\tconst char *const symv[], int flags,\n\t\t\t\tvoid *procPtrs, Tcl_LoadHandle *handlePtr);\n/* 628 */\nEXTERN void *\t\tTcl_FindSymbol(Tcl_Interp *interp,\n\t\t\t\tTcl_LoadHandle handle, const char *symbol);\n/* 629 */\nEXTERN int\t\tTcl_FSUnloadFile(Tcl_Interp *interp,\n\t\t\t\tTcl_LoadHandle handlePtr);\n/* 630 */\nEXTERN void\t\tTcl_ZlibStreamSetCompressionDictionary(\n\t\t\t\tTcl_ZlibStream zhandle,\n\t\t\t\tTcl_Obj *compressionDictionaryObj);\n\ntypedef struct {\n    const struct TclPlatStubs *tclPlatStubs;\n    const struct TclIntStubs *tclIntStubs;\n    const struct TclIntPlatStubs *tclIntPlatStubs;\n} TclStubHooks;\n\ntypedef struct TclStubs {\n    int magic;\n    const TclStubHooks *hooks;\n\n    int (*tcl_PkgProvideEx) (Tcl_Interp *interp, const char *name, const char *version, const void *clientData); /* 0 */\n    CONST84_RETURN char * (*tcl_PkgRequireEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 1 */\n    TCL_NORETURN1 void (*tcl_Panic) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 2 */\n    char * (*tcl_Alloc) (unsigned int size); /* 3 */\n    void (*tcl_Free) (char *ptr); /* 4 */\n    char * (*tcl_Realloc) (char *ptr, unsigned int size); /* 5 */\n    char * (*tcl_DbCkalloc) (unsigned int size, const char *file, int line); /* 6 */\n    void (*tcl_DbCkfree) (char *ptr, const char *file, int line); /* 7 */\n    char * (*tcl_DbCkrealloc) (char *ptr, unsigned int size, const char *file, int line); /* 8 */\n#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */\n    void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */\n#endif /* UNIX */\n#if defined(_WIN32) /* WIN */\n    void (*reserved9)(void);\n#endif /* WIN */\n#ifdef MAC_OSX_TCL /* MACOSX */\n    void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */\n#endif /* MACOSX */\n#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */\n    void (*tcl_DeleteFileHandler) (int fd); /* 10 */\n#endif /* UNIX */\n#if defined(_WIN32) /* WIN */\n    void (*reserved10)(void);\n#endif /* WIN */\n#ifdef MAC_OSX_TCL /* MACOSX */\n    void (*tcl_DeleteFileHandler) (int fd); /* 10 */\n#endif /* MACOSX */\n    void (*tcl_SetTimer) (const Tcl_Time *timePtr); /* 11 */\n    void (*tcl_Sleep) (int ms); /* 12 */\n    int (*tcl_WaitForEvent) (const Tcl_Time *timePtr); /* 13 */\n    int (*tcl_AppendAllObjTypes) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 14 */\n    void (*tcl_AppendStringsToObj) (Tcl_Obj *objPtr, ...); /* 15 */\n    void (*tcl_AppendToObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 16 */\n    Tcl_Obj * (*tcl_ConcatObj) (int objc, Tcl_Obj *const objv[]); /* 17 */\n    int (*tcl_ConvertToType) (Tcl_Interp *interp, Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 18 */\n    void (*tcl_DbDecrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 19 */\n    void (*tcl_DbIncrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 20 */\n    int (*tcl_DbIsShared) (Tcl_Obj *objPtr, const char *file, int line); /* 21 */\n    Tcl_Obj * (*tcl_DbNewBooleanObj) (int boolValue, const char *file, int line); /* 22 */\n    Tcl_Obj * (*tcl_DbNewByteArrayObj) (const unsigned char *bytes, int length, const char *file, int line); /* 23 */\n    Tcl_Obj * (*tcl_DbNewDoubleObj) (double doubleValue, const char *file, int line); /* 24 */\n    Tcl_Obj * (*tcl_DbNewListObj) (int objc, Tcl_Obj *const *objv, const char *file, int line); /* 25 */\n    Tcl_Obj * (*tcl_DbNewLongObj) (long longValue, const char *file, int line); /* 26 */\n    Tcl_Obj * (*tcl_DbNewObj) (const char *file, int line); /* 27 */\n    Tcl_Obj * (*tcl_DbNewStringObj) (const char *bytes, int length, const char *file, int line); /* 28 */\n    Tcl_Obj * (*tcl_DuplicateObj) (Tcl_Obj *objPtr); /* 29 */\n    void (*tclFreeObj) (Tcl_Obj *objPtr); /* 30 */\n    int (*tcl_GetBoolean) (Tcl_Interp *interp, const char *src, int *boolPtr); /* 31 */\n    int (*tcl_GetBooleanFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *boolPtr); /* 32 */\n    unsigned char * (*tcl_GetByteArrayFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 33 */\n    int (*tcl_GetDouble) (Tcl_Interp *interp, const char *src, double *doublePtr); /* 34 */\n    int (*tcl_GetDoubleFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* 35 */\n    int (*tcl_GetIndexFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, CONST84 char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 36 */\n    int (*tcl_GetInt) (Tcl_Interp *interp, const char *src, int *intPtr); /* 37 */\n    int (*tcl_GetIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 38 */\n    int (*tcl_GetLongFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr); /* 39 */\n    CONST86 Tcl_ObjType * (*tcl_GetObjType) (const char *typeName); /* 40 */\n    char * (*tcl_GetStringFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 41 */\n    void (*tcl_InvalidateStringRep) (Tcl_Obj *objPtr); /* 42 */\n    int (*tcl_ListObjAppendList) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); /* 43 */\n    int (*tcl_ListObjAppendElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr); /* 44 */\n    int (*tcl_ListObjGetElements) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr); /* 45 */\n    int (*tcl_ListObjIndex) (Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr); /* 46 */\n    int (*tcl_ListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr); /* 47 */\n    int (*tcl_ListObjReplace) (Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *const objv[]); /* 48 */\n    Tcl_Obj * (*tcl_NewBooleanObj) (int boolValue); /* 49 */\n    Tcl_Obj * (*tcl_NewByteArrayObj) (const unsigned char *bytes, int length); /* 50 */\n    Tcl_Obj * (*tcl_NewDoubleObj) (double doubleValue); /* 51 */\n    Tcl_Obj * (*tcl_NewIntObj) (int intValue); /* 52 */\n    Tcl_Obj * (*tcl_NewListObj) (int objc, Tcl_Obj *const objv[]); /* 53 */\n    Tcl_Obj * (*tcl_NewLongObj) (long longValue); /* 54 */\n    Tcl_Obj * (*tcl_NewObj) (void); /* 55 */\n    Tcl_Obj * (*tcl_NewStringObj) (const char *bytes, int length); /* 56 */\n    void (*tcl_SetBooleanObj) (Tcl_Obj *objPtr, int boolValue); /* 57 */\n    unsigned char * (*tcl_SetByteArrayLength) (Tcl_Obj *objPtr, int length); /* 58 */\n    void (*tcl_SetByteArrayObj) (Tcl_Obj *objPtr, const unsigned char *bytes, int length); /* 59 */\n    void (*tcl_SetDoubleObj) (Tcl_Obj *objPtr, double doubleValue); /* 60 */\n    void (*tcl_SetIntObj) (Tcl_Obj *objPtr, int intValue); /* 61 */\n    void (*tcl_SetListObj) (Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[]); /* 62 */\n    void (*tcl_SetLongObj) (Tcl_Obj *objPtr, long longValue); /* 63 */\n    void (*tcl_SetObjLength) (Tcl_Obj *objPtr, int length); /* 64 */\n    void (*tcl_SetStringObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 65 */\n    void (*tcl_AddErrorInfo) (Tcl_Interp *interp, const char *message); /* 66 */\n    void (*tcl_AddObjErrorInfo) (Tcl_Interp *interp, const char *message, int length); /* 67 */\n    void (*tcl_AllowExceptions) (Tcl_Interp *interp); /* 68 */\n    void (*tcl_AppendElement) (Tcl_Interp *interp, const char *element); /* 69 */\n    void (*tcl_AppendResult) (Tcl_Interp *interp, ...); /* 70 */\n    Tcl_AsyncHandler (*tcl_AsyncCreate) (Tcl_AsyncProc *proc, ClientData clientData); /* 71 */\n    void (*tcl_AsyncDelete) (Tcl_AsyncHandler async); /* 72 */\n    int (*tcl_AsyncInvoke) (Tcl_Interp *interp, int code); /* 73 */\n    void (*tcl_AsyncMark) (Tcl_AsyncHandler async); /* 74 */\n    int (*tcl_AsyncReady) (void); /* 75 */\n    void (*tcl_BackgroundError) (Tcl_Interp *interp); /* 76 */\n    char (*tcl_Backslash) (const char *src, int *readPtr); /* 77 */\n    int (*tcl_BadChannelOption) (Tcl_Interp *interp, const char *optionName, const char *optionList); /* 78 */\n    void (*tcl_CallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 79 */\n    void (*tcl_CancelIdleCall) (Tcl_IdleProc *idleProc, ClientData clientData); /* 80 */\n    int (*tcl_Close) (Tcl_Interp *interp, Tcl_Channel chan); /* 81 */\n    int (*tcl_CommandComplete) (const char *cmd); /* 82 */\n    char * (*tcl_Concat) (int argc, CONST84 char *const *argv); /* 83 */\n    int (*tcl_ConvertElement) (const char *src, char *dst, int flags); /* 84 */\n    int (*tcl_ConvertCountedElement) (const char *src, int length, char *dst, int flags); /* 85 */\n    int (*tcl_CreateAlias) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int argc, CONST84 char *const *argv); /* 86 */\n    int (*tcl_CreateAliasObj) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int objc, Tcl_Obj *const objv[]); /* 87 */\n    Tcl_Channel (*tcl_CreateChannel) (const Tcl_ChannelType *typePtr, const char *chanName, ClientData instanceData, int mask); /* 88 */\n    void (*tcl_CreateChannelHandler) (Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, ClientData clientData); /* 89 */\n    void (*tcl_CreateCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 90 */\n    Tcl_Command (*tcl_CreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 91 */\n    void (*tcl_CreateEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 92 */\n    void (*tcl_CreateExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 93 */\n    Tcl_Interp * (*tcl_CreateInterp) (void); /* 94 */\n    void (*tcl_CreateMathFunc) (Tcl_Interp *interp, const char *name, int numArgs, Tcl_ValueType *argTypes, Tcl_MathProc *proc, ClientData clientData); /* 95 */\n    Tcl_Command (*tcl_CreateObjCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 96 */\n    Tcl_Interp * (*tcl_CreateSlave) (Tcl_Interp *interp, const char *slaveName, int isSafe); /* 97 */\n    Tcl_TimerToken (*tcl_CreateTimerHandler) (int milliseconds, Tcl_TimerProc *proc, ClientData clientData); /* 98 */\n    Tcl_Trace (*tcl_CreateTrace) (Tcl_Interp *interp, int level, Tcl_CmdTraceProc *proc, ClientData clientData); /* 99 */\n    void (*tcl_DeleteAssocData) (Tcl_Interp *interp, const char *name); /* 100 */\n    void (*tcl_DeleteChannelHandler) (Tcl_Channel chan, Tcl_ChannelProc *proc, ClientData clientData); /* 101 */\n    void (*tcl_DeleteCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 102 */\n    int (*tcl_DeleteCommand) (Tcl_Interp *interp, const char *cmdName); /* 103 */\n    int (*tcl_DeleteCommandFromToken) (Tcl_Interp *interp, Tcl_Command command); /* 104 */\n    void (*tcl_DeleteEvents) (Tcl_EventDeleteProc *proc, ClientData clientData); /* 105 */\n    void (*tcl_DeleteEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 106 */\n    void (*tcl_DeleteExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 107 */\n    void (*tcl_DeleteHashEntry) (Tcl_HashEntry *entryPtr); /* 108 */\n    void (*tcl_DeleteHashTable) (Tcl_HashTable *tablePtr); /* 109 */\n    void (*tcl_DeleteInterp) (Tcl_Interp *interp); /* 110 */\n    void (*tcl_DetachPids) (int numPids, Tcl_Pid *pidPtr); /* 111 */\n    void (*tcl_DeleteTimerHandler) (Tcl_TimerToken token); /* 112 */\n    void (*tcl_DeleteTrace) (Tcl_Interp *interp, Tcl_Trace trace); /* 113 */\n    void (*tcl_DontCallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 114 */\n    int (*tcl_DoOneEvent) (int flags); /* 115 */\n    void (*tcl_DoWhenIdle) (Tcl_IdleProc *proc, ClientData clientData); /* 116 */\n    char * (*tcl_DStringAppend) (Tcl_DString *dsPtr, const char *bytes, int length); /* 117 */\n    char * (*tcl_DStringAppendElement) (Tcl_DString *dsPtr, const char *element); /* 118 */\n    void (*tcl_DStringEndSublist) (Tcl_DString *dsPtr); /* 119 */\n    void (*tcl_DStringFree) (Tcl_DString *dsPtr); /* 120 */\n    void (*tcl_DStringGetResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 121 */\n    void (*tcl_DStringInit) (Tcl_DString *dsPtr); /* 122 */\n    void (*tcl_DStringResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 123 */\n    void (*tcl_DStringSetLength) (Tcl_DString *dsPtr, int length); /* 124 */\n    void (*tcl_DStringStartSublist) (Tcl_DString *dsPtr); /* 125 */\n    int (*tcl_Eof) (Tcl_Channel chan); /* 126 */\n    CONST84_RETURN char * (*tcl_ErrnoId) (void); /* 127 */\n    CONST84_RETURN char * (*tcl_ErrnoMsg) (int err); /* 128 */\n    int (*tcl_Eval) (Tcl_Interp *interp, const char *script); /* 129 */\n    int (*tcl_EvalFile) (Tcl_Interp *interp, const char *fileName); /* 130 */\n    int (*tcl_EvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 131 */\n    void (*tcl_EventuallyFree) (ClientData clientData, Tcl_FreeProc *freeProc); /* 132 */\n    TCL_NORETURN1 void (*tcl_Exit) (int status); /* 133 */\n    int (*tcl_ExposeCommand) (Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName); /* 134 */\n    int (*tcl_ExprBoolean) (Tcl_Interp *interp, const char *expr, int *ptr); /* 135 */\n    int (*tcl_ExprBooleanObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr); /* 136 */\n    int (*tcl_ExprDouble) (Tcl_Interp *interp, const char *expr, double *ptr); /* 137 */\n    int (*tcl_ExprDoubleObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr); /* 138 */\n    int (*tcl_ExprLong) (Tcl_Interp *interp, const char *expr, long *ptr); /* 139 */\n    int (*tcl_ExprLongObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr); /* 140 */\n    int (*tcl_ExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr); /* 141 */\n    int (*tcl_ExprString) (Tcl_Interp *interp, const char *expr); /* 142 */\n    void (*tcl_Finalize) (void); /* 143 */\n    void (*tcl_FindExecutable) (const char *argv0); /* 144 */\n    Tcl_HashEntry * (*tcl_FirstHashEntry) (Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr); /* 145 */\n    int (*tcl_Flush) (Tcl_Channel chan); /* 146 */\n    void (*tcl_FreeResult) (Tcl_Interp *interp); /* 147 */\n    int (*tcl_GetAlias) (Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *argcPtr, CONST84 char ***argvPtr); /* 148 */\n    int (*tcl_GetAliasObj) (Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv); /* 149 */\n    ClientData (*tcl_GetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc **procPtr); /* 150 */\n    Tcl_Channel (*tcl_GetChannel) (Tcl_Interp *interp, const char *chanName, int *modePtr); /* 151 */\n    int (*tcl_GetChannelBufferSize) (Tcl_Channel chan); /* 152 */\n    int (*tcl_GetChannelHandle) (Tcl_Channel chan, int direction, ClientData *handlePtr); /* 153 */\n    ClientData (*tcl_GetChannelInstanceData) (Tcl_Channel chan); /* 154 */\n    int (*tcl_GetChannelMode) (Tcl_Channel chan); /* 155 */\n    CONST84_RETURN char * (*tcl_GetChannelName) (Tcl_Channel chan); /* 156 */\n    int (*tcl_GetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, Tcl_DString *dsPtr); /* 157 */\n    CONST86 Tcl_ChannelType * (*tcl_GetChannelType) (Tcl_Channel chan); /* 158 */\n    int (*tcl_GetCommandInfo) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); /* 159 */\n    CONST84_RETURN char * (*tcl_GetCommandName) (Tcl_Interp *interp, Tcl_Command command); /* 160 */\n    int (*tcl_GetErrno) (void); /* 161 */\n    CONST84_RETURN char * (*tcl_GetHostName) (void); /* 162 */\n    int (*tcl_GetInterpPath) (Tcl_Interp *askInterp, Tcl_Interp *slaveInterp); /* 163 */\n    Tcl_Interp * (*tcl_GetMaster) (Tcl_Interp *interp); /* 164 */\n    const char * (*tcl_GetNameOfExecutable) (void); /* 165 */\n    Tcl_Obj * (*tcl_GetObjResult) (Tcl_Interp *interp); /* 166 */\n#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */\n    int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */\n#endif /* UNIX */\n#if defined(_WIN32) /* WIN */\n    void (*reserved167)(void);\n#endif /* WIN */\n#ifdef MAC_OSX_TCL /* MACOSX */\n    int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */\n#endif /* MACOSX */\n    Tcl_PathType (*tcl_GetPathType) (const char *path); /* 168 */\n    int (*tcl_Gets) (Tcl_Channel chan, Tcl_DString *dsPtr); /* 169 */\n    int (*tcl_GetsObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 170 */\n    int (*tcl_GetServiceMode) (void); /* 171 */\n    Tcl_Interp * (*tcl_GetSlave) (Tcl_Interp *interp, const char *slaveName); /* 172 */\n    Tcl_Channel (*tcl_GetStdChannel) (int type); /* 173 */\n    CONST84_RETURN char * (*tcl_GetStringResult) (Tcl_Interp *interp); /* 174 */\n    CONST84_RETURN char * (*tcl_GetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 175 */\n    CONST84_RETURN char * (*tcl_GetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 176 */\n    int (*tcl_GlobalEval) (Tcl_Interp *interp, const char *command); /* 177 */\n    int (*tcl_GlobalEvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 178 */\n    int (*tcl_HideCommand) (Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken); /* 179 */\n    int (*tcl_Init) (Tcl_Interp *interp); /* 180 */\n    void (*tcl_InitHashTable) (Tcl_HashTable *tablePtr, int keyType); /* 181 */\n    int (*tcl_InputBlocked) (Tcl_Channel chan); /* 182 */\n    int (*tcl_InputBuffered) (Tcl_Channel chan); /* 183 */\n    int (*tcl_InterpDeleted) (Tcl_Interp *interp); /* 184 */\n    int (*tcl_IsSafe) (Tcl_Interp *interp); /* 185 */\n    char * (*tcl_JoinPath) (int argc, CONST84 char *const *argv, Tcl_DString *resultPtr); /* 186 */\n    int (*tcl_LinkVar) (Tcl_Interp *interp, const char *varName, char *addr, int type); /* 187 */\n    void (*reserved188)(void);\n    Tcl_Channel (*tcl_MakeFileChannel) (ClientData handle, int mode); /* 189 */\n    int (*tcl_MakeSafe) (Tcl_Interp *interp); /* 190 */\n    Tcl_Channel (*tcl_MakeTcpClientChannel) (ClientData tcpSocket); /* 191 */\n    char * (*tcl_Merge) (int argc, CONST84 char *const *argv); /* 192 */\n    Tcl_HashEntry * (*tcl_NextHashEntry) (Tcl_HashSearch *searchPtr); /* 193 */\n    void (*tcl_NotifyChannel) (Tcl_Channel channel, int mask); /* 194 */\n    Tcl_Obj * (*tcl_ObjGetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags); /* 195 */\n    Tcl_Obj * (*tcl_ObjSetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); /* 196 */\n    Tcl_Channel (*tcl_OpenCommandChannel) (Tcl_Interp *interp, int argc, CONST84 char **argv, int flags); /* 197 */\n    Tcl_Channel (*tcl_OpenFileChannel) (Tcl_Interp *interp, const char *fileName, const char *modeString, int permissions); /* 198 */\n    Tcl_Channel (*tcl_OpenTcpClient) (Tcl_Interp *interp, int port, const char *address, const char *myaddr, int myport, int async); /* 199 */\n    Tcl_Channel (*tcl_OpenTcpServer) (Tcl_Interp *interp, int port, const char *host, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 200 */\n    void (*tcl_Preserve) (ClientData data); /* 201 */\n    void (*tcl_PrintDouble) (Tcl_Interp *interp, double value, char *dst); /* 202 */\n    int (*tcl_PutEnv) (const char *assignment); /* 203 */\n    CONST84_RETURN char * (*tcl_PosixError) (Tcl_Interp *interp); /* 204 */\n    void (*tcl_QueueEvent) (Tcl_Event *evPtr, Tcl_QueuePosition position); /* 205 */\n    int (*tcl_Read) (Tcl_Channel chan, char *bufPtr, int toRead); /* 206 */\n    void (*tcl_ReapDetachedProcs) (void); /* 207 */\n    int (*tcl_RecordAndEval) (Tcl_Interp *interp, const char *cmd, int flags); /* 208 */\n    int (*tcl_RecordAndEvalObj) (Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags); /* 209 */\n    void (*tcl_RegisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 210 */\n    void (*tcl_RegisterObjType) (const Tcl_ObjType *typePtr); /* 211 */\n    Tcl_RegExp (*tcl_RegExpCompile) (Tcl_Interp *interp, const char *pattern); /* 212 */\n    int (*tcl_RegExpExec) (Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start); /* 213 */\n    int (*tcl_RegExpMatch) (Tcl_Interp *interp, const char *text, const char *pattern); /* 214 */\n    void (*tcl_RegExpRange) (Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr); /* 215 */\n    void (*tcl_Release) (ClientData clientData); /* 216 */\n    void (*tcl_ResetResult) (Tcl_Interp *interp); /* 217 */\n    int (*tcl_ScanElement) (const char *src, int *flagPtr); /* 218 */\n    int (*tcl_ScanCountedElement) (const char *src, int length, int *flagPtr); /* 219 */\n    int (*tcl_SeekOld) (Tcl_Channel chan, int offset, int mode); /* 220 */\n    int (*tcl_ServiceAll) (void); /* 221 */\n    int (*tcl_ServiceEvent) (int flags); /* 222 */\n    void (*tcl_SetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 223 */\n    void (*tcl_SetChannelBufferSize) (Tcl_Channel chan, int sz); /* 224 */\n    int (*tcl_SetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue); /* 225 */\n    int (*tcl_SetCommandInfo) (Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr); /* 226 */\n    void (*tcl_SetErrno) (int err); /* 227 */\n    void (*tcl_SetErrorCode) (Tcl_Interp *interp, ...); /* 228 */\n    void (*tcl_SetMaxBlockTime) (const Tcl_Time *timePtr); /* 229 */\n    void (*tcl_SetPanicProc) (TCL_NORETURN1 Tcl_PanicProc *panicProc); /* 230 */\n    int (*tcl_SetRecursionLimit) (Tcl_Interp *interp, int depth); /* 231 */\n    void (*tcl_SetResult) (Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc); /* 232 */\n    int (*tcl_SetServiceMode) (int mode); /* 233 */\n    void (*tcl_SetObjErrorCode) (Tcl_Interp *interp, Tcl_Obj *errorObjPtr); /* 234 */\n    void (*tcl_SetObjResult) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr); /* 235 */\n    void (*tcl_SetStdChannel) (Tcl_Channel channel, int type); /* 236 */\n    CONST84_RETURN char * (*tcl_SetVar) (Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 237 */\n    CONST84_RETURN char * (*tcl_SetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags); /* 238 */\n    CONST84_RETURN char * (*tcl_SignalId) (int sig); /* 239 */\n    CONST84_RETURN char * (*tcl_SignalMsg) (int sig); /* 240 */\n    void (*tcl_SourceRCFile) (Tcl_Interp *interp); /* 241 */\n    int (*tcl_SplitList) (Tcl_Interp *interp, const char *listStr, int *argcPtr, CONST84 char ***argvPtr); /* 242 */\n    void (*tcl_SplitPath) (const char *path, int *argcPtr, CONST84 char ***argvPtr); /* 243 */\n    void (*tcl_StaticPackage) (Tcl_Interp *interp, const char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc); /* 244 */\n    int (*tcl_StringMatch) (const char *str, const char *pattern); /* 245 */\n    int (*tcl_TellOld) (Tcl_Channel chan); /* 246 */\n    int (*tcl_TraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 247 */\n    int (*tcl_TraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 248 */\n    char * (*tcl_TranslateFileName) (Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr); /* 249 */\n    int (*tcl_Ungets) (Tcl_Channel chan, const char *str, int len, int atHead); /* 250 */\n    void (*tcl_UnlinkVar) (Tcl_Interp *interp, const char *varName); /* 251 */\n    int (*tcl_UnregisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 252 */\n    int (*tcl_UnsetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 253 */\n    int (*tcl_UnsetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 254 */\n    void (*tcl_UntraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 255 */\n    void (*tcl_UntraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 256 */\n    void (*tcl_UpdateLinkedVar) (Tcl_Interp *interp, const char *varName); /* 257 */\n    int (*tcl_UpVar) (Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 258 */\n    int (*tcl_UpVar2) (Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags); /* 259 */\n    int (*tcl_VarEval) (Tcl_Interp *interp, ...); /* 260 */\n    ClientData (*tcl_VarTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 261 */\n    ClientData (*tcl_VarTraceInfo2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 262 */\n    int (*tcl_Write) (Tcl_Channel chan, const char *s, int slen); /* 263 */\n    void (*tcl_WrongNumArgs) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *message); /* 264 */\n    int (*tcl_DumpActiveMemory) (const char *fileName); /* 265 */\n    void (*tcl_ValidateAllMemory) (const char *file, int line); /* 266 */\n    void (*tcl_AppendResultVA) (Tcl_Interp *interp, va_list argList); /* 267 */\n    void (*tcl_AppendStringsToObjVA) (Tcl_Obj *objPtr, va_list argList); /* 268 */\n    char * (*tcl_HashStats) (Tcl_HashTable *tablePtr); /* 269 */\n    CONST84_RETURN char * (*tcl_ParseVar) (Tcl_Interp *interp, const char *start, CONST84 char **termPtr); /* 270 */\n    CONST84_RETURN char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */\n    CONST84_RETURN char * (*tcl_PkgPresentEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 272 */\n    int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */\n    CONST84_RETURN char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */\n    void (*tcl_SetErrorCodeVA) (Tcl_Interp *interp, va_list argList); /* 275 */\n    int (*tcl_VarEvalVA) (Tcl_Interp *interp, va_list argList); /* 276 */\n    Tcl_Pid (*tcl_WaitPid) (Tcl_Pid pid, int *statPtr, int options); /* 277 */\n    TCL_NORETURN1 void (*tcl_PanicVA) (const char *format, va_list argList); /* 278 */\n    void (*tcl_GetVersion) (int *major, int *minor, int *patchLevel, int *type); /* 279 */\n    void (*tcl_InitMemory) (Tcl_Interp *interp); /* 280 */\n    Tcl_Channel (*tcl_StackChannel) (Tcl_Interp *interp, const Tcl_ChannelType *typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan); /* 281 */\n    int (*tcl_UnstackChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 282 */\n    Tcl_Channel (*tcl_GetStackedChannel) (Tcl_Channel chan); /* 283 */\n    void (*tcl_SetMainLoop) (Tcl_MainLoopProc *proc); /* 284 */\n    void (*reserved285)(void);\n    void (*tcl_AppendObjToObj) (Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr); /* 286 */\n    Tcl_Encoding (*tcl_CreateEncoding) (const Tcl_EncodingType *typePtr); /* 287 */\n    void (*tcl_CreateThreadExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 288 */\n    void (*tcl_DeleteThreadExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 289 */\n    void (*tcl_DiscardResult) (Tcl_SavedResult *statePtr); /* 290 */\n    int (*tcl_EvalEx) (Tcl_Interp *interp, const char *script, int numBytes, int flags); /* 291 */\n    int (*tcl_EvalObjv) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 292 */\n    int (*tcl_EvalObjEx) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 293 */\n    void (*tcl_ExitThread) (int status); /* 294 */\n    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 */\n    char * (*tcl_ExternalToUtfDString) (Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 296 */\n    void (*tcl_FinalizeThread) (void); /* 297 */\n    void (*tcl_FinalizeNotifier) (ClientData clientData); /* 298 */\n    void (*tcl_FreeEncoding) (Tcl_Encoding encoding); /* 299 */\n    Tcl_ThreadId (*tcl_GetCurrentThread) (void); /* 300 */\n    Tcl_Encoding (*tcl_GetEncoding) (Tcl_Interp *interp, const char *name); /* 301 */\n    CONST84_RETURN char * (*tcl_GetEncodingName) (Tcl_Encoding encoding); /* 302 */\n    void (*tcl_GetEncodingNames) (Tcl_Interp *interp); /* 303 */\n    int (*tcl_GetIndexFromObjStruct) (Tcl_Interp *interp, Tcl_Obj *objPtr, const void *tablePtr, int offset, const char *msg, int flags, int *indexPtr); /* 304 */\n    void * (*tcl_GetThreadData) (Tcl_ThreadDataKey *keyPtr, int size); /* 305 */\n    Tcl_Obj * (*tcl_GetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 306 */\n    ClientData (*tcl_InitNotifier) (void); /* 307 */\n    void (*tcl_MutexLock) (Tcl_Mutex *mutexPtr); /* 308 */\n    void (*tcl_MutexUnlock) (Tcl_Mutex *mutexPtr); /* 309 */\n    void (*tcl_ConditionNotify) (Tcl_Condition *condPtr); /* 310 */\n    void (*tcl_ConditionWait) (Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); /* 311 */\n    int (*tcl_NumUtfChars) (const char *src, int length); /* 312 */\n    int (*tcl_ReadChars) (Tcl_Channel channel, Tcl_Obj *objPtr, int charsToRead, int appendFlag); /* 313 */\n    void (*tcl_RestoreResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 314 */\n    void (*tcl_SaveResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 315 */\n    int (*tcl_SetSystemEncoding) (Tcl_Interp *interp, const char *name); /* 316 */\n    Tcl_Obj * (*tcl_SetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, Tcl_Obj *newValuePtr, int flags); /* 317 */\n    void (*tcl_ThreadAlert) (Tcl_ThreadId threadId); /* 318 */\n    void (*tcl_ThreadQueueEvent) (Tcl_ThreadId threadId, Tcl_Event *evPtr, Tcl_QueuePosition position); /* 319 */\n    Tcl_UniChar (*tcl_UniCharAtIndex) (const char *src, int index); /* 320 */\n    Tcl_UniChar (*tcl_UniCharToLower) (int ch); /* 321 */\n    Tcl_UniChar (*tcl_UniCharToTitle) (int ch); /* 322 */\n    Tcl_UniChar (*tcl_UniCharToUpper) (int ch); /* 323 */\n    int (*tcl_UniCharToUtf) (int ch, char *buf); /* 324 */\n    CONST84_RETURN char * (*tcl_UtfAtIndex) (const char *src, int index); /* 325 */\n    int (*tcl_UtfCharComplete) (const char *src, int length); /* 326 */\n    int (*tcl_UtfBackslash) (const char *src, int *readPtr, char *dst); /* 327 */\n    CONST84_RETURN char * (*tcl_UtfFindFirst) (const char *src, int ch); /* 328 */\n    CONST84_RETURN char * (*tcl_UtfFindLast) (const char *src, int ch); /* 329 */\n    CONST84_RETURN char * (*tcl_UtfNext) (const char *src); /* 330 */\n    CONST84_RETURN char * (*tcl_UtfPrev) (const char *src, const char *start); /* 331 */\n    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 */\n    char * (*tcl_UtfToExternalDString) (Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 333 */\n    int (*tcl_UtfToLower) (char *src); /* 334 */\n    int (*tcl_UtfToTitle) (char *src); /* 335 */\n    int (*tcl_UtfToUniChar) (const char *src, Tcl_UniChar *chPtr); /* 336 */\n    int (*tcl_UtfToUpper) (char *src); /* 337 */\n    int (*tcl_WriteChars) (Tcl_Channel chan, const char *src, int srcLen); /* 338 */\n    int (*tcl_WriteObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 339 */\n    char * (*tcl_GetString) (Tcl_Obj *objPtr); /* 340 */\n    CONST84_RETURN char * (*tcl_GetDefaultEncodingDir) (void); /* 341 */\n    void (*tcl_SetDefaultEncodingDir) (const char *path); /* 342 */\n    void (*tcl_AlertNotifier) (ClientData clientData); /* 343 */\n    void (*tcl_ServiceModeHook) (int mode); /* 344 */\n    int (*tcl_UniCharIsAlnum) (int ch); /* 345 */\n    int (*tcl_UniCharIsAlpha) (int ch); /* 346 */\n    int (*tcl_UniCharIsDigit) (int ch); /* 347 */\n    int (*tcl_UniCharIsLower) (int ch); /* 348 */\n    int (*tcl_UniCharIsSpace) (int ch); /* 349 */\n    int (*tcl_UniCharIsUpper) (int ch); /* 350 */\n    int (*tcl_UniCharIsWordChar) (int ch); /* 351 */\n    int (*tcl_UniCharLen) (const Tcl_UniChar *uniStr); /* 352 */\n    int (*tcl_UniCharNcmp) (const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 353 */\n    char * (*tcl_UniCharToUtfDString) (const Tcl_UniChar *uniStr, int uniLength, Tcl_DString *dsPtr); /* 354 */\n    Tcl_UniChar * (*tcl_UtfToUniCharDString) (const char *src, int length, Tcl_DString *dsPtr); /* 355 */\n    Tcl_RegExp (*tcl_GetRegExpFromObj) (Tcl_Interp *interp, Tcl_Obj *patObj, int flags); /* 356 */\n    Tcl_Obj * (*tcl_EvalTokens) (Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 357 */\n    void (*tcl_FreeParse) (Tcl_Parse *parsePtr); /* 358 */\n    void (*tcl_LogCommandInfo) (Tcl_Interp *interp, const char *script, const char *command, int length); /* 359 */\n    int (*tcl_ParseBraces) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 360 */\n    int (*tcl_ParseCommand) (Tcl_Interp *interp, const char *start, int numBytes, int nested, Tcl_Parse *parsePtr); /* 361 */\n    int (*tcl_ParseExpr) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr); /* 362 */\n    int (*tcl_ParseQuotedString) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 363 */\n    int (*tcl_ParseVarName) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append); /* 364 */\n    char * (*tcl_GetCwd) (Tcl_Interp *interp, Tcl_DString *cwdPtr); /* 365 */\n    int (*tcl_Chdir) (const char *dirName); /* 366 */\n    int (*tcl_Access) (const char *path, int mode); /* 367 */\n    int (*tcl_Stat) (const char *path, struct stat *bufPtr); /* 368 */\n    int (*tcl_UtfNcmp) (const char *s1, const char *s2, unsigned long n); /* 369 */\n    int (*tcl_UtfNcasecmp) (const char *s1, const char *s2, unsigned long n); /* 370 */\n    int (*tcl_StringCaseMatch) (const char *str, const char *pattern, int nocase); /* 371 */\n    int (*tcl_UniCharIsControl) (int ch); /* 372 */\n    int (*tcl_UniCharIsGraph) (int ch); /* 373 */\n    int (*tcl_UniCharIsPrint) (int ch); /* 374 */\n    int (*tcl_UniCharIsPunct) (int ch); /* 375 */\n    int (*tcl_RegExpExecObj) (Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, int offset, int nmatches, int flags); /* 376 */\n    void (*tcl_RegExpGetInfo) (Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr); /* 377 */\n    Tcl_Obj * (*tcl_NewUnicodeObj) (const Tcl_UniChar *unicode, int numChars); /* 378 */\n    void (*tcl_SetUnicodeObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int numChars); /* 379 */\n    int (*tcl_GetCharLength) (Tcl_Obj *objPtr); /* 380 */\n    Tcl_UniChar (*tcl_GetUniChar) (Tcl_Obj *objPtr, int index); /* 381 */\n    Tcl_UniChar * (*tcl_GetUnicode) (Tcl_Obj *objPtr); /* 382 */\n    Tcl_Obj * (*tcl_GetRange) (Tcl_Obj *objPtr, int first, int last); /* 383 */\n    void (*tcl_AppendUnicodeToObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int length); /* 384 */\n    int (*tcl_RegExpMatchObj) (Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj); /* 385 */\n    void (*tcl_SetNotifier) (Tcl_NotifierProcs *notifierProcPtr); /* 386 */\n    Tcl_Mutex * (*tcl_GetAllocMutex) (void); /* 387 */\n    int (*tcl_GetChannelNames) (Tcl_Interp *interp); /* 388 */\n    int (*tcl_GetChannelNamesEx) (Tcl_Interp *interp, const char *pattern); /* 389 */\n    int (*tcl_ProcObjCmd) (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* 390 */\n    void (*tcl_ConditionFinalize) (Tcl_Condition *condPtr); /* 391 */\n    void (*tcl_MutexFinalize) (Tcl_Mutex *mutex); /* 392 */\n    int (*tcl_CreateThread) (Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, ClientData clientData, int stackSize, int flags); /* 393 */\n    int (*tcl_ReadRaw) (Tcl_Channel chan, char *dst, int bytesToRead); /* 394 */\n    int (*tcl_WriteRaw) (Tcl_Channel chan, const char *src, int srcLen); /* 395 */\n    Tcl_Channel (*tcl_GetTopChannel) (Tcl_Channel chan); /* 396 */\n    int (*tcl_ChannelBuffered) (Tcl_Channel chan); /* 397 */\n    CONST84_RETURN char * (*tcl_ChannelName) (const Tcl_ChannelType *chanTypePtr); /* 398 */\n    Tcl_ChannelTypeVersion (*tcl_ChannelVersion) (const Tcl_ChannelType *chanTypePtr); /* 399 */\n    Tcl_DriverBlockModeProc * (*tcl_ChannelBlockModeProc) (const Tcl_ChannelType *chanTypePtr); /* 400 */\n    Tcl_DriverCloseProc * (*tcl_ChannelCloseProc) (const Tcl_ChannelType *chanTypePtr); /* 401 */\n    Tcl_DriverClose2Proc * (*tcl_ChannelClose2Proc) (const Tcl_ChannelType *chanTypePtr); /* 402 */\n    Tcl_DriverInputProc * (*tcl_ChannelInputProc) (const Tcl_ChannelType *chanTypePtr); /* 403 */\n    Tcl_DriverOutputProc * (*tcl_ChannelOutputProc) (const Tcl_ChannelType *chanTypePtr); /* 404 */\n    Tcl_DriverSeekProc * (*tcl_ChannelSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 405 */\n    Tcl_DriverSetOptionProc * (*tcl_ChannelSetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 406 */\n    Tcl_DriverGetOptionProc * (*tcl_ChannelGetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 407 */\n    Tcl_DriverWatchProc * (*tcl_ChannelWatchProc) (const Tcl_ChannelType *chanTypePtr); /* 408 */\n    Tcl_DriverGetHandleProc * (*tcl_ChannelGetHandleProc) (const Tcl_ChannelType *chanTypePtr); /* 409 */\n    Tcl_DriverFlushProc * (*tcl_ChannelFlushProc) (const Tcl_ChannelType *chanTypePtr); /* 410 */\n    Tcl_DriverHandlerProc * (*tcl_ChannelHandlerProc) (const Tcl_ChannelType *chanTypePtr); /* 411 */\n    int (*tcl_JoinThread) (Tcl_ThreadId threadId, int *result); /* 412 */\n    int (*tcl_IsChannelShared) (Tcl_Channel channel); /* 413 */\n    int (*tcl_IsChannelRegistered) (Tcl_Interp *interp, Tcl_Channel channel); /* 414 */\n    void (*tcl_CutChannel) (Tcl_Channel channel); /* 415 */\n    void (*tcl_SpliceChannel) (Tcl_Channel channel); /* 416 */\n    void (*tcl_ClearChannelHandlers) (Tcl_Channel channel); /* 417 */\n    int (*tcl_IsChannelExisting) (const char *channelName); /* 418 */\n    int (*tcl_UniCharNcasecmp) (const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 419 */\n    int (*tcl_UniCharCaseMatch) (const Tcl_UniChar *uniStr, const Tcl_UniChar *uniPattern, int nocase); /* 420 */\n    Tcl_HashEntry * (*tcl_FindHashEntry) (Tcl_HashTable *tablePtr, const void *key); /* 421 */\n    Tcl_HashEntry * (*tcl_CreateHashEntry) (Tcl_HashTable *tablePtr, const void *key, int *newPtr); /* 422 */\n    void (*tcl_InitCustomHashTable) (Tcl_HashTable *tablePtr, int keyType, const Tcl_HashKeyType *typePtr); /* 423 */\n    void (*tcl_InitObjHashTable) (Tcl_HashTable *tablePtr); /* 424 */\n    ClientData (*tcl_CommandTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *procPtr, ClientData prevClientData); /* 425 */\n    int (*tcl_TraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 426 */\n    void (*tcl_UntraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 427 */\n    char * (*tcl_AttemptAlloc) (unsigned int size); /* 428 */\n    char * (*tcl_AttemptDbCkalloc) (unsigned int size, const char *file, int line); /* 429 */\n    char * (*tcl_AttemptRealloc) (char *ptr, unsigned int size); /* 430 */\n    char * (*tcl_AttemptDbCkrealloc) (char *ptr, unsigned int size, const char *file, int line); /* 431 */\n    int (*tcl_AttemptSetObjLength) (Tcl_Obj *objPtr, int length); /* 432 */\n    Tcl_ThreadId (*tcl_GetChannelThread) (Tcl_Channel channel); /* 433 */\n    Tcl_UniChar * (*tcl_GetUnicodeFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 434 */\n    int (*tcl_GetMathFuncInfo) (Tcl_Interp *interp, const char *name, int *numArgsPtr, Tcl_ValueType **argTypesPtr, Tcl_MathProc **procPtr, ClientData *clientDataPtr); /* 435 */\n    Tcl_Obj * (*tcl_ListMathFuncs) (Tcl_Interp *interp, const char *pattern); /* 436 */\n    Tcl_Obj * (*tcl_SubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 437 */\n    int (*tcl_DetachChannel) (Tcl_Interp *interp, Tcl_Channel channel); /* 438 */\n    int (*tcl_IsStandardChannel) (Tcl_Channel channel); /* 439 */\n    int (*tcl_FSCopyFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 440 */\n    int (*tcl_FSCopyDirectory) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); /* 441 */\n    int (*tcl_FSCreateDirectory) (Tcl_Obj *pathPtr); /* 442 */\n    int (*tcl_FSDeleteFile) (Tcl_Obj *pathPtr); /* 443 */\n    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 */\n    int (*tcl_FSMatchInDirectory) (Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); /* 445 */\n    Tcl_Obj * (*tcl_FSLink) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction); /* 446 */\n    int (*tcl_FSRemoveDirectory) (Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr); /* 447 */\n    int (*tcl_FSRenameFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 448 */\n    int (*tcl_FSLstat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 449 */\n    int (*tcl_FSUtime) (Tcl_Obj *pathPtr, struct utimbuf *tval); /* 450 */\n    int (*tcl_FSFileAttrsGet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 451 */\n    int (*tcl_FSFileAttrsSet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr); /* 452 */\n    const char *CONST86 * (*tcl_FSFileAttrStrings) (Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 453 */\n    int (*tcl_FSStat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 454 */\n    int (*tcl_FSAccess) (Tcl_Obj *pathPtr, int mode); /* 455 */\n    Tcl_Channel (*tcl_FSOpenFileChannel) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *modeString, int permissions); /* 456 */\n    Tcl_Obj * (*tcl_FSGetCwd) (Tcl_Interp *interp); /* 457 */\n    int (*tcl_FSChdir) (Tcl_Obj *pathPtr); /* 458 */\n    int (*tcl_FSConvertToPathType) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 459 */\n    Tcl_Obj * (*tcl_FSJoinPath) (Tcl_Obj *listObj, int elements); /* 460 */\n    Tcl_Obj * (*tcl_FSSplitPath) (Tcl_Obj *pathPtr, int *lenPtr); /* 461 */\n    int (*tcl_FSEqualPaths) (Tcl_Obj *firstPtr, Tcl_Obj *secondPtr); /* 462 */\n    Tcl_Obj * (*tcl_FSGetNormalizedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 463 */\n    Tcl_Obj * (*tcl_FSJoinToPath) (Tcl_Obj *pathPtr, int objc, Tcl_Obj *const objv[]); /* 464 */\n    ClientData (*tcl_FSGetInternalRep) (Tcl_Obj *pathPtr, const Tcl_Filesystem *fsPtr); /* 465 */\n    Tcl_Obj * (*tcl_FSGetTranslatedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 466 */\n    int (*tcl_FSEvalFile) (Tcl_Interp *interp, Tcl_Obj *fileName); /* 467 */\n    Tcl_Obj * (*tcl_FSNewNativePath) (const Tcl_Filesystem *fromFilesystem, ClientData clientData); /* 468 */\n    const void * (*tcl_FSGetNativePath) (Tcl_Obj *pathPtr); /* 469 */\n    Tcl_Obj * (*tcl_FSFileSystemInfo) (Tcl_Obj *pathPtr); /* 470 */\n    Tcl_Obj * (*tcl_FSPathSeparator) (Tcl_Obj *pathPtr); /* 471 */\n    Tcl_Obj * (*tcl_FSListVolumes) (void); /* 472 */\n    int (*tcl_FSRegister) (ClientData clientData, const Tcl_Filesystem *fsPtr); /* 473 */\n    int (*tcl_FSUnregister) (const Tcl_Filesystem *fsPtr); /* 474 */\n    ClientData (*tcl_FSData) (const Tcl_Filesystem *fsPtr); /* 475 */\n    const char * (*tcl_FSGetTranslatedStringPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 476 */\n    CONST86 Tcl_Filesystem * (*tcl_FSGetFileSystemForPath) (Tcl_Obj *pathPtr); /* 477 */\n    Tcl_PathType (*tcl_FSGetPathType) (Tcl_Obj *pathPtr); /* 478 */\n    int (*tcl_OutputBuffered) (Tcl_Channel chan); /* 479 */\n    void (*tcl_FSMountsChanged) (const Tcl_Filesystem *fsPtr); /* 480 */\n    int (*tcl_EvalTokensStandard) (Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 481 */\n    void (*tcl_GetTime) (Tcl_Time *timeBuf); /* 482 */\n    Tcl_Trace (*tcl_CreateObjTrace) (Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc *objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 483 */\n    int (*tcl_GetCommandInfoFromToken) (Tcl_Command token, Tcl_CmdInfo *infoPtr); /* 484 */\n    int (*tcl_SetCommandInfoFromToken) (Tcl_Command token, const Tcl_CmdInfo *infoPtr); /* 485 */\n    Tcl_Obj * (*tcl_DbNewWideIntObj) (Tcl_WideInt wideValue, const char *file, int line); /* 486 */\n    int (*tcl_GetWideIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr); /* 487 */\n    Tcl_Obj * (*tcl_NewWideIntObj) (Tcl_WideInt wideValue); /* 488 */\n    void (*tcl_SetWideIntObj) (Tcl_Obj *objPtr, Tcl_WideInt wideValue); /* 489 */\n    Tcl_StatBuf * (*tcl_AllocStatBuf) (void); /* 490 */\n    Tcl_WideInt (*tcl_Seek) (Tcl_Channel chan, Tcl_WideInt offset, int mode); /* 491 */\n    Tcl_WideInt (*tcl_Tell) (Tcl_Channel chan); /* 492 */\n    Tcl_DriverWideSeekProc * (*tcl_ChannelWideSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 493 */\n    int (*tcl_DictObjPut) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); /* 494 */\n    int (*tcl_DictObjGet) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); /* 495 */\n    int (*tcl_DictObjRemove) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); /* 496 */\n    int (*tcl_DictObjSize) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int *sizePtr); /* 497 */\n    int (*tcl_DictObjFirst) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 498 */\n    void (*tcl_DictObjNext) (Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 499 */\n    void (*tcl_DictObjDone) (Tcl_DictSearch *searchPtr); /* 500 */\n    int (*tcl_DictObjPutKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); /* 501 */\n    int (*tcl_DictObjRemoveKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv); /* 502 */\n    Tcl_Obj * (*tcl_NewDictObj) (void); /* 503 */\n    Tcl_Obj * (*tcl_DbNewDictObj) (const char *file, int line); /* 504 */\n    void (*tcl_RegisterConfig) (Tcl_Interp *interp, const char *pkgName, const Tcl_Config *configuration, const char *valEncoding); /* 505 */\n    Tcl_Namespace * (*tcl_CreateNamespace) (Tcl_Interp *interp, const char *name, ClientData clientData, Tcl_NamespaceDeleteProc *deleteProc); /* 506 */\n    void (*tcl_DeleteNamespace) (Tcl_Namespace *nsPtr); /* 507 */\n    int (*tcl_AppendExportList) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); /* 508 */\n    int (*tcl_Export) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int resetListFirst); /* 509 */\n    int (*tcl_Import) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int allowOverwrite); /* 510 */\n    int (*tcl_ForgetImport) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern); /* 511 */\n    Tcl_Namespace * (*tcl_GetCurrentNamespace) (Tcl_Interp *interp); /* 512 */\n    Tcl_Namespace * (*tcl_GetGlobalNamespace) (Tcl_Interp *interp); /* 513 */\n    Tcl_Namespace * (*tcl_FindNamespace) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 514 */\n    Tcl_Command (*tcl_FindCommand) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 515 */\n    Tcl_Command (*tcl_GetCommandFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 516 */\n    void (*tcl_GetCommandFullName) (Tcl_Interp *interp, Tcl_Command command, Tcl_Obj *objPtr); /* 517 */\n    int (*tcl_FSEvalFileEx) (Tcl_Interp *interp, Tcl_Obj *fileName, const char *encodingName); /* 518 */\n    Tcl_ExitProc * (*tcl_SetExitProc) (TCL_NORETURN1 Tcl_ExitProc *proc); /* 519 */\n    void (*tcl_LimitAddHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData, Tcl_LimitHandlerDeleteProc *deleteProc); /* 520 */\n    void (*tcl_LimitRemoveHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData); /* 521 */\n    int (*tcl_LimitReady) (Tcl_Interp *interp); /* 522 */\n    int (*tcl_LimitCheck) (Tcl_Interp *interp); /* 523 */\n    int (*tcl_LimitExceeded) (Tcl_Interp *interp); /* 524 */\n    void (*tcl_LimitSetCommands) (Tcl_Interp *interp, int commandLimit); /* 525 */\n    void (*tcl_LimitSetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 526 */\n    void (*tcl_LimitSetGranularity) (Tcl_Interp *interp, int type, int granularity); /* 527 */\n    int (*tcl_LimitTypeEnabled) (Tcl_Interp *interp, int type); /* 528 */\n    int (*tcl_LimitTypeExceeded) (Tcl_Interp *interp, int type); /* 529 */\n    void (*tcl_LimitTypeSet) (Tcl_Interp *interp, int type); /* 530 */\n    void (*tcl_LimitTypeReset) (Tcl_Interp *interp, int type); /* 531 */\n    int (*tcl_LimitGetCommands) (Tcl_Interp *interp); /* 532 */\n    void (*tcl_LimitGetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 533 */\n    int (*tcl_LimitGetGranularity) (Tcl_Interp *interp, int type); /* 534 */\n    Tcl_InterpState (*tcl_SaveInterpState) (Tcl_Interp *interp, int status); /* 535 */\n    int (*tcl_RestoreInterpState) (Tcl_Interp *interp, Tcl_InterpState state); /* 536 */\n    void (*tcl_DiscardInterpState) (Tcl_InterpState state); /* 537 */\n    int (*tcl_SetReturnOptions) (Tcl_Interp *interp, Tcl_Obj *options); /* 538 */\n    Tcl_Obj * (*tcl_GetReturnOptions) (Tcl_Interp *interp, int result); /* 539 */\n    int (*tcl_IsEnsemble) (Tcl_Command token); /* 540 */\n    Tcl_Command (*tcl_CreateEnsemble) (Tcl_Interp *interp, const char *name, Tcl_Namespace *namespacePtr, int flags); /* 541 */\n    Tcl_Command (*tcl_FindEnsemble) (Tcl_Interp *interp, Tcl_Obj *cmdNameObj, int flags); /* 542 */\n    int (*tcl_SetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *subcmdList); /* 543 */\n    int (*tcl_SetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *mapDict); /* 544 */\n    int (*tcl_SetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *unknownList); /* 545 */\n    int (*tcl_SetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int flags); /* 546 */\n    int (*tcl_GetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr); /* 547 */\n    int (*tcl_GetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr); /* 548 */\n    int (*tcl_GetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr); /* 549 */\n    int (*tcl_GetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 550 */\n    int (*tcl_GetEnsembleNamespace) (Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 551 */\n    void (*tcl_SetTimeProc) (Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, ClientData clientData); /* 552 */\n    void (*tcl_QueryTimeProc) (Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, ClientData *clientData); /* 553 */\n    Tcl_DriverThreadActionProc * (*tcl_ChannelThreadActionProc) (const Tcl_ChannelType *chanTypePtr); /* 554 */\n    Tcl_Obj * (*tcl_NewBignumObj) (mp_int *value); /* 555 */\n    Tcl_Obj * (*tcl_DbNewBignumObj) (mp_int *value, const char *file, int line); /* 556 */\n    void (*tcl_SetBignumObj) (Tcl_Obj *obj, mp_int *value); /* 557 */\n    int (*tcl_GetBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 558 */\n    int (*tcl_TakeBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 559 */\n    int (*tcl_TruncateChannel) (Tcl_Channel chan, Tcl_WideInt length); /* 560 */\n    Tcl_DriverTruncateProc * (*tcl_ChannelTruncateProc) (const Tcl_ChannelType *chanTypePtr); /* 561 */\n    void (*tcl_SetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj *msg); /* 562 */\n    void (*tcl_GetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj **msg); /* 563 */\n    void (*tcl_SetChannelError) (Tcl_Channel chan, Tcl_Obj *msg); /* 564 */\n    void (*tcl_GetChannelError) (Tcl_Channel chan, Tcl_Obj **msg); /* 565 */\n    int (*tcl_InitBignumFromDouble) (Tcl_Interp *interp, double initval, mp_int *toInit); /* 566 */\n    Tcl_Obj * (*tcl_GetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr); /* 567 */\n    int (*tcl_SetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); /* 568 */\n    int (*tcl_GetEncodingFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); /* 569 */\n    Tcl_Obj * (*tcl_GetEncodingSearchPath) (void); /* 570 */\n    int (*tcl_SetEncodingSearchPath) (Tcl_Obj *searchPath); /* 571 */\n    const char * (*tcl_GetEncodingNameFromEnvironment) (Tcl_DString *bufPtr); /* 572 */\n    int (*tcl_PkgRequireProc) (Tcl_Interp *interp, const char *name, int objc, Tcl_Obj *const objv[], void *clientDataPtr); /* 573 */\n    void (*tcl_AppendObjToErrorInfo) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 574 */\n    void (*tcl_AppendLimitedToObj) (Tcl_Obj *objPtr, const char *bytes, int length, int limit, const char *ellipsis); /* 575 */\n    Tcl_Obj * (*tcl_Format) (Tcl_Interp *interp, const char *format, int objc, Tcl_Obj *const objv[]); /* 576 */\n    int (*tcl_AppendFormatToObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *format, int objc, Tcl_Obj *const objv[]); /* 577 */\n    Tcl_Obj * (*tcl_ObjPrintf) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 578 */\n    void (*tcl_AppendPrintfToObj) (Tcl_Obj *objPtr, const char *format, ...) TCL_FORMAT_PRINTF(2, 3); /* 579 */\n    int (*tcl_CancelEval) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr, ClientData clientData, int flags); /* 580 */\n    int (*tcl_Canceled) (Tcl_Interp *interp, int flags); /* 581 */\n    int (*tcl_CreatePipe) (Tcl_Interp *interp, Tcl_Channel *rchan, Tcl_Channel *wchan, int flags); /* 582 */\n    Tcl_Command (*tcl_NRCreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 583 */\n    int (*tcl_NREvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 584 */\n    int (*tcl_NREvalObjv) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 585 */\n    int (*tcl_NRCmdSwap) (Tcl_Interp *interp, Tcl_Command cmd, int objc, Tcl_Obj *const objv[], int flags); /* 586 */\n    void (*tcl_NRAddCallback) (Tcl_Interp *interp, Tcl_NRPostProc *postProcPtr, ClientData data0, ClientData data1, ClientData data2, ClientData data3); /* 587 */\n    int (*tcl_NRCallObjProc) (Tcl_Interp *interp, Tcl_ObjCmdProc *objProc, ClientData clientData, int objc, Tcl_Obj *const objv[]); /* 588 */\n    unsigned (*tcl_GetFSDeviceFromStat) (const Tcl_StatBuf *statPtr); /* 589 */\n    unsigned (*tcl_GetFSInodeFromStat) (const Tcl_StatBuf *statPtr); /* 590 */\n    unsigned (*tcl_GetModeFromStat) (const Tcl_StatBuf *statPtr); /* 591 */\n    int (*tcl_GetLinkCountFromStat) (const Tcl_StatBuf *statPtr); /* 592 */\n    int (*tcl_GetUserIdFromStat) (const Tcl_StatBuf *statPtr); /* 593 */\n    int (*tcl_GetGroupIdFromStat) (const Tcl_StatBuf *statPtr); /* 594 */\n    int (*tcl_GetDeviceTypeFromStat) (const Tcl_StatBuf *statPtr); /* 595 */\n    Tcl_WideInt (*tcl_GetAccessTimeFromStat) (const Tcl_StatBuf *statPtr); /* 596 */\n    Tcl_WideInt (*tcl_GetModificationTimeFromStat) (const Tcl_StatBuf *statPtr); /* 597 */\n    Tcl_WideInt (*tcl_GetChangeTimeFromStat) (const Tcl_StatBuf *statPtr); /* 598 */\n    Tcl_WideUInt (*tcl_GetSizeFromStat) (const Tcl_StatBuf *statPtr); /* 599 */\n    Tcl_WideUInt (*tcl_GetBlocksFromStat) (const Tcl_StatBuf *statPtr); /* 600 */\n    unsigned (*tcl_GetBlockSizeFromStat) (const Tcl_StatBuf *statPtr); /* 601 */\n    int (*tcl_SetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *paramList); /* 602 */\n    int (*tcl_GetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **paramListPtr); /* 603 */\n    int (*tcl_ParseArgsObjv) (Tcl_Interp *interp, const Tcl_ArgvInfo *argTable, int *objcPtr, Tcl_Obj *const *objv, Tcl_Obj ***remObjv); /* 604 */\n    int (*tcl_GetErrorLine) (Tcl_Interp *interp); /* 605 */\n    void (*tcl_SetErrorLine) (Tcl_Interp *interp, int lineNum); /* 606 */\n    void (*tcl_TransferResult) (Tcl_Interp *sourceInterp, int result, Tcl_Interp *targetInterp); /* 607 */\n    int (*tcl_InterpActive) (Tcl_Interp *interp); /* 608 */\n    void (*tcl_BackgroundException) (Tcl_Interp *interp, int code); /* 609 */\n    int (*tcl_ZlibDeflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int level, Tcl_Obj *gzipHeaderDictObj); /* 610 */\n    int (*tcl_ZlibInflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int buffersize, Tcl_Obj *gzipHeaderDictObj); /* 611 */\n    unsigned int (*tcl_ZlibCRC32) (unsigned int crc, const unsigned char *buf, int len); /* 612 */\n    unsigned int (*tcl_ZlibAdler32) (unsigned int adler, const unsigned char *buf, int len); /* 613 */\n    int (*tcl_ZlibStreamInit) (Tcl_Interp *interp, int mode, int format, int level, Tcl_Obj *dictObj, Tcl_ZlibStream *zshandle); /* 614 */\n    Tcl_Obj * (*tcl_ZlibStreamGetCommandName) (Tcl_ZlibStream zshandle); /* 615 */\n    int (*tcl_ZlibStreamEof) (Tcl_ZlibStream zshandle); /* 616 */\n    int (*tcl_ZlibStreamChecksum) (Tcl_ZlibStream zshandle); /* 617 */\n    int (*tcl_ZlibStreamPut) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int flush); /* 618 */\n    int (*tcl_ZlibStreamGet) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int count); /* 619 */\n    int (*tcl_ZlibStreamClose) (Tcl_ZlibStream zshandle); /* 620 */\n    int (*tcl_ZlibStreamReset) (Tcl_ZlibStream zshandle); /* 621 */\n    void (*tcl_SetStartupScript) (Tcl_Obj *path, const char *encoding); /* 622 */\n    Tcl_Obj * (*tcl_GetStartupScript) (const char **encodingPtr); /* 623 */\n    int (*tcl_CloseEx) (Tcl_Interp *interp, Tcl_Channel chan, int flags); /* 624 */\n    int (*tcl_NRExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *resultPtr); /* 625 */\n    int (*tcl_NRSubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 626 */\n    int (*tcl_LoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *const symv[], int flags, void *procPtrs, Tcl_LoadHandle *handlePtr); /* 627 */\n    void * (*tcl_FindSymbol) (Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 628 */\n    int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */\n    void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */\n} TclStubs;\n\nextern const TclStubs *tclStubsPtr;\n\n#ifdef __cplusplus\n}\n#endif\n\n#if defined(USE_TCL_STUBS)\n\n/*\n * Inline function declarations:\n */\n\n#define Tcl_PkgProvideEx \\\n\t(tclStubsPtr->tcl_PkgProvideEx) /* 0 */\n#define Tcl_PkgRequireEx \\\n\t(tclStubsPtr->tcl_PkgRequireEx) /* 1 */\n#define Tcl_Panic \\\n\t(tclStubsPtr->tcl_Panic) /* 2 */\n#define Tcl_Alloc \\\n\t(tclStubsPtr->tcl_Alloc) /* 3 */\n#define Tcl_Free \\\n\t(tclStubsPtr->tcl_Free) /* 4 */\n#define Tcl_Realloc \\\n\t(tclStubsPtr->tcl_Realloc) /* 5 */\n#define Tcl_DbCkalloc \\\n\t(tclStubsPtr->tcl_DbCkalloc) /* 6 */\n#define Tcl_DbCkfree \\\n\t(tclStubsPtr->tcl_DbCkfree) /* 7 */\n#define Tcl_DbCkrealloc \\\n\t(tclStubsPtr->tcl_DbCkrealloc) /* 8 */\n#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */\n#define Tcl_CreateFileHandler \\\n\t(tclStubsPtr->tcl_CreateFileHandler) /* 9 */\n#endif /* UNIX */\n#ifdef MAC_OSX_TCL /* MACOSX */\n#define Tcl_CreateFileHandler \\\n\t(tclStubsPtr->tcl_CreateFileHandler) /* 9 */\n#endif /* MACOSX */\n#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */\n#define Tcl_DeleteFileHandler \\\n\t(tclStubsPtr->tcl_DeleteFileHandler) /* 10 */\n#endif /* UNIX */\n#ifdef MAC_OSX_TCL /* MACOSX */\n#define Tcl_DeleteFileHandler \\\n\t(tclStubsPtr->tcl_DeleteFileHandler) /* 10 */\n#endif /* MACOSX */\n#define Tcl_SetTimer \\\n\t(tclStubsPtr->tcl_SetTimer) /* 11 */\n#define Tcl_Sleep \\\n\t(tclStubsPtr->tcl_Sleep) /* 12 */\n#define Tcl_WaitForEvent \\\n\t(tclStubsPtr->tcl_WaitForEvent) /* 13 */\n#define Tcl_AppendAllObjTypes \\\n\t(tclStubsPtr->tcl_AppendAllObjTypes) /* 14 */\n#define Tcl_AppendStringsToObj \\\n\t(tclStubsPtr->tcl_AppendStringsToObj) /* 15 */\n#define Tcl_AppendToObj \\\n\t(tclStubsPtr->tcl_AppendToObj) /* 16 */\n#define Tcl_ConcatObj \\\n\t(tclStubsPtr->tcl_ConcatObj) /* 17 */\n#define Tcl_ConvertToType \\\n\t(tclStubsPtr->tcl_ConvertToType) /* 18 */\n#define Tcl_DbDecrRefCount \\\n\t(tclStubsPtr->tcl_DbDecrRefCount) /* 19 */\n#define Tcl_DbIncrRefCount \\\n\t(tclStubsPtr->tcl_DbIncrRefCount) /* 20 */\n#define Tcl_DbIsShared \\\n\t(tclStubsPtr->tcl_DbIsShared) /* 21 */\n#define Tcl_DbNewBooleanObj \\\n\t(tclStubsPtr->tcl_DbNewBooleanObj) /* 22 */\n#define Tcl_DbNewByteArrayObj \\\n\t(tclStubsPtr->tcl_DbNewByteArrayObj) /* 23 */\n#define Tcl_DbNewDoubleObj \\\n\t(tclStubsPtr->tcl_DbNewDoubleObj) /* 24 */\n#define Tcl_DbNewListObj \\\n\t(tclStubsPtr->tcl_DbNewListObj) /* 25 */\n#define Tcl_DbNewLongObj \\\n\t(tclStubsPtr->tcl_DbNewLongObj) /* 26 */\n#define Tcl_DbNewObj \\\n\t(tclStubsPtr->tcl_DbNewObj) /* 27 */\n#define Tcl_DbNewStringObj \\\n\t(tclStubsPtr->tcl_DbNewStringObj) /* 28 */\n#define Tcl_DuplicateObj \\\n\t(tclStubsPtr->tcl_DuplicateObj) /* 29 */\n#define TclFreeObj \\\n\t(tclStubsPtr->tclFreeObj) /* 30 */\n#define Tcl_GetBoolean \\\n\t(tclStubsPtr->tcl_GetBoolean) /* 31 */\n#define Tcl_GetBooleanFromObj \\\n\t(tclStubsPtr->tcl_GetBooleanFromObj) /* 32 */\n#define Tcl_GetByteArrayFromObj \\\n\t(tclStubsPtr->tcl_GetByteArrayFromObj) /* 33 */\n#define Tcl_GetDouble \\\n\t(tclStubsPtr->tcl_GetDouble) /* 34 */\n#define Tcl_GetDoubleFromObj \\\n\t(tclStubsPtr->tcl_GetDoubleFromObj) /* 35 */\n#define Tcl_GetIndexFromObj \\\n\t(tclStubsPtr->tcl_GetIndexFromObj) /* 36 */\n#define Tcl_GetInt \\\n\t(tclStubsPtr->tcl_GetInt) /* 37 */\n#define Tcl_GetIntFromObj \\\n\t(tclStubsPtr->tcl_GetIntFromObj) /* 38 */\n#define Tcl_GetLongFromObj \\\n\t(tclStubsPtr->tcl_GetLongFromObj) /* 39 */\n#define Tcl_GetObjType \\\n\t(tclStubsPtr->tcl_GetObjType) /* 40 */\n#define Tcl_GetStringFromObj \\\n\t(tclStubsPtr->tcl_GetStringFromObj) /* 41 */\n#define Tcl_InvalidateStringRep \\\n\t(tclStubsPtr->tcl_InvalidateStringRep) /* 42 */\n#define Tcl_ListObjAppendList \\\n\t(tclStubsPtr->tcl_ListObjAppendList) /* 43 */\n#define Tcl_ListObjAppendElement \\\n\t(tclStubsPtr->tcl_ListObjAppendElement) /* 44 */\n#define Tcl_ListObjGetElements \\\n\t(tclStubsPtr->tcl_ListObjGetElements) /* 45 */\n#define Tcl_ListObjIndex \\\n\t(tclStubsPtr->tcl_ListObjIndex) /* 46 */\n#define Tcl_ListObjLength \\\n\t(tclStubsPtr->tcl_ListObjLength) /* 47 */\n#define Tcl_ListObjReplace \\\n\t(tclStubsPtr->tcl_ListObjReplace) /* 48 */\n#define Tcl_NewBooleanObj \\\n\t(tclStubsPtr->tcl_NewBooleanObj) /* 49 */\n#define Tcl_NewByteArrayObj \\\n\t(tclStubsPtr->tcl_NewByteArrayObj) /* 50 */\n#define Tcl_NewDoubleObj \\\n\t(tclStubsPtr->tcl_NewDoubleObj) /* 51 */\n#define Tcl_NewIntObj \\\n\t(tclStubsPtr->tcl_NewIntObj) /* 52 */\n#define Tcl_NewListObj \\\n\t(tclStubsPtr->tcl_NewListObj) /* 53 */\n#define Tcl_NewLongObj \\\n\t(tclStubsPtr->tcl_NewLongObj) /* 54 */\n#define Tcl_NewObj \\\n\t(tclStubsPtr->tcl_NewObj) /* 55 */\n#define Tcl_NewStringObj \\\n\t(tclStubsPtr->tcl_NewStringObj) /* 56 */\n#define Tcl_SetBooleanObj \\\n\t(tclStubsPtr->tcl_SetBooleanObj) /* 57 */\n#define Tcl_SetByteArrayLength \\\n\t(tclStubsPtr->tcl_SetByteArrayLength) /* 58 */\n#define Tcl_SetByteArrayObj \\\n\t(tclStubsPtr->tcl_SetByteArrayObj) /* 59 */\n#define Tcl_SetDoubleObj \\\n\t(tclStubsPtr->tcl_SetDoubleObj) /* 60 */\n#define Tcl_SetIntObj \\\n\t(tclStubsPtr->tcl_SetIntObj) /* 61 */\n#define Tcl_SetListObj \\\n\t(tclStubsPtr->tcl_SetListObj) /* 62 */\n#define Tcl_SetLongObj \\\n\t(tclStubsPtr->tcl_SetLongObj) /* 63 */\n#define Tcl_SetObjLength \\\n\t(tclStubsPtr->tcl_SetObjLength) /* 64 */\n#define Tcl_SetStringObj \\\n\t(tclStubsPtr->tcl_SetStringObj) /* 65 */\n#define Tcl_AddErrorInfo \\\n\t(tclStubsPtr->tcl_AddErrorInfo) /* 66 */\n#define Tcl_AddObjErrorInfo \\\n\t(tclStubsPtr->tcl_AddObjErrorInfo) /* 67 */\n#define Tcl_AllowExceptions \\\n\t(tclStubsPtr->tcl_AllowExceptions) /* 68 */\n#define Tcl_AppendElement \\\n\t(tclStubsPtr->tcl_AppendElement) /* 69 */\n#define Tcl_AppendResult \\\n\t(tclStubsPtr->tcl_AppendResult) /* 70 */\n#define Tcl_AsyncCreate \\\n\t(tclStubsPtr->tcl_AsyncCreate) /* 71 */\n#define Tcl_AsyncDelete \\\n\t(tclStubsPtr->tcl_AsyncDelete) /* 72 */\n#define Tcl_AsyncInvoke \\\n\t(tclStubsPtr->tcl_AsyncInvoke) /* 73 */\n#define Tcl_AsyncMark \\\n\t(tclStubsPtr->tcl_AsyncMark) /* 74 */\n#define Tcl_AsyncReady \\\n\t(tclStubsPtr->tcl_AsyncReady) /* 75 */\n#define Tcl_BackgroundError \\\n\t(tclStubsPtr->tcl_BackgroundError) /* 76 */\n#define Tcl_Backslash \\\n\t(tclStubsPtr->tcl_Backslash) /* 77 */\n#define Tcl_BadChannelOption \\\n\t(tclStubsPtr->tcl_BadChannelOption) /* 78 */\n#define Tcl_CallWhenDeleted \\\n\t(tclStubsPtr->tcl_CallWhenDeleted) /* 79 */\n#define Tcl_CancelIdleCall \\\n\t(tclStubsPtr->tcl_CancelIdleCall) /* 80 */\n#define Tcl_Close \\\n\t(tclStubsPtr->tcl_Close) /* 81 */\n#define Tcl_CommandComplete \\\n\t(tclStubsPtr->tcl_CommandComplete) /* 82 */\n#define Tcl_Concat \\\n\t(tclStubsPtr->tcl_Concat) /* 83 */\n#define Tcl_ConvertElement \\\n\t(tclStubsPtr->tcl_ConvertElement) /* 84 */\n#define Tcl_ConvertCountedElement \\\n\t(tclStubsPtr->tcl_ConvertCountedElement) /* 85 */\n#define Tcl_CreateAlias \\\n\t(tclStubsPtr->tcl_CreateAlias) /* 86 */\n#define Tcl_CreateAliasObj \\\n\t(tclStubsPtr->tcl_CreateAliasObj) /* 87 */\n#define Tcl_CreateChannel \\\n\t(tclStubsPtr->tcl_CreateChannel) /* 88 */\n#define Tcl_CreateChannelHandler \\\n\t(tclStubsPtr->tcl_CreateChannelHandler) /* 89 */\n#define Tcl_CreateCloseHandler \\\n\t(tclStubsPtr->tcl_CreateCloseHandler) /* 90 */\n#define Tcl_CreateCommand \\\n\t(tclStubsPtr->tcl_CreateCommand) /* 91 */\n#define Tcl_CreateEventSource \\\n\t(tclStubsPtr->tcl_CreateEventSource) /* 92 */\n#define Tcl_CreateExitHandler \\\n\t(tclStubsPtr->tcl_CreateExitHandler) /* 93 */\n#define Tcl_CreateInterp \\\n\t(tclStubsPtr->tcl_CreateInterp) /* 94 */\n#define Tcl_CreateMathFunc \\\n\t(tclStubsPtr->tcl_CreateMathFunc) /* 95 */\n#define Tcl_CreateObjCommand \\\n\t(tclStubsPtr->tcl_CreateObjCommand) /* 96 */\n#define Tcl_CreateSlave \\\n\t(tclStubsPtr->tcl_CreateSlave) /* 97 */\n#define Tcl_CreateTimerHandler \\\n\t(tclStubsPtr->tcl_CreateTimerHandler) /* 98 */\n#define Tcl_CreateTrace \\\n\t(tclStubsPtr->tcl_CreateTrace) /* 99 */\n#define Tcl_DeleteAssocData \\\n\t(tclStubsPtr->tcl_DeleteAssocData) /* 100 */\n#define Tcl_DeleteChannelHandler \\\n\t(tclStubsPtr->tcl_DeleteChannelHandler) /* 101 */\n#define Tcl_DeleteCloseHandler \\\n\t(tclStubsPtr->tcl_DeleteCloseHandler) /* 102 */\n#define Tcl_DeleteCommand \\\n\t(tclStubsPtr->tcl_DeleteCommand) /* 103 */\n#define Tcl_DeleteCommandFromToken \\\n\t(tclStubsPtr->tcl_DeleteCommandFromToken) /* 104 */\n#define Tcl_DeleteEvents \\\n\t(tclStubsPtr->tcl_DeleteEvents) /* 105 */\n#define Tcl_DeleteEventSource \\\n\t(tclStubsPtr->tcl_DeleteEventSource) /* 106 */\n#define Tcl_DeleteExitHandler \\\n\t(tclStubsPtr->tcl_DeleteExitHandler) /* 107 */\n#define Tcl_DeleteHashEntry \\\n\t(tclStubsPtr->tcl_DeleteHashEntry) /* 108 */\n#define Tcl_DeleteHashTable \\\n\t(tclStubsPtr->tcl_DeleteHashTable) /* 109 */\n#define Tcl_DeleteInterp \\\n\t(tclStubsPtr->tcl_DeleteInterp) /* 110 */\n#define Tcl_DetachPids \\\n\t(tclStubsPtr->tcl_DetachPids) /* 111 */\n#define Tcl_DeleteTimerHandler \\\n\t(tclStubsPtr->tcl_DeleteTimerHandler) /* 112 */\n#define Tcl_DeleteTrace \\\n\t(tclStubsPtr->tcl_DeleteTrace) /* 113 */\n#define Tcl_DontCallWhenDeleted \\\n\t(tclStubsPtr->tcl_DontCallWhenDeleted) /* 114 */\n#define Tcl_DoOneEvent \\\n\t(tclStubsPtr->tcl_DoOneEvent) /* 115 */\n#define Tcl_DoWhenIdle \\\n\t(tclStubsPtr->tcl_DoWhenIdle) /* 116 */\n#define Tcl_DStringAppend \\\n\t(tclStubsPtr->tcl_DStringAppend) /* 117 */\n#define Tcl_DStringAppendElement \\\n\t(tclStubsPtr->tcl_DStringAppendElement) /* 118 */\n#define Tcl_DStringEndSublist \\\n\t(tclStubsPtr->tcl_DStringEndSublist) /* 119 */\n#define Tcl_DStringFree \\\n\t(tclStubsPtr->tcl_DStringFree) /* 120 */\n#define Tcl_DStringGetResult \\\n\t(tclStubsPtr->tcl_DStringGetResult) /* 121 */\n#define Tcl_DStringInit \\\n\t(tclStubsPtr->tcl_DStringInit) /* 122 */\n#define Tcl_DStringResult \\\n\t(tclStubsPtr->tcl_DStringResult) /* 123 */\n#define Tcl_DStringSetLength \\\n\t(tclStubsPtr->tcl_DStringSetLength) /* 124 */\n#define Tcl_DStringStartSublist \\\n\t(tclStubsPtr->tcl_DStringStartSublist) /* 125 */\n#define Tcl_Eof \\\n\t(tclStubsPtr->tcl_Eof) /* 126 */\n#define Tcl_ErrnoId \\\n\t(tclStubsPtr->tcl_ErrnoId) /* 127 */\n#define Tcl_ErrnoMsg \\\n\t(tclStubsPtr->tcl_ErrnoMsg) /* 128 */\n#define Tcl_Eval \\\n\t(tclStubsPtr->tcl_Eval) /* 129 */\n#define Tcl_EvalFile \\\n\t(tclStubsPtr->tcl_EvalFile) /* 130 */\n#define Tcl_EvalObj \\\n\t(tclStubsPtr->tcl_EvalObj) /* 131 */\n#define Tcl_EventuallyFree \\\n\t(tclStubsPtr->tcl_EventuallyFree) /* 132 */\n#define Tcl_Exit \\\n\t(tclStubsPtr->tcl_Exit) /* 133 */\n#define Tcl_ExposeCommand \\\n\t(tclStubsPtr->tcl_ExposeCommand) /* 134 */\n#define Tcl_ExprBoolean \\\n\t(tclStubsPtr->tcl_ExprBoolean) /* 135 */\n#define Tcl_ExprBooleanObj \\\n\t(tclStubsPtr->tcl_ExprBooleanObj) /* 136 */\n#define Tcl_ExprDouble \\\n\t(tclStubsPtr->tcl_ExprDouble) /* 137 */\n#define Tcl_ExprDoubleObj \\\n\t(tclStubsPtr->tcl_ExprDoubleObj) /* 138 */\n#define Tcl_ExprLong \\\n\t(tclStubsPtr->tcl_ExprLong) /* 139 */\n#define Tcl_ExprLongObj \\\n\t(tclStubsPtr->tcl_ExprLongObj) /* 140 */\n#define Tcl_ExprObj \\\n\t(tclStubsPtr->tcl_ExprObj) /* 141 */\n#define Tcl_ExprString \\\n\t(tclStubsPtr->tcl_ExprString) /* 142 */\n#define Tcl_Finalize \\\n\t(tclStubsPtr->tcl_Finalize) /* 143 */\n#define Tcl_FindExecutable \\\n\t(tclStubsPtr->tcl_FindExecutable) /* 144 */\n#define Tcl_FirstHashEntry \\\n\t(tclStubsPtr->tcl_FirstHashEntry) /* 145 */\n#define Tcl_Flush \\\n\t(tclStubsPtr->tcl_Flush) /* 146 */\n#define Tcl_FreeResult \\\n\t(tclStubsPtr->tcl_FreeResult) /* 147 */\n#define Tcl_GetAlias \\\n\t(tclStubsPtr->tcl_GetAlias) /* 148 */\n#define Tcl_GetAliasObj \\\n\t(tclStubsPtr->tcl_GetAliasObj) /* 149 */\n#define Tcl_GetAssocData \\\n\t(tclStubsPtr->tcl_GetAssocData) /* 150 */\n#define Tcl_GetChannel \\\n\t(tclStubsPtr->tcl_GetChannel) /* 151 */\n#define Tcl_GetChannelBufferSize \\\n\t(tclStubsPtr->tcl_GetChannelBufferSize) /* 152 */\n#define Tcl_GetChannelHandle \\\n\t(tclStubsPtr->tcl_GetChannelHandle) /* 153 */\n#define Tcl_GetChannelInstanceData \\\n\t(tclStubsPtr->tcl_GetChannelInstanceData) /* 154 */\n#define Tcl_GetChannelMode \\\n\t(tclStubsPtr->tcl_GetChannelMode) /* 155 */\n#define Tcl_GetChannelName \\\n\t(tclStubsPtr->tcl_GetChannelName) /* 156 */\n#define Tcl_GetChannelOption \\\n\t(tclStubsPtr->tcl_GetChannelOption) /* 157 */\n#define Tcl_GetChannelType \\\n\t(tclStubsPtr->tcl_GetChannelType) /* 158 */\n#define Tcl_GetCommandInfo \\\n\t(tclStubsPtr->tcl_GetCommandInfo) /* 159 */\n#define Tcl_GetCommandName \\\n\t(tclStubsPtr->tcl_GetCommandName) /* 160 */\n#define Tcl_GetErrno \\\n\t(tclStubsPtr->tcl_GetErrno) /* 161 */\n#define Tcl_GetHostName \\\n\t(tclStubsPtr->tcl_GetHostName) /* 162 */\n#define Tcl_GetInterpPath \\\n\t(tclStubsPtr->tcl_GetInterpPath) /* 163 */\n#define Tcl_GetMaster \\\n\t(tclStubsPtr->tcl_GetMaster) /* 164 */\n#define Tcl_GetNameOfExecutable \\\n\t(tclStubsPtr->tcl_GetNameOfExecutable) /* 165 */\n#define Tcl_GetObjResult \\\n\t(tclStubsPtr->tcl_GetObjResult) /* 166 */\n#if !defined(_WIN32) && !defined(MAC_OSX_TCL) /* UNIX */\n#define Tcl_GetOpenFile \\\n\t(tclStubsPtr->tcl_GetOpenFile) /* 167 */\n#endif /* UNIX */\n#ifdef MAC_OSX_TCL /* MACOSX */\n#define Tcl_GetOpenFile \\\n\t(tclStubsPtr->tcl_GetOpenFile) /* 167 */\n#endif /* MACOSX */\n#define Tcl_GetPathType \\\n\t(tclStubsPtr->tcl_GetPathType) /* 168 */\n#define Tcl_Gets \\\n\t(tclStubsPtr->tcl_Gets) /* 169 */\n#define Tcl_GetsObj \\\n\t(tclStubsPtr->tcl_GetsObj) /* 170 */\n#define Tcl_GetServiceMode \\\n\t(tclStubsPtr->tcl_GetServiceMode) /* 171 */\n#define Tcl_GetSlave \\\n\t(tclStubsPtr->tcl_GetSlave) /* 172 */\n#define Tcl_GetStdChannel \\\n\t(tclStubsPtr->tcl_GetStdChannel) /* 173 */\n#define Tcl_GetStringResult \\\n\t(tclStubsPtr->tcl_GetStringResult) /* 174 */\n#define Tcl_GetVar \\\n\t(tclStubsPtr->tcl_GetVar) /* 175 */\n#define Tcl_GetVar2 \\\n\t(tclStubsPtr->tcl_GetVar2) /* 176 */\n#define Tcl_GlobalEval \\\n\t(tclStubsPtr->tcl_GlobalEval) /* 177 */\n#define Tcl_GlobalEvalObj \\\n\t(tclStubsPtr->tcl_GlobalEvalObj) /* 178 */\n#define Tcl_HideCommand \\\n\t(tclStubsPtr->tcl_HideCommand) /* 179 */\n#define Tcl_Init \\\n\t(tclStubsPtr->tcl_Init) /* 180 */\n#define Tcl_InitHashTable \\\n\t(tclStubsPtr->tcl_InitHashTable) /* 181 */\n#define Tcl_InputBlocked \\\n\t(tclStubsPtr->tcl_InputBlocked) /* 182 */\n#define Tcl_InputBuffered \\\n\t(tclStubsPtr->tcl_InputBuffered) /* 183 */\n#define Tcl_InterpDeleted \\\n\t(tclStubsPtr->tcl_InterpDeleted) /* 184 */\n#define Tcl_IsSafe \\\n\t(tclStubsPtr->tcl_IsSafe) /* 185 */\n#define Tcl_JoinPath \\\n\t(tclStubsPtr->tcl_JoinPath) /* 186 */\n#define Tcl_LinkVar \\\n\t(tclStubsPtr->tcl_LinkVar) /* 187 */\n/* Slot 188 is reserved */\n#define Tcl_MakeFileChannel \\\n\t(tclStubsPtr->tcl_MakeFileChannel) /* 189 */\n#define Tcl_MakeSafe \\\n\t(tclStubsPtr->tcl_MakeSafe) /* 190 */\n#define Tcl_MakeTcpClientChannel \\\n\t(tclStubsPtr->tcl_MakeTcpClientChannel) /* 191 */\n#define Tcl_Merge \\\n\t(tclStubsPtr->tcl_Merge) /* 192 */\n#define Tcl_NextHashEntry \\\n\t(tclStubsPtr->tcl_NextHashEntry) /* 193 */\n#define Tcl_NotifyChannel \\\n\t(tclStubsPtr->tcl_NotifyChannel) /* 194 */\n#define Tcl_ObjGetVar2 \\\n\t(tclStubsPtr->tcl_ObjGetVar2) /* 195 */\n#define Tcl_ObjSetVar2 \\\n\t(tclStubsPtr->tcl_ObjSetVar2) /* 196 */\n#define Tcl_OpenCommandChannel \\\n\t(tclStubsPtr->tcl_OpenCommandChannel) /* 197 */\n#define Tcl_OpenFileChannel \\\n\t(tclStubsPtr->tcl_OpenFileChannel) /* 198 */\n#define Tcl_OpenTcpClient \\\n\t(tclStubsPtr->tcl_OpenTcpClient) /* 199 */\n#define Tcl_OpenTcpServer \\\n\t(tclStubsPtr->tcl_OpenTcpServer) /* 200 */\n#define Tcl_Preserve \\\n\t(tclStubsPtr->tcl_Preserve) /* 201 */\n#define Tcl_PrintDouble \\\n\t(tclStubsPtr->tcl_PrintDouble) /* 202 */\n#define Tcl_PutEnv \\\n\t(tclStubsPtr->tcl_PutEnv) /* 203 */\n#define Tcl_PosixError \\\n\t(tclStubsPtr->tcl_PosixError) /* 204 */\n#define Tcl_QueueEvent \\\n\t(tclStubsPtr->tcl_QueueEvent) /* 205 */\n#define Tcl_Read \\\n\t(tclStubsPtr->tcl_Read) /* 206 */\n#define Tcl_ReapDetachedProcs \\\n\t(tclStubsPtr->tcl_ReapDetachedProcs) /* 207 */\n#define Tcl_RecordAndEval \\\n\t(tclStubsPtr->tcl_RecordAndEval) /* 208 */\n#define Tcl_RecordAndEvalObj \\\n\t(tclStubsPtr->tcl_RecordAndEvalObj) /* 209 */\n#define Tcl_RegisterChannel \\\n\t(tclStubsPtr->tcl_RegisterChannel) /* 210 */\n#define Tcl_RegisterObjType \\\n\t(tclStubsPtr->tcl_RegisterObjType) /* 211 */\n#define Tcl_RegExpCompile \\\n\t(tclStubsPtr->tcl_RegExpCompile) /* 212 */\n#define Tcl_RegExpExec \\\n\t(tclStubsPtr->tcl_RegExpExec) /* 213 */\n#define Tcl_RegExpMatch \\\n\t(tclStubsPtr->tcl_RegExpMatch) /* 214 */\n#define Tcl_RegExpRange \\\n\t(tclStubsPtr->tcl_RegExpRange) /* 215 */\n#define Tcl_Release \\\n\t(tclStubsPtr->tcl_Release) /* 216 */\n#define Tcl_ResetResult \\\n\t(tclStubsPtr->tcl_ResetResult) /* 217 */\n#define Tcl_ScanElement \\\n\t(tclStubsPtr->tcl_ScanElement) /* 218 */\n#define Tcl_ScanCountedElement \\\n\t(tclStubsPtr->tcl_ScanCountedElement) /* 219 */\n#define Tcl_SeekOld \\\n\t(tclStubsPtr->tcl_SeekOld) /* 220 */\n#define Tcl_ServiceAll \\\n\t(tclStubsPtr->tcl_ServiceAll) /* 221 */\n#define Tcl_ServiceEvent \\\n\t(tclStubsPtr->tcl_ServiceEvent) /* 222 */\n#define Tcl_SetAssocData \\\n\t(tclStubsPtr->tcl_SetAssocData) /* 223 */\n#define Tcl_SetChannelBufferSize \\\n\t(tclStubsPtr->tcl_SetChannelBufferSize) /* 224 */\n#define Tcl_SetChannelOption \\\n\t(tclStubsPtr->tcl_SetChannelOption) /* 225 */\n#define Tcl_SetCommandInfo \\\n\t(tclStubsPtr->tcl_SetCommandInfo) /* 226 */\n#define Tcl_SetErrno \\\n\t(tclStubsPtr->tcl_SetErrno) /* 227 */\n#define Tcl_SetErrorCode \\\n\t(tclStubsPtr->tcl_SetErrorCode) /* 228 */\n#define Tcl_SetMaxBlockTime \\\n\t(tclStubsPtr->tcl_SetMaxBlockTime) /* 229 */\n#define Tcl_SetPanicProc \\\n\t(tclStubsPtr->tcl_SetPanicProc) /* 230 */\n#define Tcl_SetRecursionLimit \\\n\t(tclStubsPtr->tcl_SetRecursionLimit) /* 231 */\n#define Tcl_SetResult \\\n\t(tclStubsPtr->tcl_SetResult) /* 232 */\n#define Tcl_SetServiceMode \\\n\t(tclStubsPtr->tcl_SetServiceMode) /* 233 */\n#define Tcl_SetObjErrorCode \\\n\t(tclStubsPtr->tcl_SetObjErrorCode) /* 234 */\n#define Tcl_SetObjResult \\\n\t(tclStubsPtr->tcl_SetObjResult) /* 235 */\n#define Tcl_SetStdChannel \\\n\t(tclStubsPtr->tcl_SetStdChannel) /* 236 */\n#define Tcl_SetVar \\\n\t(tclStubsPtr->tcl_SetVar) /* 237 */\n#define Tcl_SetVar2 \\\n\t(tclStubsPtr->tcl_SetVar2) /* 238 */\n#define Tcl_SignalId \\\n\t(tclStubsPtr->tcl_SignalId) /* 239 */\n#define Tcl_SignalMsg \\\n\t(tclStubsPtr->tcl_SignalMsg) /* 240 */\n#define Tcl_SourceRCFile \\\n\t(tclStubsPtr->tcl_SourceRCFile) /* 241 */\n#define Tcl_SplitList \\\n\t(tclStubsPtr->tcl_SplitList) /* 242 */\n#define Tcl_SplitPath \\\n\t(tclStubsPtr->tcl_SplitPath) /* 243 */\n#define Tcl_StaticPackage \\\n\t(tclStubsPtr->tcl_StaticPackage) /* 244 */\n#define Tcl_StringMatch \\\n\t(tclStubsPtr->tcl_StringMatch) /* 245 */\n#define Tcl_TellOld \\\n\t(tclStubsPtr->tcl_TellOld) /* 246 */\n#define Tcl_TraceVar \\\n\t(tclStubsPtr->tcl_TraceVar) /* 247 */\n#define Tcl_TraceVar2 \\\n\t(tclStubsPtr->tcl_TraceVar2) /* 248 */\n#define Tcl_TranslateFileName \\\n\t(tclStubsPtr->tcl_TranslateFileName) /* 249 */\n#define Tcl_Ungets \\\n\t(tclStubsPtr->tcl_Ungets) /* 250 */\n#define Tcl_UnlinkVar \\\n\t(tclStubsPtr->tcl_UnlinkVar) /* 251 */\n#define Tcl_UnregisterChannel \\\n\t(tclStubsPtr->tcl_UnregisterChannel) /* 252 */\n#define Tcl_UnsetVar \\\n\t(tclStubsPtr->tcl_UnsetVar) /* 253 */\n#define Tcl_UnsetVar2 \\\n\t(tclStubsPtr->tcl_UnsetVar2) /* 254 */\n#define Tcl_UntraceVar \\\n\t(tclStubsPtr->tcl_UntraceVar) /* 255 */\n#define Tcl_UntraceVar2 \\\n\t(tclStubsPtr->tcl_UntraceVar2) /* 256 */\n#define Tcl_UpdateLinkedVar \\\n\t(tclStubsPtr->tcl_UpdateLinkedVar) /* 257 */\n#define Tcl_UpVar \\\n\t(tclStubsPtr->tcl_UpVar) /* 258 */\n#define Tcl_UpVar2 \\\n\t(tclStubsPtr->tcl_UpVar2) /* 259 */\n#define Tcl_VarEval \\\n\t(tclStubsPtr->tcl_VarEval) /* 260 */\n#define Tcl_VarTraceInfo \\\n\t(tclStubsPtr->tcl_VarTraceInfo) /* 261 */\n#define Tcl_VarTraceInfo2 \\\n\t(tclStubsPtr->tcl_VarTraceInfo2) /* 262 */\n#define Tcl_Write \\\n\t(tclStubsPtr->tcl_Write) /* 263 */\n#define Tcl_WrongNumArgs \\\n\t(tclStubsPtr->tcl_WrongNumArgs) /* 264 */\n#define Tcl_DumpActiveMemory \\\n\t(tclStubsPtr->tcl_DumpActiveMemory) /* 265 */\n#define Tcl_ValidateAllMemory \\\n\t(tclStubsPtr->tcl_ValidateAllMemory) /* 266 */\n#define Tcl_AppendResultVA \\\n\t(tclStubsPtr->tcl_AppendResultVA) /* 267 */\n#define Tcl_AppendStringsToObjVA \\\n\t(tclStubsPtr->tcl_AppendStringsToObjVA) /* 268 */\n#define Tcl_HashStats \\\n\t(tclStubsPtr->tcl_HashStats) /* 269 */\n#define Tcl_ParseVar \\\n\t(tclStubsPtr->tcl_ParseVar) /* 270 */\n#define Tcl_PkgPresent \\\n\t(tclStubsPtr->tcl_PkgPresent) /* 271 */\n#define Tcl_PkgPresentEx \\\n\t(tclStubsPtr->tcl_PkgPresentEx) /* 272 */\n#define Tcl_PkgProvide \\\n\t(tclStubsPtr->tcl_PkgProvide) /* 273 */\n#define Tcl_PkgRequire \\\n\t(tclStubsPtr->tcl_PkgRequire) /* 274 */\n#define Tcl_SetErrorCodeVA \\\n\t(tclStubsPtr->tcl_SetErrorCodeVA) /* 275 */\n#define Tcl_VarEvalVA \\\n\t(tclStubsPtr->tcl_VarEvalVA) /* 276 */\n#define Tcl_WaitPid \\\n\t(tclStubsPtr->tcl_WaitPid) /* 277 */\n#define Tcl_PanicVA \\\n\t(tclStubsPtr->tcl_PanicVA) /* 278 */\n#define Tcl_GetVersion \\\n\t(tclStubsPtr->tcl_GetVersion) /* 279 */\n#define Tcl_InitMemory \\\n\t(tclStubsPtr->tcl_InitMemory) /* 280 */\n#define Tcl_StackChannel \\\n\t(tclStubsPtr->tcl_StackChannel) /* 281 */\n#define Tcl_UnstackChannel \\\n\t(tclStubsPtr->tcl_UnstackChannel) /* 282 */\n#define Tcl_GetStackedChannel \\\n\t(tclStubsPtr->tcl_GetStackedChannel) /* 283 */\n#define Tcl_SetMainLoop \\\n\t(tclStubsPtr->tcl_SetMainLoop) /* 284 */\n/* Slot 285 is reserved */\n#define Tcl_AppendObjToObj \\\n\t(tclStubsPtr->tcl_AppendObjToObj) /* 286 */\n#define Tcl_CreateEncoding \\\n\t(tclStubsPtr->tcl_CreateEncoding) /* 287 */\n#define Tcl_CreateThreadExitHandler \\\n\t(tclStubsPtr->tcl_CreateThreadExitHandler) /* 288 */\n#define Tcl_DeleteThreadExitHandler \\\n\t(tclStubsPtr->tcl_DeleteThreadExitHandler) /* 289 */\n#define Tcl_DiscardResult \\\n\t(tclStubsPtr->tcl_DiscardResult) /* 290 */\n#define Tcl_EvalEx \\\n\t(tclStubsPtr->tcl_EvalEx) /* 291 */\n#define Tcl_EvalObjv \\\n\t(tclStubsPtr->tcl_EvalObjv) /* 292 */\n#define Tcl_EvalObjEx \\\n\t(tclStubsPtr->tcl_EvalObjEx) /* 293 */\n#define Tcl_ExitThread \\\n\t(tclStubsPtr->tcl_ExitThread) /* 294 */\n#define Tcl_ExternalToUtf \\\n\t(tclStubsPtr->tcl_ExternalToUtf) /* 295 */\n#define Tcl_ExternalToUtfDString \\\n\t(tclStubsPtr->tcl_ExternalToUtfDString) /* 296 */\n#define Tcl_FinalizeThread \\\n\t(tclStubsPtr->tcl_FinalizeThread) /* 297 */\n#define Tcl_FinalizeNotifier \\\n\t(tclStubsPtr->tcl_FinalizeNotifier) /* 298 */\n#define Tcl_FreeEncoding \\\n\t(tclStubsPtr->tcl_FreeEncoding) /* 299 */\n#define Tcl_GetCurrentThread \\\n\t(tclStubsPtr->tcl_GetCurrentThread) /* 300 */\n#define Tcl_GetEncoding \\\n\t(tclStubsPtr->tcl_GetEncoding) /* 301 */\n#define Tcl_GetEncodingName \\\n\t(tclStubsPtr->tcl_GetEncodingName) /* 302 */\n#define Tcl_GetEncodingNames \\\n\t(tclStubsPtr->tcl_GetEncodingNames) /* 303 */\n#define Tcl_GetIndexFromObjStruct \\\n\t(tclStubsPtr->tcl_GetIndexFromObjStruct) /* 304 */\n#define Tcl_GetThreadData \\\n\t(tclStubsPtr->tcl_GetThreadData) /* 305 */\n#define Tcl_GetVar2Ex \\\n\t(tclStubsPtr->tcl_GetVar2Ex) /* 306 */\n#define Tcl_InitNotifier \\\n\t(tclStubsPtr->tcl_InitNotifier) /* 307 */\n#define Tcl_MutexLock \\\n\t(tclStubsPtr->tcl_MutexLock) /* 308 */\n#define Tcl_MutexUnlock \\\n\t(tclStubsPtr->tcl_MutexUnlock) /* 309 */\n#define Tcl_ConditionNotify \\\n\t(tclStubsPtr->tcl_ConditionNotify) /* 310 */\n#define Tcl_ConditionWait \\\n\t(tclStubsPtr->tcl_ConditionWait) /* 311 */\n#define Tcl_NumUtfChars \\\n\t(tclStubsPtr->tcl_NumUtfChars) /* 312 */\n#define Tcl_ReadChars \\\n\t(tclStubsPtr->tcl_ReadChars) /* 313 */\n#define Tcl_RestoreResult \\\n\t(tclStubsPtr->tcl_RestoreResult) /* 314 */\n#define Tcl_SaveResult \\\n\t(tclStubsPtr->tcl_SaveResult) /* 315 */\n#define Tcl_SetSystemEncoding \\\n\t(tclStubsPtr->tcl_SetSystemEncoding) /* 316 */\n#define Tcl_SetVar2Ex \\\n\t(tclStubsPtr->tcl_SetVar2Ex) /* 317 */\n#define Tcl_ThreadAlert \\\n\t(tclStubsPtr->tcl_ThreadAlert) /* 318 */\n#define Tcl_ThreadQueueEvent \\\n\t(tclStubsPtr->tcl_ThreadQueueEvent) /* 319 */\n#define Tcl_UniCharAtIndex \\\n\t(tclStubsPtr->tcl_UniCharAtIndex) /* 320 */\n#define Tcl_UniCharToLower \\\n\t(tclStubsPtr->tcl_UniCharToLower) /* 321 */\n#define Tcl_UniCharToTitle \\\n\t(tclStubsPtr->tcl_UniCharToTitle) /* 322 */\n#define Tcl_UniCharToUpper \\\n\t(tclStubsPtr->tcl_UniCharToUpper) /* 323 */\n#define Tcl_UniCharToUtf \\\n\t(tclStubsPtr->tcl_UniCharToUtf) /* 324 */\n#define Tcl_UtfAtIndex \\\n\t(tclStubsPtr->tcl_UtfAtIndex) /* 325 */\n#define Tcl_UtfCharComplete \\\n\t(tclStubsPtr->tcl_UtfCharComplete) /* 326 */\n#define Tcl_UtfBackslash \\\n\t(tclStubsPtr->tcl_UtfBackslash) /* 327 */\n#define Tcl_UtfFindFirst \\\n\t(tclStubsPtr->tcl_UtfFindFirst) /* 328 */\n#define Tcl_UtfFindLast \\\n\t(tclStubsPtr->tcl_UtfFindLast) /* 329 */\n#define Tcl_UtfNext \\\n\t(tclStubsPtr->tcl_UtfNext) /* 330 */\n#define Tcl_UtfPrev \\\n\t(tclStubsPtr->tcl_UtfPrev) /* 331 */\n#define Tcl_UtfToExternal \\\n\t(tclStubsPtr->tcl_UtfToExternal) /* 332 */\n#define Tcl_UtfToExternalDString \\\n\t(tclStubsPtr->tcl_UtfToExternalDString) /* 333 */\n#define Tcl_UtfToLower \\\n\t(tclStubsPtr->tcl_UtfToLower) /* 334 */\n#define Tcl_UtfToTitle \\\n\t(tclStubsPtr->tcl_UtfToTitle) /* 335 */\n#define Tcl_UtfToUniChar \\\n\t(tclStubsPtr->tcl_UtfToUniChar) /* 336 */\n#define Tcl_UtfToUpper \\\n\t(tclStubsPtr->tcl_UtfToUpper) /* 337 */\n#define Tcl_WriteChars \\\n\t(tclStubsPtr->tcl_WriteChars) /* 338 */\n#define Tcl_WriteObj \\\n\t(tclStubsPtr->tcl_WriteObj) /* 339 */\n#define Tcl_GetString \\\n\t(tclStubsPtr->tcl_GetString) /* 340 */\n#define Tcl_GetDefaultEncodingDir \\\n\t(tclStubsPtr->tcl_GetDefaultEncodingDir) /* 341 */\n#define Tcl_SetDefaultEncodingDir \\\n\t(tclStubsPtr->tcl_SetDefaultEncodingDir) /* 342 */\n#define Tcl_AlertNotifier \\\n\t(tclStubsPtr->tcl_AlertNotifier) /* 343 */\n#define Tcl_ServiceModeHook \\\n\t(tclStubsPtr->tcl_ServiceModeHook) /* 344 */\n#define Tcl_UniCharIsAlnum \\\n\t(tclStubsPtr->tcl_UniCharIsAlnum) /* 345 */\n#define Tcl_UniCharIsAlpha \\\n\t(tclStubsPtr->tcl_UniCharIsAlpha) /* 346 */\n#define Tcl_UniCharIsDigit \\\n\t(tclStubsPtr->tcl_UniCharIsDigit) /* 347 */\n#define Tcl_UniCharIsLower \\\n\t(tclStubsPtr->tcl_UniCharIsLower) /* 348 */\n#define Tcl_UniCharIsSpace \\\n\t(tclStubsPtr->tcl_UniCharIsSpace) /* 349 */\n#define Tcl_UniCharIsUpper \\\n\t(tclStubsPtr->tcl_UniCharIsUpper) /* 350 */\n#define Tcl_UniCharIsWordChar \\\n\t(tclStubsPtr->tcl_UniCharIsWordChar) /* 351 */\n#define Tcl_UniCharLen \\\n\t(tclStubsPtr->tcl_UniCharLen) /* 352 */\n#define Tcl_UniCharNcmp \\\n\t(tclStubsPtr->tcl_UniCharNcmp) /* 353 */\n#define Tcl_UniCharToUtfDString \\\n\t(tclStubsPtr->tcl_UniCharToUtfDString) /* 354 */\n#define Tcl_UtfToUniCharDString \\\n\t(tclStubsPtr->tcl_UtfToUniCharDString) /* 355 */\n#define Tcl_GetRegExpFromObj \\\n\t(tclStubsPtr->tcl_GetRegExpFromObj) /* 356 */\n#define Tcl_EvalTokens \\\n\t(tclStubsPtr->tcl_EvalTokens) /* 357 */\n#define Tcl_FreeParse \\\n\t(tclStubsPtr->tcl_FreeParse) /* 358 */\n#define Tcl_LogCommandInfo \\\n\t(tclStubsPtr->tcl_LogCommandInfo) /* 359 */\n#define Tcl_ParseBraces \\\n\t(tclStubsPtr->tcl_ParseBraces) /* 360 */\n#define Tcl_ParseCommand \\\n\t(tclStubsPtr->tcl_ParseCommand) /* 361 */\n#define Tcl_ParseExpr \\\n\t(tclStubsPtr->tcl_ParseExpr) /* 362 */\n#define Tcl_ParseQuotedString \\\n\t(tclStubsPtr->tcl_ParseQuotedString) /* 363 */\n#define Tcl_ParseVarName \\\n\t(tclStubsPtr->tcl_ParseVarName) /* 364 */\n#define Tcl_GetCwd \\\n\t(tclStubsPtr->tcl_GetCwd) /* 365 */\n#define Tcl_Chdir \\\n\t(tclStubsPtr->tcl_Chdir) /* 366 */\n#define Tcl_Access \\\n\t(tclStubsPtr->tcl_Access) /* 367 */\n#define Tcl_Stat \\\n\t(tclStubsPtr->tcl_Stat) /* 368 */\n#define Tcl_UtfNcmp \\\n\t(tclStubsPtr->tcl_UtfNcmp) /* 369 */\n#define Tcl_UtfNcasecmp \\\n\t(tclStubsPtr->tcl_UtfNcasecmp) /* 370 */\n#define Tcl_StringCaseMatch \\\n\t(tclStubsPtr->tcl_StringCaseMatch) /* 371 */\n#define Tcl_UniCharIsControl \\\n\t(tclStubsPtr->tcl_UniCharIsControl) /* 372 */\n#define Tcl_UniCharIsGraph \\\n\t(tclStubsPtr->tcl_UniCharIsGraph) /* 373 */\n#define Tcl_UniCharIsPrint \\\n\t(tclStubsPtr->tcl_UniCharIsPrint) /* 374 */\n#define Tcl_UniCharIsPunct \\\n\t(tclStubsPtr->tcl_UniCharIsPunct) /* 375 */\n#define Tcl_RegExpExecObj \\\n\t(tclStubsPtr->tcl_RegExpExecObj) /* 376 */\n#define Tcl_RegExpGetInfo \\\n\t(tclStubsPtr->tcl_RegExpGetInfo) /* 377 */\n#define Tcl_NewUnicodeObj \\\n\t(tclStubsPtr->tcl_NewUnicodeObj) /* 378 */\n#define Tcl_SetUnicodeObj \\\n\t(tclStubsPtr->tcl_SetUnicodeObj) /* 379 */\n#define Tcl_GetCharLength \\\n\t(tclStubsPtr->tcl_GetCharLength) /* 380 */\n#define Tcl_GetUniChar \\\n\t(tclStubsPtr->tcl_GetUniChar) /* 381 */\n#define Tcl_GetUnicode \\\n\t(tclStubsPtr->tcl_GetUnicode) /* 382 */\n#define Tcl_GetRange \\\n\t(tclStubsPtr->tcl_GetRange) /* 383 */\n#define Tcl_AppendUnicodeToObj \\\n\t(tclStubsPtr->tcl_AppendUnicodeToObj) /* 384 */\n#define Tcl_RegExpMatchObj \\\n\t(tclStubsPtr->tcl_RegExpMatchObj) /* 385 */\n#define Tcl_SetNotifier \\\n\t(tclStubsPtr->tcl_SetNotifier) /* 386 */\n#define Tcl_GetAllocMutex \\\n\t(tclStubsPtr->tcl_GetAllocMutex) /* 387 */\n#define Tcl_GetChannelNames \\\n\t(tclStubsPtr->tcl_GetChannelNames) /* 388 */\n#define Tcl_GetChannelNamesEx \\\n\t(tclStubsPtr->tcl_GetChannelNamesEx) /* 389 */\n#define Tcl_ProcObjCmd \\\n\t(tclStubsPtr->tcl_ProcObjCmd) /* 390 */\n#define Tcl_ConditionFinalize \\\n\t(tclStubsPtr->tcl_ConditionFinalize) /* 391 */\n#define Tcl_MutexFinalize \\\n\t(tclStubsPtr->tcl_MutexFinalize) /* 392 */\n#define Tcl_CreateThread \\\n\t(tclStubsPtr->tcl_CreateThread) /* 393 */\n#define Tcl_ReadRaw \\\n\t(tclStubsPtr->tcl_ReadRaw) /* 394 */\n#define Tcl_WriteRaw \\\n\t(tclStubsPtr->tcl_WriteRaw) /* 395 */\n#define Tcl_GetTopChannel \\\n\t(tclStubsPtr->tcl_GetTopChannel) /* 396 */\n#define Tcl_ChannelBuffered \\\n\t(tclStubsPtr->tcl_ChannelBuffered) /* 397 */\n#define Tcl_ChannelName \\\n\t(tclStubsPtr->tcl_ChannelName) /* 398 */\n#define Tcl_ChannelVersion \\\n\t(tclStubsPtr->tcl_ChannelVersion) /* 399 */\n#define Tcl_ChannelBlockModeProc \\\n\t(tclStubsPtr->tcl_ChannelBlockModeProc) /* 400 */\n#define Tcl_ChannelCloseProc \\\n\t(tclStubsPtr->tcl_ChannelCloseProc) /* 401 */\n#define Tcl_ChannelClose2Proc \\\n\t(tclStubsPtr->tcl_ChannelClose2Proc) /* 402 */\n#define Tcl_ChannelInputProc \\\n\t(tclStubsPtr->tcl_ChannelInputProc) /* 403 */\n#define Tcl_ChannelOutputProc \\\n\t(tclStubsPtr->tcl_ChannelOutputProc) /* 404 */\n#define Tcl_ChannelSeekProc \\\n\t(tclStubsPtr->tcl_ChannelSeekProc) /* 405 */\n#define Tcl_ChannelSetOptionProc \\\n\t(tclStubsPtr->tcl_ChannelSetOptionProc) /* 406 */\n#define Tcl_ChannelGetOptionProc \\\n\t(tclStubsPtr->tcl_ChannelGetOptionProc) /* 407 */\n#define Tcl_ChannelWatchProc \\\n\t(tclStubsPtr->tcl_ChannelWatchProc) /* 408 */\n#define Tcl_ChannelGetHandleProc \\\n\t(tclStubsPtr->tcl_ChannelGetHandleProc) /* 409 */\n#define Tcl_ChannelFlushProc \\\n\t(tclStubsPtr->tcl_ChannelFlushProc) /* 410 */\n#define Tcl_ChannelHandlerProc \\\n\t(tclStubsPtr->tcl_ChannelHandlerProc) /* 411 */\n#define Tcl_JoinThread \\\n\t(tclStubsPtr->tcl_JoinThread) /* 412 */\n#define Tcl_IsChannelShared \\\n\t(tclStubsPtr->tcl_IsChannelShared) /* 413 */\n#define Tcl_IsChannelRegistered \\\n\t(tclStubsPtr->tcl_IsChannelRegistered) /* 414 */\n#define Tcl_CutChannel \\\n\t(tclStubsPtr->tcl_CutChannel) /* 415 */\n#define Tcl_SpliceChannel \\\n\t(tclStubsPtr->tcl_SpliceChannel) /* 416 */\n#define Tcl_ClearChannelHandlers \\\n\t(tclStubsPtr->tcl_ClearChannelHandlers) /* 417 */\n#define Tcl_IsChannelExisting \\\n\t(tclStubsPtr->tcl_IsChannelExisting) /* 418 */\n#define Tcl_UniCharNcasecmp \\\n\t(tclStubsPtr->tcl_UniCharNcasecmp) /* 419 */\n#define Tcl_UniCharCaseMatch \\\n\t(tclStubsPtr->tcl_UniCharCaseMatch) /* 420 */\n#define Tcl_FindHashEntry \\\n\t(tclStubsPtr->tcl_FindHashEntry) /* 421 */\n#define Tcl_CreateHashEntry \\\n\t(tclStubsPtr->tcl_CreateHashEntry) /* 422 */\n#define Tcl_InitCustomHashTable \\\n\t(tclStubsPtr->tcl_InitCustomHashTable) /* 423 */\n#define Tcl_InitObjHashTable \\\n\t(tclStubsPtr->tcl_InitObjHashTable) /* 424 */\n#define Tcl_CommandTraceInfo \\\n\t(tclStubsPtr->tcl_CommandTraceInfo) /* 425 */\n#define Tcl_TraceCommand \\\n\t(tclStubsPtr->tcl_TraceCommand) /* 426 */\n#define Tcl_UntraceCommand \\\n\t(tclStubsPtr->tcl_UntraceCommand) /* 427 */\n#define Tcl_AttemptAlloc \\\n\t(tclStubsPtr->tcl_AttemptAlloc) /* 428 */\n#define Tcl_AttemptDbCkalloc \\\n\t(tclStubsPtr->tcl_AttemptDbCkalloc) /* 429 */\n#define Tcl_AttemptRealloc \\\n\t(tclStubsPtr->tcl_AttemptRealloc) /* 430 */\n#define Tcl_AttemptDbCkrealloc \\\n\t(tclStubsPtr->tcl_AttemptDbCkrealloc) /* 431 */\n#define Tcl_AttemptSetObjLength \\\n\t(tclStubsPtr->tcl_AttemptSetObjLength) /* 432 */\n#define Tcl_GetChannelThread \\\n\t(tclStubsPtr->tcl_GetChannelThread) /* 433 */\n#define Tcl_GetUnicodeFromObj \\\n\t(tclStubsPtr->tcl_GetUnicodeFromObj) /* 434 */\n#define Tcl_GetMathFuncInfo \\\n\t(tclStubsPtr->tcl_GetMathFuncInfo) /* 435 */\n#define Tcl_ListMathFuncs \\\n\t(tclStubsPtr->tcl_ListMathFuncs) /* 436 */\n#define Tcl_SubstObj \\\n\t(tclStubsPtr->tcl_SubstObj) /* 437 */\n#define Tcl_DetachChannel \\\n\t(tclStubsPtr->tcl_DetachChannel) /* 438 */\n#define Tcl_IsStandardChannel \\\n\t(tclStubsPtr->tcl_IsStandardChannel) /* 439 */\n#define Tcl_FSCopyFile \\\n\t(tclStubsPtr->tcl_FSCopyFile) /* 440 */\n#define Tcl_FSCopyDirectory \\\n\t(tclStubsPtr->tcl_FSCopyDirectory) /* 441 */\n#define Tcl_FSCreateDirectory \\\n\t(tclStubsPtr->tcl_FSCreateDirectory) /* 442 */\n#define Tcl_FSDeleteFile \\\n\t(tclStubsPtr->tcl_FSDeleteFile) /* 443 */\n#define Tcl_FSLoadFile \\\n\t(tclStubsPtr->tcl_FSLoadFile) /* 444 */\n#define Tcl_FSMatchInDirectory \\\n\t(tclStubsPtr->tcl_FSMatchInDirectory) /* 445 */\n#define Tcl_FSLink \\\n\t(tclStubsPtr->tcl_FSLink) /* 446 */\n#define Tcl_FSRemoveDirectory \\\n\t(tclStubsPtr->tcl_FSRemoveDirectory) /* 447 */\n#define Tcl_FSRenameFile \\\n\t(tclStubsPtr->tcl_FSRenameFile) /* 448 */\n#define Tcl_FSLstat \\\n\t(tclStubsPtr->tcl_FSLstat) /* 449 */\n#define Tcl_FSUtime \\\n\t(tclStubsPtr->tcl_FSUtime) /* 450 */\n#define Tcl_FSFileAttrsGet \\\n\t(tclStubsPtr->tcl_FSFileAttrsGet) /* 451 */\n#define Tcl_FSFileAttrsSet \\\n\t(tclStubsPtr->tcl_FSFileAttrsSet) /* 452 */\n#define Tcl_FSFileAttrStrings \\\n\t(tclStubsPtr->tcl_FSFileAttrStrings) /* 453 */\n#define Tcl_FSStat \\\n\t(tclStubsPtr->tcl_FSStat) /* 454 */\n#define Tcl_FSAccess \\\n\t(tclStubsPtr->tcl_FSAccess) /* 455 */\n#define Tcl_FSOpenFileChannel \\\n\t(tclStubsPtr->tcl_FSOpenFileChannel) /* 456 */\n#define Tcl_FSGetCwd \\\n\t(tclStubsPtr->tcl_FSGetCwd) /* 457 */\n#define Tcl_FSChdir \\\n\t(tclStubsPtr->tcl_FSChdir) /* 458 */\n#define Tcl_FSConvertToPathType \\\n\t(tclStubsPtr->tcl_FSConvertToPathType) /* 459 */\n#define Tcl_FSJoinPath \\\n\t(tclStubsPtr->tcl_FSJoinPath) /* 460 */\n#define Tcl_FSSplitPath \\\n\t(tclStubsPtr->tcl_FSSplitPath) /* 461 */\n#define Tcl_FSEqualPaths \\\n\t(tclStubsPtr->tcl_FSEqualPaths) /* 462 */\n#define Tcl_FSGetNormalizedPath \\\n\t(tclStubsPtr->tcl_FSGetNormalizedPath) /* 463 */\n#define Tcl_FSJoinToPath \\\n\t(tclStubsPtr->tcl_FSJoinToPath) /* 464 */\n#define Tcl_FSGetInternalRep \\\n\t(tclStubsPtr->tcl_FSGetInternalRep) /* 465 */\n#define Tcl_FSGetTranslatedPath \\\n\t(tclStubsPtr->tcl_FSGetTranslatedPath) /* 466 */\n#define Tcl_FSEvalFile \\\n\t(tclStubsPtr->tcl_FSEvalFile) /* 467 */\n#define Tcl_FSNewNativePath \\\n\t(tclStubsPtr->tcl_FSNewNativePath) /* 468 */\n#define Tcl_FSGetNativePath \\\n\t(tclStubsPtr->tcl_FSGetNativePath) /* 469 */\n#define Tcl_FSFileSystemInfo \\\n\t(tclStubsPtr->tcl_FSFileSystemInfo) /* 470 */\n#define Tcl_FSPathSeparator \\\n\t(tclStubsPtr->tcl_FSPathSeparator) /* 471 */\n#define Tcl_FSListVolumes \\\n\t(tclStubsPtr->tcl_FSListVolumes) /* 472 */\n#define Tcl_FSRegister \\\n\t(tclStubsPtr->tcl_FSRegister) /* 473 */\n#define Tcl_FSUnregister \\\n\t(tclStubsPtr->tcl_FSUnregister) /* 474 */\n#define Tcl_FSData \\\n\t(tclStubsPtr->tcl_FSData) /* 475 */\n#define Tcl_FSGetTranslatedStringPath \\\n\t(tclStubsPtr->tcl_FSGetTranslatedStringPath) /* 476 */\n#define Tcl_FSGetFileSystemForPath \\\n\t(tclStubsPtr->tcl_FSGetFileSystemForPath) /* 477 */\n#define Tcl_FSGetPathType \\\n\t(tclStubsPtr->tcl_FSGetPathType) /* 478 */\n#define Tcl_OutputBuffered \\\n\t(tclStubsPtr->tcl_OutputBuffered) /* 479 */\n#define Tcl_FSMountsChanged \\\n\t(tclStubsPtr->tcl_FSMountsChanged) /* 480 */\n#define Tcl_EvalTokensStandard \\\n\t(tclStubsPtr->tcl_EvalTokensStandard) /* 481 */\n#define Tcl_GetTime \\\n\t(tclStubsPtr->tcl_GetTime) /* 482 */\n#define Tcl_CreateObjTrace \\\n\t(tclStubsPtr->tcl_CreateObjTrace) /* 483 */\n#define Tcl_GetCommandInfoFromToken \\\n\t(tclStubsPtr->tcl_GetCommandInfoFromToken) /* 484 */\n#define Tcl_SetCommandInfoFromToken \\\n\t(tclStubsPtr->tcl_SetCommandInfoFromToken) /* 485 */\n#define Tcl_DbNewWideIntObj \\\n\t(tclStubsPtr->tcl_DbNewWideIntObj) /* 486 */\n#define Tcl_GetWideIntFromObj \\\n\t(tclStubsPtr->tcl_GetWideIntFromObj) /* 487 */\n#define Tcl_NewWideIntObj \\\n\t(tclStubsPtr->tcl_NewWideIntObj) /* 488 */\n#define Tcl_SetWideIntObj \\\n\t(tclStubsPtr->tcl_SetWideIntObj) /* 489 */\n#define Tcl_AllocStatBuf \\\n\t(tclStubsPtr->tcl_AllocStatBuf) /* 490 */\n#define Tcl_Seek \\\n\t(tclStubsPtr->tcl_Seek) /* 491 */\n#define Tcl_Tell \\\n\t(tclStubsPtr->tcl_Tell) /* 492 */\n#define Tcl_ChannelWideSeekProc \\\n\t(tclStubsPtr->tcl_ChannelWideSeekProc) /* 493 */\n#define Tcl_DictObjPut \\\n\t(tclStubsPtr->tcl_DictObjPut) /* 494 */\n#define Tcl_DictObjGet \\\n\t(tclStubsPtr->tcl_DictObjGet) /* 495 */\n#define Tcl_DictObjRemove \\\n\t(tclStubsPtr->tcl_DictObjRemove) /* 496 */\n#define Tcl_DictObjSize \\\n\t(tclStubsPtr->tcl_DictObjSize) /* 497 */\n#define Tcl_DictObjFirst \\\n\t(tclStubsPtr->tcl_DictObjFirst) /* 498 */\n#define Tcl_DictObjNext \\\n\t(tclStubsPtr->tcl_DictObjNext) /* 499 */\n#define Tcl_DictObjDone \\\n\t(tclStubsPtr->tcl_DictObjDone) /* 500 */\n#define Tcl_DictObjPutKeyList \\\n\t(tclStubsPtr->tcl_DictObjPutKeyList) /* 501 */\n#define Tcl_DictObjRemoveKeyList \\\n\t(tclStubsPtr->tcl_DictObjRemoveKeyList) /* 502 */\n#define Tcl_NewDictObj \\\n\t(tclStubsPtr->tcl_NewDictObj) /* 503 */\n#define Tcl_DbNewDictObj \\\n\t(tclStubsPtr->tcl_DbNewDictObj) /* 504 */\n#define Tcl_RegisterConfig \\\n\t(tclStubsPtr->tcl_RegisterConfig) /* 505 */\n#define Tcl_CreateNamespace \\\n\t(tclStubsPtr->tcl_CreateNamespace) /* 506 */\n#define Tcl_DeleteNamespace \\\n\t(tclStubsPtr->tcl_DeleteNamespace) /* 507 */\n#define Tcl_AppendExportList \\\n\t(tclStubsPtr->tcl_AppendExportList) /* 508 */\n#define Tcl_Export \\\n\t(tclStubsPtr->tcl_Export) /* 509 */\n#define Tcl_Import \\\n\t(tclStubsPtr->tcl_Import) /* 510 */\n#define Tcl_ForgetImport \\\n\t(tclStubsPtr->tcl_ForgetImport) /* 511 */\n#define Tcl_GetCurrentNamespace \\\n\t(tclStubsPtr->tcl_GetCurrentNamespace) /* 512 */\n#define Tcl_GetGlobalNamespace \\\n\t(tclStubsPtr->tcl_GetGlobalNamespace) /* 513 */\n#define Tcl_FindNamespace \\\n\t(tclStubsPtr->tcl_FindNamespace) /* 514 */\n#define Tcl_FindCommand \\\n\t(tclStubsPtr->tcl_FindCommand) /* 515 */\n#define Tcl_GetCommandFromObj \\\n\t(tclStubsPtr->tcl_GetCommandFromObj) /* 516 */\n#define Tcl_GetCommandFullName \\\n\t(tclStubsPtr->tcl_GetCommandFullName) /* 517 */\n#define Tcl_FSEvalFileEx \\\n\t(tclStubsPtr->tcl_FSEvalFileEx) /* 518 */\n#define Tcl_SetExitProc \\\n\t(tclStubsPtr->tcl_SetExitProc) /* 519 */\n#define Tcl_LimitAddHandler \\\n\t(tclStubsPtr->tcl_LimitAddHandler) /* 520 */\n#define Tcl_LimitRemoveHandler \\\n\t(tclStubsPtr->tcl_LimitRemoveHandler) /* 521 */\n#define Tcl_LimitReady \\\n\t(tclStubsPtr->tcl_LimitReady) /* 522 */\n#define Tcl_LimitCheck \\\n\t(tclStubsPtr->tcl_LimitCheck) /* 523 */\n#define Tcl_LimitExceeded \\\n\t(tclStubsPtr->tcl_LimitExceeded) /* 524 */\n#define Tcl_LimitSetCommands \\\n\t(tclStubsPtr->tcl_LimitSetCommands) /* 525 */\n#define Tcl_LimitSetTime \\\n\t(tclStubsPtr->tcl_LimitSetTime) /* 526 */\n#define Tcl_LimitSetGranularity \\\n\t(tclStubsPtr->tcl_LimitSetGranularity) /* 527 */\n#define Tcl_LimitTypeEnabled \\\n\t(tclStubsPtr->tcl_LimitTypeEnabled) /* 528 */\n#define Tcl_LimitTypeExceeded \\\n\t(tclStubsPtr->tcl_LimitTypeExceeded) /* 529 */\n#define Tcl_LimitTypeSet \\\n\t(tclStubsPtr->tcl_LimitTypeSet) /* 530 */\n#define Tcl_LimitTypeReset \\\n\t(tclStubsPtr->tcl_LimitTypeReset) /* 531 */\n#define Tcl_LimitGetCommands \\\n\t(tclStubsPtr->tcl_LimitGetCommands) /* 532 */\n#define Tcl_LimitGetTime \\\n\t(tclStubsPtr->tcl_LimitGetTime) /* 533 */\n#define Tcl_LimitGetGranularity \\\n\t(tclStubsPtr->tcl_LimitGetGranularity) /* 534 */\n#define Tcl_SaveInterpState \\\n\t(tclStubsPtr->tcl_SaveInterpState) /* 535 */\n#define Tcl_RestoreInterpState \\\n\t(tclStubsPtr->tcl_RestoreInterpState) /* 536 */\n#define Tcl_DiscardInterpState \\\n\t(tclStubsPtr->tcl_DiscardInterpState) /* 537 */\n#define Tcl_SetReturnOptions \\\n\t(tclStubsPtr->tcl_SetReturnOptions) /* 538 */\n#define Tcl_GetReturnOptions \\\n\t(tclStubsPtr->tcl_GetReturnOptions) /* 539 */\n#define Tcl_IsEnsemble \\\n\t(tclStubsPtr->tcl_IsEnsemble) /* 540 */\n#define Tcl_CreateEnsemble \\\n\t(tclStubsPtr->tcl_CreateEnsemble) /* 541 */\n#define Tcl_FindEnsemble \\\n\t(tclStubsPtr->tcl_FindEnsemble) /* 542 */\n#define Tcl_SetEnsembleSubcommandList \\\n\t(tclStubsPtr->tcl_SetEnsembleSubcommandList) /* 543 */\n#define Tcl_SetEnsembleMappingDict \\\n\t(tclStubsPtr->tcl_SetEnsembleMappingDict) /* 544 */\n#define Tcl_SetEnsembleUnknownHandler \\\n\t(tclStubsPtr->tcl_SetEnsembleUnknownHandler) /* 545 */\n#define Tcl_SetEnsembleFlags \\\n\t(tclStubsPtr->tcl_SetEnsembleFlags) /* 546 */\n#define Tcl_GetEnsembleSubcommandList \\\n\t(tclStubsPtr->tcl_GetEnsembleSubcommandList) /* 547 */\n#define Tcl_GetEnsembleMappingDict \\\n\t(tclStubsPtr->tcl_GetEnsembleMappingDict) /* 548 */\n#define Tcl_GetEnsembleUnknownHandler \\\n\t(tclStubsPtr->tcl_GetEnsembleUnknownHandler) /* 549 */\n#define Tcl_GetEnsembleFlags \\\n\t(tclStubsPtr->tcl_GetEnsembleFlags) /* 550 */\n#define Tcl_GetEnsembleNamespace \\\n\t(tclStubsPtr->tcl_GetEnsembleNamespace) /* 551 */\n#define Tcl_SetTimeProc \\\n\t(tclStubsPtr->tcl_SetTimeProc) /* 552 */\n#define Tcl_QueryTimeProc \\\n\t(tclStubsPtr->tcl_QueryTimeProc) /* 553 */\n#define Tcl_ChannelThreadActionProc \\\n\t(tclStubsPtr->tcl_ChannelThreadActionProc) /* 554 */\n#define Tcl_NewBignumObj \\\n\t(tclStubsPtr->tcl_NewBignumObj) /* 555 */\n#define Tcl_DbNewBignumObj \\\n\t(tclStubsPtr->tcl_DbNewBignumObj) /* 556 */\n#define Tcl_SetBignumObj \\\n\t(tclStubsPtr->tcl_SetBignumObj) /* 557 */\n#define Tcl_GetBignumFromObj \\\n\t(tclStubsPtr->tcl_GetBignumFromObj) /* 558 */\n#define Tcl_TakeBignumFromObj \\\n\t(tclStubsPtr->tcl_TakeBignumFromObj) /* 559 */\n#define Tcl_TruncateChannel \\\n\t(tclStubsPtr->tcl_TruncateChannel) /* 560 */\n#define Tcl_ChannelTruncateProc \\\n\t(tclStubsPtr->tcl_ChannelTruncateProc) /* 561 */\n#define Tcl_SetChannelErrorInterp \\\n\t(tclStubsPtr->tcl_SetChannelErrorInterp) /* 562 */\n#define Tcl_GetChannelErrorInterp \\\n\t(tclStubsPtr->tcl_GetChannelErrorInterp) /* 563 */\n#define Tcl_SetChannelError \\\n\t(tclStubsPtr->tcl_SetChannelError) /* 564 */\n#define Tcl_GetChannelError \\\n\t(tclStubsPtr->tcl_GetChannelError) /* 565 */\n#define Tcl_InitBignumFromDouble \\\n\t(tclStubsPtr->tcl_InitBignumFromDouble) /* 566 */\n#define Tcl_GetNamespaceUnknownHandler \\\n\t(tclStubsPtr->tcl_GetNamespaceUnknownHandler) /* 567 */\n#define Tcl_SetNamespaceUnknownHandler \\\n\t(tclStubsPtr->tcl_SetNamespaceUnknownHandler) /* 568 */\n#define Tcl_GetEncodingFromObj \\\n\t(tclStubsPtr->tcl_GetEncodingFromObj) /* 569 */\n#define Tcl_GetEncodingSearchPath \\\n\t(tclStubsPtr->tcl_GetEncodingSearchPath) /* 570 */\n#define Tcl_SetEncodingSearchPath \\\n\t(tclStubsPtr->tcl_SetEncodingSearchPath) /* 571 */\n#define Tcl_GetEncodingNameFromEnvironment \\\n\t(tclStubsPtr->tcl_GetEncodingNameFromEnvironment) /* 572 */\n#define Tcl_PkgRequireProc \\\n\t(tclStubsPtr->tcl_PkgRequireProc) /* 573 */\n#define Tcl_AppendObjToErrorInfo \\\n\t(tclStubsPtr->tcl_AppendObjToErrorInfo) /* 574 */\n#define Tcl_AppendLimitedToObj \\\n\t(tclStubsPtr->tcl_AppendLimitedToObj) /* 575 */\n#define Tcl_Format \\\n\t(tclStubsPtr->tcl_Format) /* 576 */\n#define Tcl_AppendFormatToObj \\\n\t(tclStubsPtr->tcl_AppendFormatToObj) /* 577 */\n#define Tcl_ObjPrintf \\\n\t(tclStubsPtr->tcl_ObjPrintf) /* 578 */\n#define Tcl_AppendPrintfToObj \\\n\t(tclStubsPtr->tcl_AppendPrintfToObj) /* 579 */\n#define Tcl_CancelEval \\\n\t(tclStubsPtr->tcl_CancelEval) /* 580 */\n#define Tcl_Canceled \\\n\t(tclStubsPtr->tcl_Canceled) /* 581 */\n#define Tcl_CreatePipe \\\n\t(tclStubsPtr->tcl_CreatePipe) /* 582 */\n#define Tcl_NRCreateCommand \\\n\t(tclStubsPtr->tcl_NRCreateCommand) /* 583 */\n#define Tcl_NREvalObj \\\n\t(tclStubsPtr->tcl_NREvalObj) /* 584 */\n#define Tcl_NREvalObjv \\\n\t(tclStubsPtr->tcl_NREvalObjv) /* 585 */\n#define Tcl_NRCmdSwap \\\n\t(tclStubsPtr->tcl_NRCmdSwap) /* 586 */\n#define Tcl_NRAddCallback \\\n\t(tclStubsPtr->tcl_NRAddCallback) /* 587 */\n#define Tcl_NRCallObjProc \\\n\t(tclStubsPtr->tcl_NRCallObjProc) /* 588 */\n#define Tcl_GetFSDeviceFromStat \\\n\t(tclStubsPtr->tcl_GetFSDeviceFromStat) /* 589 */\n#define Tcl_GetFSInodeFromStat \\\n\t(tclStubsPtr->tcl_GetFSInodeFromStat) /* 590 */\n#define Tcl_GetModeFromStat \\\n\t(tclStubsPtr->tcl_GetModeFromStat) /* 591 */\n#define Tcl_GetLinkCountFromStat \\\n\t(tclStubsPtr->tcl_GetLinkCountFromStat) /* 592 */\n#define Tcl_GetUserIdFromStat \\\n\t(tclStubsPtr->tcl_GetUserIdFromStat) /* 593 */\n#define Tcl_GetGroupIdFromStat \\\n\t(tclStubsPtr->tcl_GetGroupIdFromStat) /* 594 */\n#define Tcl_GetDeviceTypeFromStat \\\n\t(tclStubsPtr->tcl_GetDeviceTypeFromStat) /* 595 */\n#define Tcl_GetAccessTimeFromStat \\\n\t(tclStubsPtr->tcl_GetAccessTimeFromStat) /* 596 */\n#define Tcl_GetModificationTimeFromStat \\\n\t(tclStubsPtr->tcl_GetModificationTimeFromStat) /* 597 */\n#define Tcl_GetChangeTimeFromStat \\\n\t(tclStubsPtr->tcl_GetChangeTimeFromStat) /* 598 */\n#define Tcl_GetSizeFromStat \\\n\t(tclStubsPtr->tcl_GetSizeFromStat) /* 599 */\n#define Tcl_GetBlocksFromStat \\\n\t(tclStubsPtr->tcl_GetBlocksFromStat) /* 600 */\n#define Tcl_GetBlockSizeFromStat \\\n\t(tclStubsPtr->tcl_GetBlockSizeFromStat) /* 601 */\n#define Tcl_SetEnsembleParameterList \\\n\t(tclStubsPtr->tcl_SetEnsembleParameterList) /* 602 */\n#define Tcl_GetEnsembleParameterList \\\n\t(tclStubsPtr->tcl_GetEnsembleParameterList) /* 603 */\n#define Tcl_ParseArgsObjv \\\n\t(tclStubsPtr->tcl_ParseArgsObjv) /* 604 */\n#define Tcl_GetErrorLine \\\n\t(tclStubsPtr->tcl_GetErrorLine) /* 605 */\n#define Tcl_SetErrorLine \\\n\t(tclStubsPtr->tcl_SetErrorLine) /* 606 */\n#define Tcl_TransferResult \\\n\t(tclStubsPtr->tcl_TransferResult) /* 607 */\n#define Tcl_InterpActive \\\n\t(tclStubsPtr->tcl_InterpActive) /* 608 */\n#define Tcl_BackgroundException \\\n\t(tclStubsPtr->tcl_BackgroundException) /* 609 */\n#define Tcl_ZlibDeflate \\\n\t(tclStubsPtr->tcl_ZlibDeflate) /* 610 */\n#define Tcl_ZlibInflate \\\n\t(tclStubsPtr->tcl_ZlibInflate) /* 611 */\n#define Tcl_ZlibCRC32 \\\n\t(tclStubsPtr->tcl_ZlibCRC32) /* 612 */\n#define Tcl_ZlibAdler32 \\\n\t(tclStubsPtr->tcl_ZlibAdler32) /* 613 */\n#define Tcl_ZlibStreamInit \\\n\t(tclStubsPtr->tcl_ZlibStreamInit) /* 614 */\n#define Tcl_ZlibStreamGetCommandName \\\n\t(tclStubsPtr->tcl_ZlibStreamGetCommandName) /* 615 */\n#define Tcl_ZlibStreamEof \\\n\t(tclStubsPtr->tcl_ZlibStreamEof) /* 616 */\n#define Tcl_ZlibStreamChecksum \\\n\t(tclStubsPtr->tcl_ZlibStreamChecksum) /* 617 */\n#define Tcl_ZlibStreamPut \\\n\t(tclStubsPtr->tcl_ZlibStreamPut) /* 618 */\n#define Tcl_ZlibStreamGet \\\n\t(tclStubsPtr->tcl_ZlibStreamGet) /* 619 */\n#define Tcl_ZlibStreamClose \\\n\t(tclStubsPtr->tcl_ZlibStreamClose) /* 620 */\n#define Tcl_ZlibStreamReset \\\n\t(tclStubsPtr->tcl_ZlibStreamReset) /* 621 */\n#define Tcl_SetStartupScript \\\n\t(tclStubsPtr->tcl_SetStartupScript) /* 622 */\n#define Tcl_GetStartupScript \\\n\t(tclStubsPtr->tcl_GetStartupScript) /* 623 */\n#define Tcl_CloseEx \\\n\t(tclStubsPtr->tcl_CloseEx) /* 624 */\n#define Tcl_NRExprObj \\\n\t(tclStubsPtr->tcl_NRExprObj) /* 625 */\n#define Tcl_NRSubstObj \\\n\t(tclStubsPtr->tcl_NRSubstObj) /* 626 */\n#define Tcl_LoadFile \\\n\t(tclStubsPtr->tcl_LoadFile) /* 627 */\n#define Tcl_FindSymbol \\\n\t(tclStubsPtr->tcl_FindSymbol) /* 628 */\n#define Tcl_FSUnloadFile \\\n\t(tclStubsPtr->tcl_FSUnloadFile) /* 629 */\n#define Tcl_ZlibStreamSetCompressionDictionary \\\n\t(tclStubsPtr->tcl_ZlibStreamSetCompressionDictionary) /* 630 */\n\n#endif /* defined(USE_TCL_STUBS) */\n\n/* !END!: Do not edit above this line. */\n\n#if defined(USE_TCL_STUBS)\n#   undef Tcl_CreateInterp\n#   undef Tcl_FindExecutable\n#   undef Tcl_GetStringResult\n#   undef Tcl_Init\n#   undef Tcl_SetPanicProc\n#   undef Tcl_SetVar\n#   undef Tcl_ObjSetVar2\n#   undef Tcl_StaticPackage\n#   undef TclFSGetNativePath\n#   define Tcl_CreateInterp() (tclStubsPtr->tcl_CreateInterp())\n#   define Tcl_GetStringResult(interp) (tclStubsPtr->tcl_GetStringResult(interp))\n#   define Tcl_Init(interp) (tclStubsPtr->tcl_Init(interp))\n#   define Tcl_SetPanicProc(proc) (tclStubsPtr->tcl_SetPanicProc(proc))\n#   define Tcl_SetVar(interp, varName, newValue, flags) \\\n\t    (tclStubsPtr->tcl_SetVar(interp, varName, newValue, flags))\n#   define Tcl_ObjSetVar2(interp, part1, part2, newValue, flags) \\\n\t    (tclStubsPtr->tcl_ObjSetVar2(interp, part1, part2, newValue, flags))\n#endif\n\n#if defined(_WIN32) && defined(UNICODE)\n#   define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg)))\n#   define Tcl_MainEx Tcl_MainExW\n    EXTERN void Tcl_MainExW(int argc, wchar_t **argv,\n\t    Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);\n#endif\n\n#undef TCL_STORAGE_CLASS\n#define TCL_STORAGE_CLASS DLLIMPORT\n\n#undef Tcl_SeekOld\n#undef Tcl_TellOld\n\n#undef Tcl_PkgPresent\n#define Tcl_PkgPresent(interp, name, version, exact) \\\n\tTcl_PkgPresentEx(interp, name, version, exact, NULL)\n#undef Tcl_PkgProvide\n#define Tcl_PkgProvide(interp, name, version) \\\n\tTcl_PkgProvideEx(interp, name, version, NULL)\n#undef Tcl_PkgRequire\n#define Tcl_PkgRequire(interp, name, version, exact) \\\n\tTcl_PkgRequireEx(interp, name, version, exact, NULL)\n#undef Tcl_GetIndexFromObj\n#define Tcl_GetIndexFromObj(interp, objPtr, tablePtr, msg, flags, indexPtr) \\\n\tTcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, \\\n\tsizeof(char *), msg, flags, indexPtr)\n#undef Tcl_NewBooleanObj\n#define Tcl_NewBooleanObj(boolValue) \\\n\tTcl_NewIntObj((boolValue)!=0)\n#undef Tcl_DbNewBooleanObj\n#define Tcl_DbNewBooleanObj(boolValue, file, line) \\\n\tTcl_DbNewLongObj((boolValue)!=0, file, line)\n#undef Tcl_SetBooleanObj\n#define Tcl_SetBooleanObj(objPtr, boolValue) \\\n\tTcl_SetIntObj((objPtr), (boolValue)!=0)\n#undef Tcl_SetVar\n#define Tcl_SetVar(interp, varName, newValue, flags) \\\n\tTcl_SetVar2(interp, varName, NULL, newValue, flags)\n#undef Tcl_UnsetVar\n#define Tcl_UnsetVar(interp, varName, flags) \\\n\tTcl_UnsetVar2(interp, varName, NULL, flags)\n#undef Tcl_GetVar\n#define Tcl_GetVar(interp, varName, flags) \\\n\tTcl_GetVar2(interp, varName, NULL, flags)\n#undef Tcl_TraceVar\n#define Tcl_TraceVar(interp, varName, flags, proc, clientData) \\\n\tTcl_TraceVar2(interp, varName, NULL, flags, proc, clientData)\n#undef Tcl_UntraceVar\n#define Tcl_UntraceVar(interp, varName, flags, proc, clientData) \\\n\tTcl_UntraceVar2(interp, varName, NULL, flags, proc, clientData)\n#undef Tcl_VarTraceInfo\n#define Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData) \\\n\tTcl_VarTraceInfo2(interp, varName, NULL, flags, proc, prevClientData)\n#undef Tcl_UpVar\n#define Tcl_UpVar(interp, frameName, varName, localName, flags) \\\n\tTcl_UpVar2(interp, frameName, varName, NULL, localName, flags)\n\n#if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS)\n#   if defined(__CYGWIN__) && defined(TCL_WIDE_INT_IS_LONG)\n/* On Cygwin64, long is 64-bit while on Win64 long is 32-bit. Therefore\n * we have to make sure that all stub entries on Cygwin64 follow the\n * Win64 signature. Cygwin64 stubbed extensions cannot use those stub\n * entries any more, they should use the 64-bit alternatives where\n * possible. Tcl 9 must find a better solution, but that cannot be done\n * without introducing a binary incompatibility.\n */\n#\tundef Tcl_DbNewLongObj\n#\tundef Tcl_GetLongFromObj\n#\tundef Tcl_NewLongObj\n#\tundef Tcl_SetLongObj\n#\tundef Tcl_ExprLong\n#\tundef Tcl_ExprLongObj\n#\tundef Tcl_UniCharNcmp\n#\tundef Tcl_UtfNcmp\n#\tundef Tcl_UtfNcasecmp\n#\tundef Tcl_UniCharNcasecmp\n#\tdefine Tcl_DbNewLongObj ((Tcl_Obj*(*)(long,const char*,int))Tcl_DbNewWideIntObj)\n#\tdefine Tcl_GetLongFromObj ((int(*)(Tcl_Interp*,Tcl_Obj*,long*))Tcl_GetWideIntFromObj)\n#\tdefine Tcl_NewLongObj ((Tcl_Obj*(*)(long))Tcl_NewWideIntObj)\n#\tdefine Tcl_SetLongObj ((void(*)(Tcl_Obj*,long))Tcl_SetWideIntObj)\n#\tdefine Tcl_ExprLong TclExprLong\n\tstatic inline int TclExprLong(Tcl_Interp *interp, const char *string, long *ptr){\n\t    int intValue;\n\t    int result = tclStubsPtr->tcl_ExprLong(interp, string, (long *)&intValue);\n\t    if (result == TCL_OK) *ptr = (long)intValue;\n\t    return result;\n\t}\n#\tdefine Tcl_ExprLongObj TclExprLongObj\n\tstatic inline int TclExprLongObj(Tcl_Interp *interp, Tcl_Obj *obj, long *ptr){\n\t    int intValue;\n\t    int result = tclStubsPtr->tcl_ExprLongObj(interp, obj, (long *)&intValue);\n\t    if (result == TCL_OK) *ptr = (long)intValue;\n\t    return result;\n\t}\n#\tdefine Tcl_UniCharNcmp(ucs,uct,n) \\\n\t\t((int(*)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned int))tclStubsPtr->tcl_UniCharNcmp)(ucs,uct,(unsigned int)(n))\n#\tdefine Tcl_UtfNcmp(s1,s2,n) \\\n\t\t((int(*)(const char*,const char*,unsigned int))tclStubsPtr->tcl_UtfNcmp)(s1,s2,(unsigned int)(n))\n#\tdefine Tcl_UtfNcasecmp(s1,s2,n) \\\n\t\t((int(*)(const char*,const char*,unsigned int))tclStubsPtr->tcl_UtfNcasecmp)(s1,s2,(unsigned int)(n))\n#\tdefine Tcl_UniCharNcasecmp(ucs,uct,n) \\\n\t\t((int(*)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned int))tclStubsPtr->tcl_UniCharNcasecmp)(ucs,uct,(unsigned int)(n))\n#   endif\n#endif\n\n/*\n * Deprecated Tcl procedures:\n */\n\n#undef Tcl_EvalObj\n#define Tcl_EvalObj(interp,objPtr) \\\n    Tcl_EvalObjEx((interp),(objPtr),0)\n#undef Tcl_GlobalEvalObj\n#define Tcl_GlobalEvalObj(interp,objPtr) \\\n    Tcl_EvalObjEx((interp),(objPtr),TCL_EVAL_GLOBAL)\n\n#endif /* _TCLDECLS */\n"
  },
  {
    "path": "src/cocotb/_vendor/tcl/tclPlatDecls.h",
    "content": "/*\n * tclPlatDecls.h --\n *\n *\tDeclarations of platform specific Tcl APIs.\n *\n * Copyright (c) 1998-1999 by Scriptics Corporation.\n * All rights reserved.\n */\n\n#ifndef _TCLPLATDECLS\n#define _TCLPLATDECLS\n\n#undef TCL_STORAGE_CLASS\n#ifdef BUILD_tcl\n#   define TCL_STORAGE_CLASS DLLEXPORT\n#else\n#   ifdef USE_TCL_STUBS\n#      define TCL_STORAGE_CLASS\n#   else\n#      define TCL_STORAGE_CLASS DLLIMPORT\n#   endif\n#endif\n\n/*\n * WARNING: This file is automatically generated by the tools/genStubs.tcl\n * script.  Any modifications to the function declarations below should be made\n * in the generic/tcl.decls script.\n */\n\n/*\n * TCHAR is needed here for win32, so if it is not defined yet do it here.\n * This way, we don't need to include <tchar.h> just for one define.\n */\n#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(_TCHAR_DEFINED)\n#   if defined(_UNICODE)\n\ttypedef wchar_t TCHAR;\n#   else\n\ttypedef char TCHAR;\n#   endif\n#   define _TCHAR_DEFINED\n#endif\n\n/* !BEGIN!: Do not edit below this line. */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n * Exported function declarations:\n */\n\n#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */\n/* 0 */\nEXTERN TCHAR *\t\tTcl_WinUtfToTChar(const char *str, int len,\n\t\t\t\tTcl_DString *dsPtr);\n/* 1 */\nEXTERN char *\t\tTcl_WinTCharToUtf(const TCHAR *str, int len,\n\t\t\t\tTcl_DString *dsPtr);\n#endif /* WIN */\n#ifdef MAC_OSX_TCL /* MACOSX */\n/* 0 */\nEXTERN int\t\tTcl_MacOSXOpenBundleResources(Tcl_Interp *interp,\n\t\t\t\tconst char *bundleName, int hasResourceFile,\n\t\t\t\tint maxPathLen, char *libraryPath);\n/* 1 */\nEXTERN int\t\tTcl_MacOSXOpenVersionedBundleResources(\n\t\t\t\tTcl_Interp *interp, const char *bundleName,\n\t\t\t\tconst char *bundleVersion,\n\t\t\t\tint hasResourceFile, int maxPathLen,\n\t\t\t\tchar *libraryPath);\n#endif /* MACOSX */\n\ntypedef struct TclPlatStubs {\n    int magic;\n    void *hooks;\n\n#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */\n    TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */\n    char * (*tcl_WinTCharToUtf) (const TCHAR *str, int len, Tcl_DString *dsPtr); /* 1 */\n#endif /* WIN */\n#ifdef MAC_OSX_TCL /* MACOSX */\n    int (*tcl_MacOSXOpenBundleResources) (Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath); /* 0 */\n    int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath); /* 1 */\n#endif /* MACOSX */\n} TclPlatStubs;\n\nextern const TclPlatStubs *tclPlatStubsPtr;\n\n#ifdef __cplusplus\n}\n#endif\n\n#if defined(USE_TCL_STUBS)\n\n/*\n * Inline function declarations:\n */\n\n#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */\n#define Tcl_WinUtfToTChar \\\n\t(tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */\n#define Tcl_WinTCharToUtf \\\n\t(tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */\n#endif /* WIN */\n#ifdef MAC_OSX_TCL /* MACOSX */\n#define Tcl_MacOSXOpenBundleResources \\\n\t(tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */\n#define Tcl_MacOSXOpenVersionedBundleResources \\\n\t(tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */\n#endif /* MACOSX */\n\n#endif /* defined(USE_TCL_STUBS) */\n\n/* !END!: Do not edit above this line. */\n\n#undef TCL_STORAGE_CLASS\n#define TCL_STORAGE_CLASS DLLIMPORT\n\n#endif /* _TCLPLATDECLS */\n\n\n"
  },
  {
    "path": "src/cocotb/_vendor/vhpi/vhpi_user.h",
    "content": "/*\n * |---------------------------------------------------------------|\n * |                                                               |\n * | This is the VHPI header file                                  |\n * |                                                               |\n * |                                                               |\n * |                                                               |\n * | FOR CONFORMANCE WITH THE VHPI STANDARD, A VHPI APPLICATION    |\n * | OR PROGRAM MUST REFERENCE THIS HEADER FILE                    |\n * | Its contents can be modified to include vendor extensions.    |\n * |                                                               |\n * |---------------------------------------------------------------|\n */\n\n/*** File vhpi_user.h ***/\n/*** This file describes the procedural interface to access VHDL\n     compiled, instantiated and run-time data. It is derived from\n     the UML model. ***/\n\n#ifndef VHPI_USER_H\n#define VHPI_USER_H\n#include <stddef.h>\n#include <stdarg.h>\n/* Ensure that size-critical types are defined on all OS platforms. */\n#if defined(_MSC_VER)\n    typedef unsigned __int64 uint64_t;\n    typedef unsigned __int32 uint32_t;\n    typedef unsigned __int8 uint8_t;\n    typedef signed __int64 int64_t;\n    typedef signed __int32 int32_t;\n    typedef signed __int8 int8_t;\n#elif defined(__MINGW32__) || (defined(__APPLE__) && defined(__MACH__))\n    #include <stdint.h>\n#elif defined(__linux)\n    #include <inttypes.h>\n#else\n    #include <sys/types.h>\n#endif\n\n#ifdef  __cplusplus\nextern \"C\" {\n#endif\n\n#pragma pack(8)\n\n/*---------------------------------------------------------------------------*/\n/*--------------------------- Portability Help ------------------------------*/\n/*---------------------------------------------------------------------------*/\n/* Use to import/export a symbol */\n#if defined(WIN32) || defined(WIN64)\n    #ifndef PLI_DLLISPEC\n        #define PLI_DLLISPEC __declspec(dllimport)\n        #define VHPI_USER_DEFINED_DLLISPEC 1\n    #endif\n    #ifndef PLI_DLLESPEC\n        #define PLI_DLLESPEC __declspec(dllexport)\n        #define VHPI_USER_DEFINED_DLLESPEC 1\n    #endif\n#else\n    #ifndef PLI_DLLISPEC\n        #define PLI_DLLISPEC\n    #endif\n    #ifndef PLI_DLLESPEC\n        #define PLI_DLLESPEC\n    #endif\n#endif\n\n/* Use to mark a function as external */\n#ifndef PLI_EXTERN\n    #define PLI_EXTERN\n#endif\n\n/* Use to mark a variable as external */\n#ifndef PLI_VEXTERN\n    #define PLI_VEXTERN extern\n#endif\n\n#ifndef PLI_PROTOTYPES\n    #define PLI_PROTOTYPES\n    /* object is defined imported by the application */\n    #define XXTERN PLI_EXTERN PLI_DLLISPEC\n    /* object is exported by the application */\n    #define EETERN PLI_EXTERN PLI_DLLESPEC\n#endif\n\n/* basic typedefs */\n#ifndef VHPI_TYPES\n    #define VHPI_TYPES\n    typedef uint32_t *vhpiHandleT;\n    typedef uint32_t vhpiEnumT;\n    typedef uint8_t vhpiSmallEnumT;\n    typedef uint32_t vhpiIntT;\n    typedef uint64_t vhpiLongIntT;\n    typedef char vhpiCharT;\n    typedef double vhpiRealT;\n    typedef uint32_t vhpiSmallPhysT;\n\n    typedef struct vhpiPhysS\n    {\n        int32_t high;\n        uint32_t low;\n    } vhpiPhysT;\n\n    /* Sized variables */\n    #ifndef PLI_TYPES\n        #define PLI_TYPES\n        typedef int PLI_INT32;\n        typedef unsigned int PLI_UINT32;\n        typedef short PLI_INT16;\n        typedef unsigned short PLI_UINT16;\n        typedef char PLI_BYTE8;\n        typedef unsigned char PLI_UBYTE8;\n        typedef void PLI_VOID;\n    #endif\n\n    /********************** time structure ****************************/\n    typedef struct vhpiTimeS\n    {\n        uint32_t high;\n        uint32_t low;\n    } vhpiTimeT;\n\n    /********************** value structure **************************/\n\n    /* value formats */\n    typedef enum\n    {\n        vhpiBinStrVal        = 1, /* do not move */\n        vhpiOctStrVal        = 2, /* do not move */\n        vhpiDecStrVal        = 3, /* do not move */\n        vhpiHexStrVal        = 4, /* do not move */\n        vhpiEnumVal          = 5,\n        vhpiIntVal           = 6,\n        vhpiLogicVal         = 7,\n        vhpiRealVal          = 8,\n        vhpiStrVal           = 9,\n        vhpiCharVal          = 10,\n        vhpiTimeVal          = 11,\n        vhpiPhysVal          = 12,\n        vhpiObjTypeVal       = 13,\n        vhpiPtrVal           = 14,\n        vhpiEnumVecVal       = 15,\n        vhpiIntVecVal        = 16,\n        vhpiLogicVecVal      = 17,\n        vhpiRealVecVal       = 18,\n        vhpiTimeVecVal       = 19,\n        vhpiPhysVecVal       = 20,\n        vhpiPtrVecVal        = 21,\n        vhpiRawDataVal       = 22,\n        vhpiSmallEnumVal     = 23,\n        vhpiSmallEnumVecVal  = 24,\n        vhpiLongIntVal       = 25,\n        vhpiLongIntVecVal    = 26,\n        vhpiSmallPhysVal     = 27,\n        vhpiSmallPhysVecVal  = 28\n\n        #ifdef VHPIEXTEND_VAL_FORMATS\n            VHPIEXTEND_VAL_FORMATS\n        #endif\n    } vhpiFormatT;\n\n    /* value structure */\n    typedef struct vhpiValueS\n    {\n        vhpiFormatT format;  /* vhpi[Char,[Bin,Oct,Dec,Hex]Str,\n                                        [Small]Enum,Logic,Int,Real,[Small]Phys,Time,Ptr,\n                                        [Small]EnumVec,LogicVec,IntVect,RealVec,[Small]PhysVec,TimeVec,\n                                        PtrVec,ObjType,RawData]Val */\n#ifndef IUS\n        size_t bufSize;  /* the size in bytes of the value buffer; this is set by the user */\n#else\n        int32_t bufSize;  /* IUS/Xcelium defines this as 32-bits, even when running in 64-bit mode */\n#endif\n        int32_t numElems;\n        /* different meanings depending on the format:\n            vhpiStrVal, vhpi{Bin...}StrVal: size of string\n            array type values: number of array elements\n            scalar type values: undefined\n        */\n\n        vhpiPhysT unit;\n        union\n        {\n            vhpiEnumT enumv, *enumvs;\n            vhpiSmallEnumT smallenumv, *smallenumvs;\n            vhpiIntT  intg, *intgs;\n            vhpiLongIntT  longintg, *longintgs;\n            vhpiRealT real, *reals;\n            vhpiSmallPhysT smallphys, *smallphyss;\n            vhpiPhysT phys, *physs;\n            vhpiTimeT time, *times;\n            vhpiCharT ch, *str;\n            void *ptr, **ptrs;\n        } value;\n    } vhpiValueT;\n#endif\n\n/* Following are the constant definitions. They are divided into\n   three major areas:\n\n 1) object types\n\n 2) access methods\n\n 3) properties\n\n*/\n\n#ifndef IUS\n#define vhpiUndefined -1\n#else\n#define vhpiUndefined 1000\n#endif\n\n/*************** OBJECT KINDS *******************/\ntypedef enum\n{\n    vhpiAccessTypeDeclK         = 1001,\n    vhpiAggregateK              = 1002,\n    vhpiAliasDeclK              = 1003,\n    vhpiAllK                    = 1004,\n    vhpiAllocatorK              = 1005,\n    vhpiAnyCollectionK          = 1006,\n    vhpiArchBodyK               = 1007,\n    vhpiArgvK                   = 1008,\n    vhpiArrayTypeDeclK          = 1009,\n    vhpiAssertStmtK             = 1010,\n    vhpiAssocElemK              = 1011,\n    vhpiAttrDeclK               = 1012,\n    vhpiAttrSpecK               = 1013,\n    vhpiBinaryExprK             = 1014, /* DEPRECATED */\n    vhpiBitStringLiteralK       = 1015,\n    vhpiBlockConfigK            = 1016,\n    vhpiBlockStmtK              = 1017,\n    vhpiBranchK                 = 1018,\n    vhpiCallbackK               = 1019,\n    vhpiCaseStmtK               = 1020,\n    vhpiCharLiteralK            = 1021,\n    vhpiCompConfigK             = 1022,\n    vhpiCompDeclK               = 1023,\n    vhpiCompInstStmtK           = 1024,\n    vhpiCondSigAssignStmtK      = 1025,\n    vhpiCondWaveformK           = 1026,\n    vhpiConfigDeclK             = 1027,\n    vhpiConstDeclK              = 1028,\n    vhpiConstParamDeclK         = 1029,\n    vhpiConvFuncK               = 1030,\n    vhpiDerefObjK               = 1031,\n    vhpiDisconnectSpecK         = 1032,\n    vhpiDriverK                 = 1033,\n    vhpiDriverCollectionK       = 1034,\n    vhpiElemAssocK              = 1035,\n    vhpiElemDeclK               = 1036,\n    vhpiEntityClassEntryK       = 1037,\n    vhpiEntityDeclK             = 1038,\n    vhpiEnumLiteralK            = 1039,\n    vhpiEnumRangeK              = 1040,\n    vhpiEnumTypeDeclK           = 1041,\n    vhpiExitStmtK               = 1042,\n    vhpiFileDeclK               = 1043,\n    vhpiFileParamDeclK          = 1044,\n    vhpiFileTypeDeclK           = 1045,\n    vhpiFloatRangeK             = 1046,\n    vhpiFloatTypeDeclK          = 1047,\n    vhpiForGenerateK            = 1048,\n    vhpiForLoopK                = 1049,\n    vhpiForeignfK               = 1050,\n    vhpiFuncCallK               = 1051,\n    vhpiFuncDeclK               = 1052,\n    vhpiGenericDeclK            = 1053,\n    vhpiGroupDeclK              = 1054,\n    vhpiGroupTempDeclK          = 1055,\n    vhpiIfGenerateK             = 1056,\n    vhpiIfStmtK                 = 1057,\n    vhpiInPortK                 = 1058,\n    vhpiIndexedNameK            = 1059,\n    vhpiIntLiteralK             = 1060,\n    vhpiIntRangeK               = 1061,\n    vhpiIntTypeDeclK            = 1062,\n    vhpiIteratorK               = 1063,\n    vhpiLibraryDeclK            = 1064,\n    vhpiLoopStmtK               = 1065,\n    vhpiNextStmtK               = 1066,\n    vhpiNullLiteralK            = 1067,\n    vhpiNullStmtK               = 1068,\n    vhpiOperatorK               = 1069,\n    vhpiOthersK                 = 1070,\n    vhpiOutPortK                = 1071,\n    vhpiPackBodyK               = 1072,\n    vhpiPackDeclK               = 1073,\n    vhpiPackInstK               = 1074,\n    vhpiParamAttrNameK          = 1075,\n    vhpiPhysLiteralK            = 1076,\n    vhpiPhysRangeK              = 1077,\n    vhpiPhysTypeDeclK           = 1078,\n    vhpiPortDeclK               = 1079,\n    vhpiProcCallStmtK           = 1080,\n    vhpiProcDeclK               = 1081,\n    vhpiProcessStmtK            = 1082,\n    vhpiProtectedTypeK          = 1083,\n    vhpiProtectedTypeBodyK      = 1084,\n    vhpiProtectedTypeDeclK      = 1085,\n    vhpiRealLiteralK            = 1086,\n    vhpiRecordTypeDeclK         = 1087,\n    vhpiReportStmtK             = 1088,\n    vhpiReturnStmtK             = 1089,\n    vhpiRootInstK               = 1090,\n    vhpiSelectSigAssignStmtK    = 1091,\n    vhpiSelectWaveformK         = 1092,\n    vhpiSelectedNameK           = 1093,\n    vhpiSigDeclK                = 1094,\n    vhpiSigParamDeclK           = 1095,\n    vhpiSimpAttrNameK           = 1096,\n    vhpiSimpleSigAssignStmtK    = 1097,\n    vhpiSliceNameK              = 1098,\n    vhpiStringLiteralK          = 1099,\n    vhpiSubpBodyK               = 1100,\n    vhpiSubtypeDeclK            = 1101,\n    vhpiSubtypeIndicK           = 1102, /* DEPRECATED */\n    vhpiToolK                   = 1103,\n    vhpiTransactionK            = 1104,\n    vhpiTypeConvK               = 1105,\n    vhpiUnaryExprK              = 1106, /* DEPRECATED */\n    vhpiUnitDeclK               = 1107,\n    vhpiUserAttrNameK           = 1108,\n    vhpiVarAssignStmtK          = 1109,\n    vhpiVarDeclK                = 1110,\n    vhpiVarParamDeclK           = 1111,\n    vhpiWaitStmtK               = 1112,\n    vhpiWaveformElemK           = 1113,\n    vhpiWhileLoopK              = 1114,\n    vhpiQualifiedExprK          = 1115,\n#ifndef IUS\n    vhpiUseClauseK              = 1116,\n#else\n    vhpiUseClauseK              = 1200,\n#endif\n\n#ifdef VHPIEXTEND_CLASSES\n    VHPIEXTEND_CLASSES\n#endif\n    /* private vendor extensions */\n    vhpiVerilog                 = 1117,\n    vhpiEdifUnit                = 1118,\n    vhpiCollectionK             = 1119,\n    vhpiVHDL                    = 1120,\n\tvhpiSystemC                 = 1121\n} vhpiClassKindT;\n\n/************** methods used to traverse 1 to 1 relationships *******************/\ntypedef enum\n{\n    vhpiAbstractLiteral         = 1301,\n    vhpiActual                  = 1302,\n    vhpiAll                     = 1303,\n    vhpiAttrDecl                = 1304,\n    vhpiAttrSpec                = 1305,\n    vhpiBaseType                = 1306,\n    vhpiBaseUnit                = 1307,\n    vhpiBasicSignal             = 1308,\n    vhpiBlockConfig             = 1309,\n    vhpiCaseExpr                = 1310,\n    vhpiCondExpr                = 1311,\n    vhpiConfigDecl              = 1312,\n    vhpiConfigSpec              = 1313,\n    vhpiConstraint              = 1314,\n    vhpiContributor             = 1315,\n    vhpiCurCallback             = 1316,\n    vhpiCurEqProcess            = 1317,\n    vhpiCurStackFrame           = 1318,\n    vhpiDerefObj                = 1319,\n    vhpiDecl                    = 1320,\n    vhpiDesignUnit              = 1321,\n    vhpiDownStack               = 1322,\n    vhpiElemSubtype             = 1323, /* DEPRECATED */\n    vhpiEntityAspect            = 1324,\n    vhpiEntityDecl              = 1325,\n    vhpiEqProcessStmt           = 1326,\n    vhpiExpr                    = 1327,\n    vhpiFormal                  = 1328,\n    vhpiFuncDecl                = 1329,\n    vhpiGroupTempDecl           = 1330,\n    vhpiGuardExpr               = 1331,\n    vhpiGuardSig                = 1332,\n    vhpiImmRegion               = 1333,\n    vhpiInPort                  = 1334,\n    vhpiInitExpr                = 1335,\n    vhpiIterScheme              = 1336,\n    vhpiLeftExpr                = 1337,\n    vhpiLexicalScope            = 1338,\n    vhpiLhsExpr                 = 1339,\n    vhpiLocal                   = 1340,\n    vhpiLogicalExpr             = 1341,\n    vhpiName                    = 1342,\n    vhpiOperator                = 1343,\n    vhpiOthers                  = 1344,\n    vhpiOutPort                 = 1345,\n    vhpiParamDecl               = 1346,\n    vhpiParamExpr               = 1347,\n    vhpiParent                  = 1348,\n    vhpiPhysLiteral             = 1349,\n    vhpiPrefix                  = 1350,\n    vhpiPrimaryUnit             = 1351,\n    vhpiProtectedTypeBody       = 1352,\n    vhpiProtectedTypeDecl       = 1353,\n    vhpiRejectTime              = 1354,\n    vhpiReportExpr              = 1355,\n    vhpiResolFunc               = 1356,\n    vhpiReturnExpr              = 1357,\n    vhpiReturnTypeMark          = 1358, /* DEPRECATED */\n    vhpiRhsExpr                 = 1359,\n    vhpiRightExpr               = 1360,\n    vhpiRootInst                = 1361,\n    vhpiSelectExpr              = 1362,\n    vhpiSeverityExpr            = 1363,\n    vhpiSimpleName              = 1364,\n    vhpiSubpBody                = 1365,\n    vhpiSubpDecl                = 1366,\n    vhpiSubtype                 = 1367, /* DEPRECATED */\n    vhpiSuffix                  = 1368,\n    vhpiTimeExpr                = 1369,\n    vhpiTimeOutExpr             = 1370,\n    vhpiTool                    = 1371,\n    vhpiType                    = 1372,\n    vhpiTypeMark                = 1373, /* DEPRECATED */\n\tvhpiTypespec\t\t\t\t\t  ,\n    vhpiUnitDecl                = 1374,\n    vhpiUpStack                 = 1375,\n    vhpiUpperRegion             = 1376,\n    vhpiUse                     = 1377,\n    vhpiValExpr                 = 1378,\n    vhpiValSubtype              = 1379, /* DEPRECATED */\n    vhpiElemType                = 1380,\n    vhpiFirstNamedType          = 1381,\n    vhpiReturnType              = 1382,\n    vhpiValType                 = 1383,\n    vhpiCurRegion               = 1384\n\n#ifdef VHPIEXTEND_ONE_METHODS\n    VHPIEXTEND_ONE_METHODS\n#endif\n} vhpiOneToOneT;\n\n/************** methods used to traverse 1 to many relationships *******************/\ntypedef enum\n{\n    vhpiAliasDecls              = 1501,\n    vhpiArgvs                   = 1502,\n    vhpiAttrDecls               = 1503,\n    vhpiAttrSpecs               = 1504,\n    vhpiBasicSignals            = 1505,\n    vhpiBlockStmts              = 1506,\n    vhpiBranchs                 = 1507,\n    /* 1508 */\n    vhpiChoices                 = 1509,\n    vhpiCompInstStmts           = 1510,\n    vhpiCondExprs               = 1511,\n    vhpiCondWaveforms           = 1512,\n    vhpiConfigItems             = 1513,\n    vhpiConfigSpecs             = 1514,\n    vhpiConstDecls              = 1515,\n    vhpiConstraints             = 1516,\n    vhpiContributors            = 1517,\n    /* 1518 */\n    vhpiDecls                   = 1519,\n    vhpiDepUnits                = 1520,\n    vhpiDesignUnits             = 1521,\n    vhpiDrivenSigs              = 1522,\n    vhpiDrivers                 = 1523,\n    vhpiElemAssocs              = 1524,\n    vhpiEntityClassEntrys       = 1525,\n    vhpiEntityDesignators       = 1526,\n    vhpiEnumLiterals            = 1527,\n    vhpiForeignfs               = 1528,\n    vhpiGenericAssocs           = 1529,\n    vhpiGenericDecls            = 1530,\n    vhpiIndexExprs              = 1531,\n    vhpiIndexedNames            = 1532,\n    vhpiInternalRegions         = 1533,\n    vhpiMembers                 = 1534,\n    vhpiPackInsts               = 1535,\n    vhpiParamAssocs             = 1536,\n    vhpiParamDecls              = 1537,\n    vhpiPortAssocs              = 1538,\n    vhpiPortDecls               = 1539,\n    vhpiRecordElems             = 1540,\n    vhpiSelectWaveforms         = 1541,\n    vhpiSelectedNames           = 1542,\n    vhpiSensitivitys            = 1543,\n    vhpiSeqStmts                = 1544,\n    vhpiSigAttrs                = 1545,\n    vhpiSigDecls                = 1546,\n    vhpiSigNames                = 1547,\n    vhpiSignals                 = 1548,\n    vhpiSpecNames               = 1549,\n    vhpiSpecs                   = 1550,\n    vhpiStmts                   = 1551,\n    vhpiTransactions            = 1552,\n    vhpiTypeMarks               = 1553, /* DEPRECATED */\n    vhpiUnitDecls               = 1554,\n    vhpiUses                    = 1555,\n    vhpiVarDecls                = 1556,\n    vhpiWaveformElems           = 1557,\n    vhpiLibraryDecls            = 1558,\n    vhpiLocalLoads              = 1559,\n    vhpiOptimizedLoads          = 1560,\n    vhpiTypes                   = 1561,\n#ifndef IUS\n    vhpiUseClauses              = 1562,\n#else\n    vhpiUseClauses              = 1650,\n#endif\n\n#ifdef VHPIEXTEND_MANY_METHODS\n    VHPIEXTEND_MANY_METHODS\n#endif\n    vhpiCallbacks               = 1563,\n    vhpiCurRegions              = 1564\n} vhpiOneToManyT;\n\n/****************** PROPERTIES *******************/\n/******* INTEGER or BOOLEAN PROPERTIES **********/\ntypedef enum\n{\n    vhpiAccessP                 = 1001,\n    vhpiArgcP                   = 1002,\n    vhpiAttrKindP               = 1003,\n    vhpiBaseIndexP              = 1004,\n    vhpiBeginLineNoP            = 1005,\n    vhpiEndLineNoP              = 1006,\n    vhpiEntityClassP            = 1007,\n    vhpiForeignKindP            = 1008,\n    vhpiFrameLevelP             = 1009,\n    vhpiGenerateIndexP          = 1010,\n    vhpiIntValP                 = 1011,\n    vhpiIsAnonymousP            = 1012,\n    vhpiIsBasicP                = 1013,\n    vhpiIsCompositeP            = 1014,\n    vhpiIsDefaultP              = 1015,\n    vhpiIsDeferredP             = 1016,\n    vhpiIsDiscreteP             = 1017,\n    vhpiIsForcedP               = 1018,\n    vhpiIsForeignP              = 1019,\n    vhpiIsGuardedP              = 1020,\n    vhpiIsImplicitDeclP         = 1021,\n    vhpiIsInvalidP              = 1022, /* DEPRECATED */\n    vhpiIsLocalP                = 1023,\n    vhpiIsNamedP                = 1024,\n    vhpiIsNullP                 = 1025,\n    vhpiIsOpenP                 = 1026,\n    vhpiIsPLIP                  = 1027,\n    vhpiIsPassiveP              = 1028,\n    vhpiIsPostponedP            = 1029,\n    vhpiIsProtectedTypeP        = 1030,\n    vhpiIsPureP                 = 1031,\n    vhpiIsResolvedP             = 1032,\n    vhpiIsScalarP               = 1033,\n    vhpiIsSeqStmtP              = 1034,\n    vhpiIsSharedP               = 1035,\n    vhpiIsTransportP            = 1036,\n    vhpiIsUnaffectedP           = 1037,\n    vhpiIsUnconstrainedP        = 1038,\n    vhpiIsUninstantiatedP       = 1039,\n    vhpiIsUpP                   = 1040,\n    vhpiIsVitalP                = 1041,\n    vhpiIteratorTypeP           = 1042,\n    vhpiKindP                   = 1043,\n    vhpiLeftBoundP              = 1044,\n    vhpiLevelP                  = 1045, /* DEPRECATED */\n    vhpiLineNoP                 = 1046,\n    vhpiLineOffsetP             = 1047,\n    vhpiLoopIndexP              = 1048,\n    vhpiModeP                   = 1049,\n    vhpiNumDimensionsP          = 1050,\n    vhpiNumFieldsP              = 1051, /* DEPRECATED */\n    vhpiNumGensP                = 1052,\n    vhpiNumLiteralsP            = 1053,\n    vhpiNumMembersP             = 1054,\n    vhpiNumParamsP              = 1055,\n    vhpiNumPortsP               = 1056,\n    vhpiOpenModeP               = 1057,\n    vhpiPhaseP                  = 1058,\n    vhpiPositionP               = 1059,\n    vhpiPredefAttrP             = 1060,\n    /* 1061 */\n    vhpiReasonP                 = 1062,\n    vhpiRightBoundP             = 1063,\n    vhpiSigKindP                = 1064,\n    vhpiSizeP                   = 1065,\n    vhpiStartLineNoP            = 1066,\n    vhpiStateP                  = 1067,\n    vhpiStaticnessP             = 1068,\n    vhpiVHDLversionP            = 1069,\n    vhpiIdP                     = 1070,\n    vhpiCapabilitiesP           = 1071,\n\n#ifdef VHPIEXTEND_INT_PROPERTIES\n    VHPIEXTEND_INT_PROPERTIES\n#endif\n    vhpiIsStdLogicP             = 1072,\n    vhpiIsStdULogicP            = 1073,\n    vhpiIsStdLogicVectorP       = 1074,\n    vhpiIsStdULogicVectorP      = 1075,\n#\n    vhpiLanguageP               = 1200\n} vhpiIntPropertyT;\n\n/******* STRING PROPERTIES **********/\ntypedef enum\n{\n    vhpiCaseNameP               = 1301,\n    vhpiCompNameP               = 1302,\n    vhpiDefNameP                = 1303,\n    vhpiFileNameP               = 1304,\n    vhpiFullCaseNameP           = 1305,\n    vhpiFullNameP               = 1306,\n    vhpiKindStrP                = 1307,\n    vhpiLabelNameP              = 1308,\n    vhpiLibLogicalNameP         = 1309,\n    vhpiLibPhysicalNameP        = 1310,\n    vhpiLogicalNameP            = 1311,\n    vhpiLoopLabelNameP          = 1312,\n    vhpiNameP                   = 1313,\n    vhpiOpNameP                 = 1314,\n    vhpiStrValP                 = 1315,\n    vhpiToolVersionP            = 1316,\n    vhpiUnitNameP               = 1317,\n    vhpiSaveRestartLocationP    = 1318,\n\n    /* Cadence IUS/Xcelium */\n    vhpiFullVlogNameP = 1500,       /* Full path name (VHDL names are Verilogized) */\n    vhpiFullVHDLNameP = 1501,       /* Full path name (Verilog names are vhdlized) */\n    vhpiFullLSNameP = 1502,         /* Full path name (Upper case) using ':' and '.' separators */\n    vhpiFullLSCaseNameP = 1503      /* Full path name (VHDL case sensitive) */\n\n#ifdef VHPIEXTEND_STR_PROPERTIES\n    VHPIEXTEND_STR_PROPERTIES\n#endif\n} vhpiStrPropertyT;\n\n/******* REAL PROPERTIES **********/\ntypedef enum\n{\n    vhpiFloatLeftBoundP         = 1601,\n    vhpiFloatRightBoundP        = 1602,\n    vhpiRealValP                = 1603\n\n#ifdef VHPIEXTEND_REAL_PROPERTIES\n    VHPIEXTEND_REAL_PROPERTIES\n#endif\n} vhpiRealPropertyT;\n\n/******* PHYSICAL PROPERTIES **********/\ntypedef enum\n{\n    vhpiPhysLeftBoundP          = 1651,\n    vhpiPhysPositionP           = 1652,\n    vhpiPhysRightBoundP         = 1653,\n    vhpiPhysValP                = 1654,\n    vhpiPrecisionP              = 1655, /* DEPRECATED */\n    vhpiSimTimeUnitP            = 1656, /* DEPRECATED */\n    vhpiResolutionLimitP        = 1657\n\n#ifdef VHPIEXTEND_PHYS_PROPERTIES\n    VHPIEXTEND_PHYS_PROPERTIES\n#endif\n} vhpiPhysPropertyT;\n\n/******************* PROPERTY VALUES ************************/\n\n/* vhpiCapabilitiesP */\ntypedef enum\n{\n    vhpiProvidesHierarchy             = 1,\n    vhpiProvidesStaticAccess          = 2,\n    vhpiProvidesConnectivity          = 4,\n    vhpiProvidesPostAnalysis          = 8,\n    vhpiProvidesForeignModel          = 16,\n    vhpiProvidesAdvancedForeignModel  = 32,\n    vhpiProvidesSaveRestart           = 64,\n    vhpiProvidesReset                 = 128,\n    vhpiProvidesDebugRuntime          = 256,\n    vhpiProvidesAdvancedDebugRuntime  = 512,\n    vhpiProvidesDynamicElab           = 1024\n} vhpiCapabibilityT;\n\n\n/* vhpiOpenModeP */\ntypedef enum\n{\n    vhpiInOpen          = 1001,\n    vhpiOutOpen         = 1002,\n    vhpiReadOpen        = 1003,\n    vhpiWriteOpen       = 1004,\n    vhpiAppendOpen      = 1005\n} vhpiOpenModeT;\n\n/* vhpiModeP */\ntypedef enum\n{\n    vhpiInMode          = 1001,\n    vhpiOutMode         = 1002,\n    vhpiInoutMode       = 1003,\n    vhpiBufferMode      = 1004,\n    vhpiLinkageMode     = 1005\n} vhpiModeT;\n\n/* vhpiSigKindP */\ntypedef enum\n{\n    vhpiRegister        = 1001,\n    vhpiBus             = 1002,\n    vhpiNormal          = 1003\n} vhpiSigKindT;\n\n/* vhpiStaticnessP */\ntypedef enum\n{\n    vhpiLocallyStatic   = 1001,\n    vhpiGloballyStatic  = 1002,\n    vhpiDynamic         = 1003\n} vhpiStaticnessT;\n\n/* vhpiPredefAttrP */\ntypedef enum\n{\n    vhpiActivePA        = 1001,\n    vhpiAscendingPA     = 1002,\n    vhpiBasePA          = 1003,\n    vhpiDelayedPA       = 1004,\n    vhpiDrivingPA       = 1005,\n    vhpiDriving_valuePA = 1006,\n    vhpiEventPA         = 1007,\n    vhpiHighPA          = 1008,\n    vhpiImagePA         = 1009,\n    vhpiInstance_namePA = 1010,\n    vhpiLast_activePA   = 1011,\n    vhpiLast_eventPA    = 1012,\n    vhpiLast_valuePA    = 1013,\n    vhpiLeftPA          = 1014,\n    vhpiLeftofPA        = 1015,\n    vhpiLengthPA        = 1016,\n    vhpiLowPA           = 1017,\n    vhpiPath_namePA     = 1018,\n    vhpiPosPA           = 1019,\n    vhpiPredPA          = 1020,\n    vhpiQuietPA         = 1021,\n    vhpiRangePA         = 1022,\n    vhpiReverse_rangePA = 1023,\n    vhpiRightPA         = 1024,\n    vhpiRightofPA       = 1025,\n    vhpiSimple_namePA   = 1026,\n    vhpiStablePA        = 1027,\n    vhpiSuccPA          = 1028,\n    vhpiTransactionPA   = 1029,\n    vhpiValPA           = 1030,\n    vhpiValuePA         = 1031\n} vhpiPredefAttrT;\n\n/* vhpiAttrKindP */\ntypedef enum\n{\n  vhpiFunctionAK        = 1,\n  vhpiRangeAK           = 2,\n  vhpiSignalAK          = 3,\n  vhpiTypeAK            = 4,\n  vhpiValueAK           = 5\n\n#ifdef VHPIEXTEND_INT_ATTR\n  VHPI_EXTEND_INT_ATTR\n#endif\n} vhpiAttrKindT;\n\n/* vhpiEntityClassP */\ntypedef enum\n{\n    vhpiEntityEC        = 1001,\n    vhpiArchitectureEC  = 1002,\n    vhpiConfigurationEC = 1003,\n    vhpiProcedureEC     = 1004,\n    vhpiFunctionEC      = 1005,\n    vhpiPackageEC       = 1006,\n    vhpiTypeEC          = 1007,\n    vhpiSubtypeEC       = 1008,\n    vhpiConstantEC      = 1009,\n    vhpiSignalEC        = 1010,\n    vhpiVariableEC      = 1011,\n    vhpiComponentEC     = 1012,\n    vhpiLabelEC         = 1013,\n    vhpiLiteralEC       = 1014,\n    vhpiUnitsEC         = 1015,\n    vhpiFileEC          = 1016,\n    vhpiGroupEC         = 1017\n} vhpiEntityClassT;\n\n/* vhpiAccessP */\ntypedef enum\n{\n    vhpiRead            = 1,\n    vhpiWrite           = 2,\n    vhpiConnectivity    = 4,\n    vhpiNoAccess        = 8\n} vhpiAccessT;\n\n/* value for vhpiStateP property for callbacks */\ntypedef enum\n{\n    vhpiEnable,\n    vhpiDisable,\n    vhpiMature /* callback has occurred */\n} vhpiStateT;\n\n/* enumeration type for vhpiCompInstKindP property */\ntypedef enum\n{\n    vhpiDirect,\n    vhpiComp,\n    vhpiConfig\n} vhpiCompInstKindT;\n\n\n/* the following values are used only for the\n   vhpiResolutionLimitP property and for setting the unit field of the value\n   structure; they represent the physical position of a given\n   VHDL time unit */\n/* time unit physical position values {high, low} */\nPLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiFS;\nPLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiPS;\nPLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiNS;\nPLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiUS;\nPLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiMS;\nPLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiS;\nPLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiMN;\nPLI_VEXTERN PLI_DLLISPEC const vhpiPhysT vhpiHR;\n\n/* IEEE std_logic values */\n#define vhpiU                 0 /* uninitialized */\n#define vhpiX                 1 /* unknown */\n#define vhpi0                 2 /* forcing 0 */\n#define vhpi1                 3 /* forcing 1 */\n#define vhpiZ                 4 /* high impedance */\n#define vhpiW                 5 /* weak unknown */\n#define vhpiL                 6 /* weak 0 */\n#define vhpiH                 7 /* weak 1 */\n#define vhpiDontCare          8 /* don't care */\n\n/* IEEE std bit values */\n#define vhpibit0              0 /* bit 0 */\n#define vhpibit1              1 /* bit 1 */\n\n/* IEEE std boolean values */\n#define vhpiFalse             0 /* false */\n#define vhpiTrue              1 /* true */\n\n/************** vhpiPhaseP property values *************/\ntypedef enum\n{\n    vhpiRegistrationPhase   = 1,\n    vhpiAnalysisPhase       = 2,\n    vhpiElaborationPhase    = 3,\n    vhpiInitializationPhase = 4,\n    vhpiSimulationPhase     = 5,\n    vhpiTerminationPhase    = 6,\n    vhpiSavePhase           = 7,\n    vhpiRestartPhase        = 8,\n    vhpiResetPhase          = 9\n} vhpiPhaseT ;\n\n/**************** PLI error information structure ****************/\n\ntypedef enum\n{\n    vhpiNote                = 1,\n    vhpiWarning             = 2,\n    vhpiError               = 3,\n    vhpiFailure             = 6,\n    vhpiSystem              = 4,\n    vhpiInternal            = 5\n} vhpiSeverityT;\n\ntypedef struct vhpiErrorInfoS\n{\n\tvhpiSeverityT severity;\n\tchar *message;\n\tchar *str;\n\tchar *file; /* Name of the VHDL file where the VHPI error originated */\n\tint32_t line; /* Line number in the VHDL file */\n} vhpiErrorInfoT;\n\n/********************* callback structures ************************/\n/* callback user data structure */\n\ntypedef struct vhpiCbDataS\n{\n\tint32_t reason; /* callback reason */\n\tvoid (*cb_rtn) (const struct vhpiCbDataS *);  /* call routine */\n\tvhpiHandleT obj; /* trigger object */\n\tvhpiTimeT *time; /* callback time */\n\tvhpiValueT *value; /* trigger object value */\n\tvoid *user_data; /* pointer to user data to be passed to the callback function */\n} vhpiCbDataT;\n\n/**************************** CALLBACK REASONS ****************************/\n/*************************** Simulation object related ***********************/\n/* These are repetitive callbacks */\n#define vhpiCbValueChange               1001\n#define vhpiCbForce                     1002\n#define vhpiCbRelease                   1003\n#define vhpiCbTransaction               1004 /* optional callback reason */\n\n/****************************** Statement related ****************************/\n/* These are repetitive callbacks */\n#define vhpiCbStmt                      1005\n#define vhpiCbResume                    1006\n#define vhpiCbSuspend                   1007\n#define vhpiCbStartOfSubpCall           1008\n#define vhpiCbEndOfSubpCall             1009\n\n/****************************** Time related ******************************/\n/* the Rep callback reasons are the repeated versions of the callbacks */\n\n#define vhpiCbAfterDelay                1010\n#define vhpiCbRepAfterDelay             1011\n\n/*************************** Simulation cycle phase related *****************/\n#define vhpiCbNextTimeStep              1012\n#define vhpiCbRepNextTimeStep           1013\n#define vhpiCbStartOfNextCycle          1014\n#define vhpiCbRepStartOfNextCycle       1015\n#define vhpiCbStartOfProcesses          1016\n#define vhpiCbRepStartOfProcesses       1017\n#define vhpiCbEndOfProcesses            1018\n#define vhpiCbRepEndOfProcesses         1019\n#define vhpiCbLastKnownDeltaCycle       1020\n#define vhpiCbRepLastKnownDeltaCycle    1021\n#define vhpiCbStartOfPostponed          1022\n#define vhpiCbRepStartOfPostponed       1023\n#define vhpiCbEndOfTimeStep             1024\n#define vhpiCbRepEndOfTimeStep          1025\n\n/***************************** Action related *****************************/\n/* these are one time callback unless otherwise noted */\n#define vhpiCbStartOfTool               1026\n#define vhpiCbEndOfTool                 1027\n#define vhpiCbStartOfAnalysis           1028\n#define vhpiCbEndOfAnalysis             1029\n#define vhpiCbStartOfElaboration        1030\n#define vhpiCbEndOfElaboration          1031\n#define vhpiCbStartOfInitialization     1032\n#define vhpiCbEndOfInitialization       1033\n#define vhpiCbStartOfSimulation         1034\n#define vhpiCbEndOfSimulation           1035\n#define vhpiCbQuiescense                1036 /* repetitive */\n#define vhpiCbPLIError                  1037 /* repetitive */\n#define vhpiCbStartOfSave               1038\n#define vhpiCbEndOfSave                 1039\n#define vhpiCbStartOfRestart            1040\n#define vhpiCbEndOfRestart              1041\n#define vhpiCbStartOfReset              1042\n#define vhpiCbEndOfReset                1043\n#define vhpiCbEnterInteractive          1044 /* repetitive */\n#define vhpiCbExitInteractive           1045 /* repetitive */\n#define vhpiCbSigInterrupt              1046 /* repetitive */\n\n/* Foreign model callbacks */\n#define vhpiCbTimeOut                   1047 /* non repetitive */\n#define vhpiCbRepTimeOut                1048 /* repetitive */\n#define vhpiCbSensitivity               1049 /* repetitive */\n\n/**************************** CALLBACK FLAGS ******************************/\n#define vhpiReturnCb  0x00000001\n#define vhpiDisableCb 0x00000010\n\n/************** vhpiAutomaticRestoreP property values *************/\ntypedef enum\n{\n    vhpiRestoreAll       = 1,\n    vhpiRestoreUserData  = 2,\n    vhpiRestoreHandles   = 4,\n    vhpiRestoreCallbacks = 8\n} vhpiAutomaticRestoreT;\n\n\n/******************** FUNCTION DECLARATIONS *********************/\n\nXXTERN int vhpi_assert (vhpiSeverityT severity,\n                        const char *formatmsg,\n                        ...);\n\n/* callback related */\n\nXXTERN vhpiHandleT vhpi_register_cb (vhpiCbDataT *cb_data_p,\n                                     int32_t flags);\n\nXXTERN int vhpi_remove_cb (vhpiHandleT cb_obj);\n\nXXTERN int vhpi_disable_cb (vhpiHandleT cb_obj);\n\nXXTERN int vhpi_enable_cb (vhpiHandleT cb_obj);\n\nXXTERN int vhpi_get_cb_info (vhpiHandleT object,\n                             vhpiCbDataT *cb_data_p);\n\n/* utilities for sensitivity-set bitmaps */\n/* The replacement text for these macros is implementation defined */\n/* The behavior is specified in G.1 */\nXXTERN int vhpi_sens_first (vhpiValueT *sens);\n\nXXTERN int vhpi_sens_zero (vhpiValueT *sens);\n\nXXTERN int vhpi_sens_clr (int obj,\n                          vhpiValueT *sens);\n\nXXTERN int vhpi_sens_set (int obj,\n                         vhpiValueT *sens);\n\nXXTERN int vhpi_sens_isset (int obj,\n                            vhpiValueT *sens);\n\n#define VHPI_SENS_ZERO(sens)        vhpi_sens_zero(sens)\n#define VHPI_SENS_SET(obj, sens)    vhpi_sens_set(obj, sens)\n#define VHPI_SENS_CLR(obj, sens)    vhpi_sens_clr(obj, sens)\n#define VHPI_SENS_ISSET(obj, sens)  vhpi_sens_isset(obj, sens)\n#define VHPI_SENS_FIRST(sens)       vhpi_sens_first(sens)\n\n/* for obtaining handles */\n\nXXTERN vhpiHandleT vhpi_handle_by_name (const char *name,\n                                        vhpiHandleT scope);\n\nXXTERN vhpiHandleT vhpi_handle_by_index (vhpiOneToManyT itRel,\n                                         vhpiHandleT parent,\n                                         int32_t indx);\n\n/* for traversing relationships */\n\nXXTERN vhpiHandleT vhpi_handle (vhpiOneToOneT type,\n                                vhpiHandleT referenceHandle);\n\nXXTERN vhpiHandleT vhpi_iterator (vhpiOneToManyT type,\n                                  vhpiHandleT referenceHandle);\n\nXXTERN vhpiHandleT vhpi_scan (vhpiHandleT iterator);\n\n/* for processsing properties */\n\nXXTERN vhpiIntT vhpi_get (vhpiIntPropertyT property,\n                          vhpiHandleT object);\n\nXXTERN const vhpiCharT * vhpi_get_str (vhpiStrPropertyT property,\n                                       vhpiHandleT object);\n\nXXTERN vhpiRealT vhpi_get_real (vhpiRealPropertyT property,\n                                vhpiHandleT object);\n\nXXTERN vhpiPhysT vhpi_get_phys (vhpiPhysPropertyT property,\n                                vhpiHandleT object);\n\n/* for access to protected types */\n\ntypedef int (*vhpiUserFctT)(void);\n\nXXTERN int vhpi_protected_call (vhpiHandleT varHdl,\n                                vhpiUserFctT userFct,\n                                void *userData);\n\n/* value processing */\n\n/* vhpi_put_value flags */\ntypedef enum\n{\n  vhpiDeposit,\n  vhpiDepositPropagate,\n  vhpiForce,\n  vhpiForcePropagate,\n  vhpiRelease,\n  vhpiSizeConstraint\n} vhpiPutValueModeT;\n\ntypedef enum\n{\n  vhpiInertial,\n  vhpiTransport\n} vhpiDelayModeT;\n\nXXTERN int vhpi_get_value (vhpiHandleT expr,\n                           vhpiValueT *value_p);\n\nXXTERN int vhpi_put_value (vhpiHandleT object,\n                           vhpiValueT *value_p,\n                           vhpiPutValueModeT flags);\n\nXXTERN int vhpi_schedule_transaction (vhpiHandleT drivHdl,\n                                      vhpiValueT *value_p,\n                                      uint32_t numValues,\n                                      vhpiTimeT *delayp,\n                                      vhpiDelayModeT delayMode,\n                                      vhpiTimeT *pulseRejp);\n\nXXTERN int vhpi_format_value (const vhpiValueT *in_value_p,\n                              vhpiValueT *out_value_p);\n\n/* time processing */\n\nXXTERN void vhpi_get_time (vhpiTimeT *time_p,\n                           long *cycles);\n\n#define vhpiNoActivity -1\n\nXXTERN int vhpi_get_next_time (vhpiTimeT *time_p);\n\n/* simulation control */\n\ntypedef enum\n{\n  vhpiStop     = 0,\n  vhpiFinish   = 1,\n  vhpiReset    = 2\n\n#ifdef VHPIEXTEND_CONTROL\n  VHPIEXTEND_CONTROL\n#endif\n} vhpiSimControlT;\n\nXXTERN int vhpi_control (vhpiSimControlT command,\n                         ...);\n\nXXTERN int vhpi_sim_control (vhpiSimControlT command); /* for compatibility reasons */\n\n/* I/O routine */\n\nXXTERN int vhpi_printf (const char *format,\n                        ...);\n\nXXTERN int vhpi_vprintf (const char *format,\n                         va_list args);\n\n/* utilities to print VHDL strings */\n\nXXTERN int vhpi_is_printable(char ch);\n\n\n/* utility routines */\n\nXXTERN int vhpi_compare_handles (vhpiHandleT handle1,\n                                 vhpiHandleT handle2);\n\nXXTERN int vhpi_check_error (vhpiErrorInfoT *error_info_p);\n\nXXTERN int vhpi_release_handle (vhpiHandleT object);\n\n/* creation functions */\n\nXXTERN vhpiHandleT vhpi_create (vhpiClassKindT kind,\n                                vhpiHandleT handle1,\n                                vhpiHandleT handle2);\n\n/* Foreign model data structures and functions */\n\ntypedef enum\n{\n   vhpiArchF   = 1,\n   vhpiArchFK  = 1, /* for compatibility reasons */\n   vhpiFuncF   = 2,\n   vhpiFuncFK  = 2, /* for compatibility reasons */\n   vhpiProcF   = 3,\n   vhpiProcFK  = 3, /* for compatibility reasons */\n   vhpiLibF    = 4,\n   vhpiAppF    = 5\n} vhpiForeignT;\n\ntypedef struct vhpiForeignDataS\n{\n\tvhpiForeignT kind;\n\tchar * libraryName;\n\tchar * modelName;\n\tvoid (*elabf)(const struct vhpiCbDataS *cb_data_p);\n\tvoid (*execf)(const struct vhpiCbDataS *cb_data_p);\n} vhpiForeignDataT;\n\nXXTERN vhpiHandleT vhpi_register_foreignf (vhpiForeignDataT *foreignDatap);\n\nXXTERN int vhpi_get_foreignf_info (vhpiHandleT hdl,\n                                   vhpiForeignDataT *foreignDatap);\n\n/* vhpi_get_foreign_info is DEPRECATED */\nXXTERN int vhpi_get_foreign_info (vhpiHandleT hdl,\n                                  vhpiForeignDataT *foreignDatap);\n\n/* for saving and restoring foreign models data */\n\nXXTERN size_t vhpi_get_data (int32_t id,\n                             void *dataLoc,\n                             size_t numBytes);\n\nXXTERN size_t vhpi_put_data (int32_t id,\n                             void *dataLoc,\n                             size_t numBytes);\n\n#ifdef VHPIEXTEND_FUNCTIONS\n       VHPIEXTEND_FUNCTIONS\n#endif\n\n/* Visual Elite integration - Cause & Effect support\n   Function returns instance handle for specified signal\n   Warning!!! Function each time allocates new handle for returned instance, so you should free it !!! */\nXXTERN vhpiHandleT vhpi_get_cause_instance (vhpiHandleT sigHandle);\n\n/* Function returns source point number to code which made event on specified signal */\nXXTERN int vhpi_get_cause (vhpiHandleT sigHandle,\n                           unsigned int** p2MagicNumbersBuffer);\n\n/* Function returns info about line nr and instance hierarchy path for specified source point nr\n   and instance handle\n    returns:\n        For invalid source point: *pnLineNr == -1\n        For insufficient buffer size, returns required buffer size\n        For invalid args function returns -1\n        If all is OK, function returns 0 */\nXXTERN int vhpi_get_cause_info (const unsigned int** pn2MagicNumbers,\n                                int nBufLen,\n                                char* pszHierScopeBuf,\n                                int nFilePathBufLen,\n                                char* pszSourceFilePathBuf,\n                                int* pnLineNr);\n\n/*\n* vhpi_value_size()\n*\n* Description:\n* The vhpi_value_size() function lets you query the size in bytes\n* required for a buffer to store the value of the specified object handle\n* in the specified format. Use this function to allocate memory for the\n* appropriate field of the value structure before using\n* vphi_get_value() or vhpi_put_value().\n*\n* Returns the size in bytes required for a buffer to store the value of\n* the specified object handle in the specified format.\n*\n* Syntax: vhpi_value_size(vhpiHandleT objHdl, vhpiFormatT format)\n*   Returns: vhpiIntT Size in bytes\n*\n* Arguments:\n*   VhpiHandleT objHdl Object handle whose value is needed.\n*   VhpiFormatT format Format in which the value needs to be represented\n*\n*******************************************************************************/\n\nXXTERN vhpiIntT vhpi_value_size (vhpiHandleT objHdl,\n                                 vhpiFormatT format);\n\n/**************************** Typedef for VHPI bootstrap functions\n ****************************/\n\ntypedef void (*vhpiBootstrapFctT)(void);\n\n\n#undef PLI_EXTERN\n#undef PLI_VEXTERN\n\n#ifdef VHPI_USER_DEFINED_DLLISPEC\n    #undef VHPI_USER_DEFINED_DLLISPEC\n    #undef PLI_DLLISPEC\n#endif\n#ifdef VHPI_USER_DEFINED_DLLESPEC\n    #undef VHPI_USER_DEFINED_DLLESPEC\n    #undef PLI_DLLESPEC\n#endif\n\n#ifdef PLI_PROTOTYPES\n    #undef PLI_PROTOTYPES\n    #undef XXTERN\n    #undef EETERN\n#endif\n\n#ifdef  __cplusplus\n}\n#endif\n\n#pragma pack()\n\n#endif /* VHPI_USER_H */\n"
  },
  {
    "path": "src/cocotb/_vendor/vpi/sv_vpi_user.h",
    "content": "/***************************************************************************\n* sv_vpi_user.h\n*\n* SystemVerilog VPI extensions.\n*\n* This file contains the constant definitions, structure definitions, and\n* routine declarations used by the SystemVerilog Verification Procedural\n* Interface (VPI) access routines.\n*\n***************************************************************************/\n\n/***************************************************************************\n* NOTE:\n* The constant values 600 through 999 are reserved for use in this file.\n* - the range 600-749 is reserved for SV VPI model extensions\n* - the range 750-779 is reserved for the Coverage VPI\n* - the range 800-899 is reserved for future use\n* Overlaps in the numerical ranges are permitted for different categories\n* of identifiers; e.g.\n* - object types\n* - properties\n* - callbacks\n**************************************************************************/\n\n#ifndef SV_VPI_USER_H\n#define SV_VPI_USER_H\n\n#include \"vpi_user.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/****************************** OBJECT TYPES ******************************/\n#define vpiPackage                            600\n#define vpiInterface                          601\n#define vpiProgram                            602\n#define vpiInterfaceArray                     603\n#define vpiProgramArray                       604\n#define vpiTypespec                           605\n#define vpiModport                            606\n#define vpiInterfaceTfDecl                    607\n#define vpiRefObj                             608\n#define vpiTypeParameter                      609\n\n/* variables */\n#define vpiVarBit                             vpiRegBit\n#define vpiLongIntVar                         610\n#define vpiShortIntVar                        611\n#define vpiIntVar                             612\n#define vpiShortRealVar                       613\n#define vpiByteVar                            614\n#define vpiClassVar                           615\n#define vpiStringVar                          616\n#define vpiEnumVar                            617\n#define vpiStructVar                          618\n#define vpiUnionVar                           619\n#define vpiBitVar                             620\n#define vpiLogicVar                           vpiReg\n#define vpiArrayVar                           vpiRegArray\n#define vpiClassObj                           621\n#define vpiChandleVar                         622\n#define vpiPackedArrayVar                     623\n#define vpiVirtualInterfaceVar                728\n\n/* typespecs */\n#define vpiLongIntTypespec                    625\n#define vpiShortRealTypespec                  626\n#define vpiByteTypespec                       627\n#define vpiShortIntTypespec                   628\n#define vpiIntTypespec                        629\n#define vpiClassTypespec                      630\n#define vpiStringTypespec                     631\n#define vpiChandleTypespec                    632\n#define vpiEnumTypespec                       633\n#define vpiEnumConst                          634\n#define vpiIntegerTypespec                    635\n#define vpiTimeTypespec                       636\n#define vpiRealTypespec                       637\n#define vpiStructTypespec                     638\n#define vpiUnionTypespec                      639\n#define vpiBitTypespec                        640\n#define vpiLogicTypespec                      641\n#define vpiArrayTypespec                      642\n#define vpiVoidTypespec                       643\n#define vpiTypespecMember                     644\n#define vpiPackedArrayTypespec                692\n#define vpiSequenceTypespec                   696\n#define vpiPropertyTypespec                   697\n#define vpiEventTypespec                      698\n#define vpiInterfaceTypespec                  906\n\n#define vpiClockingBlock                      650\n#define vpiClockingIODecl                     651\n#define vpiClassDefn                          652\n#define vpiConstraint                         653\n#define vpiConstraintOrdering                 654\n\n#define vpiDistItem                           645\n#define vpiAliasStmt                          646\n#define vpiThread                             647\n#define vpiMethodFuncCall                     648\n#define vpiMethodTaskCall                     649\n\n/* concurrent assertions */\n#define vpiAssert                             686\n#define vpiAssume                             687\n#define vpiCover                              688\n#define vpiRestrict                           901\n#define vpiDisableCondition                   689\n#define vpiClockingEvent                      690\n\n/* property decl, spec */\n#define vpiPropertyDecl                       655\n#define vpiPropertySpec                       656\n#define vpiPropertyExpr                       657\n#define vpiMulticlockSequenceExpr             658\n#define vpiClockedSeq                         659\n#define vpiClockedProp                        902\n#define vpiPropertyInst                       660\n#define vpiSequenceDecl                       661\n#define vpiCaseProperty                       662 /* property case */\n#define vpiCasePropertyItem                   905 /* property case item */\n#define vpiSequenceInst                       664\n#define vpiImmediateAssert                    665\n#define vpiImmediateAssume                    694\n#define vpiImmediateCover                     695\n#define vpiReturn                             666\n/* pattern */\n#define vpiAnyPattern                         667\n#define vpiTaggedPattern                      668\n#define vpiStructPattern                      669\n/* do .. while */\n#define vpiDoWhile                            670\n/* waits */\n#define vpiOrderedWait                        671\n#define vpiWaitFork                           672\n/* disables */\n#define vpiDisableFork                        673\n#define vpiExpectStmt                         674\n#define vpiForeachStmt                        675\n#define vpiReturnStmt                         691\n#define vpiFinal                              676\n#define vpiExtends                            677\n#define vpiDistribution                       678\n#define vpiSeqFormalDecl                      679\n#define vpiPropFormalDecl                     699\n#define vpiArrayNet                           vpiNetArray\n#define vpiEnumNet                            680\n#define vpiIntegerNet                         681\n#define vpiLogicNet                           vpiNet\n#define vpiTimeNet                            682\n#define vpiUnionNet                           525\n#define vpiShortRealNet                       526\n#define vpiRealNet                            527\n#define vpiByteNet                            528\n#define vpiShortIntNet                        529\n#define vpiIntNet                             530\n#define vpiLongIntNet                         531\n#define vpiBitNet                             532\n#define vpiStructNet                          683\n#define vpiBreak                              684\n#define vpiContinue                           685\n#define vpiPackedArrayNet                     693\n#define vpiConstraintExpr                     747\n#define vpiElseConst                          748\n#define vpiImplication                        749\n#define vpiConstrIf                           738\n#define vpiConstrIfElse                       739\n#define vpiConstrForEach                      736\n#define vpiSoftDisable                        733\n#define vpiLetDecl                            903\n#define vpiLetExpr                            904\n\n/******************************** METHODS *********************************/\n/************* methods used to traverse 1 to 1 relationships **************/\n#define vpiActual                             700\n\n#define vpiTypedefAlias                       701\n\n#define vpiIndexTypespec                      702\n#define vpiBaseTypespec                       703\n#define vpiElemTypespec                       704\n\n#define vpiInputSkew                          706\n#define vpiOutputSkew                         707\n#define vpiGlobalClocking                     708\n#define vpiDefaultClocking                    709\n#define vpiDefaultDisableIff                  710\n\n#define vpiOrigin                             713\n#define vpiPrefix                             714\n#define vpiWith                               715\n\n#define vpiProperty                           718\n\n#define vpiValueRange                         720\n#define vpiPattern                            721\n#define vpiWeight                             722\n#define vpiConstraintItem                     746\n\n/************ methods used to traverse 1 to many relationships ************/\n#define vpiTypedef                            725\n#define vpiImport                             726\n#define vpiDerivedClasses                     727\n#define vpiInterfaceDecl vpiVirtualInterfaceVar /* interface decl deprecated */\n\n#define vpiMethods                            730\n#define vpiSolveBefore                        731\n#define vpiSolveAfter                         732\n\n#define vpiWaitingProcesses                   734\n\n#define vpiMessages                           735\n#define vpiLoopVars                           737\n\n#define vpiConcurrentAssertions               740\n#define vpiMatchItem                          741\n#define vpiMember                             742\n#define vpiElement                            743\n\n/************* methods used to traverse 1 to many relationships ***************/\n#define vpiAssertion                          744\n\n/*********** methods used to traverse both 1-1 and 1-many relations ***********/\n#define vpiInstance                           745\n\n/**************************************************************************/\n/************************ generic object properties ***********************/\n/**************************************************************************/\n\n#define vpiTop                                600\n\n#define vpiUnit                               602\n#define vpiJoinType                           603\n#define vpiJoin                                 0\n#define vpiJoinNone                             1\n#define vpiJoinAny                              2\n#define vpiAccessType                         604\n#define vpiForkJoinAcc                          1\n#define vpiExternAcc                            2\n#define vpiDPIExportAcc                         3\n#define vpiDPIImportAcc                         4\n\n#define vpiArrayType                          606\n#define vpiStaticArray                          1\n#define vpiDynamicArray                         2\n#define vpiAssocArray                           3\n#define vpiQueueArray                           4\n#define vpiArrayMember                        607\n\n#define vpiIsRandomized                       608\n#define vpiLocalVarDecls                      609\n#define vpiOpStrong                           656 /* strength of temporal operator */\n#define vpiRandType                           610\n#define vpiNotRand                              1\n#define vpiRand                                 2\n#define vpiRandC                                3\n#define vpiPortType                           611\n#define vpiInterfacePort                        1\n#define vpiModportPort                          2\n/* vpiPort is also a port type. It is defined in vpi_user.h */\n\n#define vpiConstantVariable                   612\n#define vpiStructUnionMember                  615\n\n#define vpiVisibility                         620\n#define vpiPublicVis                            1\n#define vpiProtectedVis                         2\n#define vpiLocalVis                             3\n/* Return values for vpiConstType property */\n\n#define vpiOneStepConst                         9\n#define vpiUnboundedConst                      10\n#define vpiNullConst                           11\n\n#define vpiAlwaysType                         624\n#define vpiAlwaysComb                           2\n#define vpiAlwaysFF                             3\n#define vpiAlwaysLatch                          4\n\n#define vpiDistType                           625\n#define vpiEqualDist                            1 /* constraint equal distribution */\n#define vpiDivDist                              2 /* constraint divided distribution */\n\n#define vpiPacked                             630\n#define vpiTagged                             632\n#define vpiRef                                  6 /* Return value for vpiDirection property */\n#define vpiVirtual                            635\n#define vpiHasActual                          636\n#define vpiIsConstraintEnabled                638\n#define vpiSoft                               639\n\n\n#define vpiClassType                          640\n#define vpiMailboxClass                         1\n#define vpiSemaphoreClass                       2\n#define vpiUserDefinedClass                     3\n#define vpiProcessClass                         4\n\n#define vpiMethod                             645\n#define vpiIsClockInferred                    649\n#define vpiIsDeferred                         657\n#define vpiIsFinal                            670\n#define vpiIsCoverSequence                    659\n#define vpiQualifier                          650\n#define vpiNoQualifier                          0\n#define vpiUniqueQualifier                      1\n#define vpiPriorityQualifier                    2\n#define vpiTaggedQualifier                      4\n#define vpiRandQualifier                        8\n#define vpiInsideQualifier                     16\n\n#define vpiInputEdge                          651 /* returns vpiNoEdge, vpiPosedge, vpiNegedge */\n#define vpiOutputEdge                         652 /* returns vpiNoEdge, vpiPosedge, vpiNegedge */\n#define vpiGeneric                            653\n\n/* Compatibility-mode property and values (object argument == NULL) */\n#define vpiCompatibilityMode                  654\n#define vpiMode1364v1995                        1\n#define vpiMode1364v2001                        2\n#define vpiMode1364v2005                        3\n#define vpiMode1800v2005                        4\n#define vpiMode1800v2009                        5\n\n#define vpiPackedArrayMember                  655\n#define vpiStartLine                          661\n#define vpiColumn                             662\n#define vpiEndLine                            663\n#define vpiEndColumn                          664\n\n/* memory allocation scheme for transient objects */\n#define vpiAllocScheme                        658\n#define vpiAutomaticScheme                      1\n#define vpiDynamicScheme                        2\n#define vpiOtherScheme                          3\n\n#define vpiObjId                              660\n\n#define vpiDPIPure                            665\n#define vpiDPIContext                         666\n#define vpiDPICStr                            667\n#define vpiDPI                                  1\n#define vpiDPIC                                 2\n#define vpiDPICIdentifier                     668\n#define vpiIsModPort                          669\n\n/******************************** Operators *******************************/\n#define vpiImplyOp                             50 /* -> implication operator */\n#define vpiNonOverlapImplyOp                   51 /* |=> nonoverlapped implication */\n#define vpiOverlapImplyOp                      52 /* |-> overlapped implication operator */\n#define vpiAcceptOnOp                          83 /* accept_on operator */\n#define vpiRejectOnOp                          84 /* reject_on operator */\n#define vpiSyncAcceptOnOp                      85 /* sync_accept_on operator */\n#define vpiSyncRejectOnOp                      86 /* sync_reject_on operator */\n#define vpiOverlapFollowedByOp                 87 /* overlapped followed_by operator */\n#define vpiNonOverlapFollowedByOp              88 /* nonoverlapped followed_by operator */\n#define vpiNexttimeOp                          89 /* nexttime operator */\n#define vpiAlwaysOp                            90 /* always operator */\n#define vpiEventuallyOp                        91 /* eventually operator */\n#define vpiUntilOp                             92 /* until operator */\n#define vpiUntilWithOp                         93 /* until_with operator */\n\n#define vpiUnaryCycleDelayOp                   53 /* binary cycle delay (##) operator */\n#define vpiCycleDelayOp                        54 /* binary cycle delay (##) operator */\n#define vpiIntersectOp                         55 /* intersection operator */\n#define vpiFirstMatchOp                        56 /* first_match operator */\n#define vpiThroughoutOp                        57 /* throughout operator */\n#define vpiWithinOp                            58 /* within operator */\n#define vpiRepeatOp                            59 /* [=] nonconsecutive repetition */\n#define vpiConsecutiveRepeatOp                 60 /* [*] consecutive repetition */\n#define vpiGotoRepeatOp                        61 /* [->] goto repetition */\n\n#define vpiPostIncOp                           62 /* ++ post-increment */\n#define vpiPreIncOp                            63 /* ++ pre-increment */\n#define vpiPostDecOp                           64 /* -- post-decrement */\n#define vpiPreDecOp                            65 /* -- pre-decrement */\n\n#define vpiMatchOp                             66 /* match() operator */\n#define vpiCastOp                              67 /* type'() operator */\n#define vpiIffOp                               68 /* iff operator */\n#define vpiWildEqOp                            69 /* ==? operator */\n#define vpiWildNeqOp                           70 /* !=? operator */\n\n#define vpiStreamLROp                          71 /* left-to-right streaming {>>} operator */\n#define vpiStreamRLOp                          72 /* right-to-left streaming {<<} operator */\n\n#define vpiMatchedOp                           73 /* the .matched sequence operation */\n#define vpiTriggeredOp                         74 /* the .triggered sequence operation */\n#define vpiAssignmentPatternOp                 75 /* '{} assignment pattern */\n#define vpiMultiAssignmentPatternOp            76 /* '{n{}} multi assignment pattern */\n#define vpiIfOp                                77 /* if operator */\n#define vpiIfElseOp                            78 /* if-else operator */\n#define vpiCompAndOp                           79 /* Composite and operator */\n#define vpiCompOrOp                            80 /* Composite or operator */\n#define vpiImpliesOp                           94 /* implies operator */\n#define vpiInsideOp                            95 /* inside operator */\n#define vpiTypeOp                              81 /* type operator */\n#define vpiAssignmentOp                        82 /* Normal assignment */\n\n/*********************** task/function properties ***********************/\n#define vpiOtherFunc                            6 /* returns other types; for property vpiFuncType */\n\n/* vpiValid,vpiValidTrue,vpiValidFalse are deprecated in 1800-2009 */\n/*********************** value for vpiValid *****************************/\n#define vpiValidUnknown                         2 /* Validity of variable is unknown */\n\n/************************** STRUCTURE DEFINITIONS *************************/\n\n\n/***************************** structure *****************************/\n\n/**************************** CALLBACK REASONS ****************************/\n#define cbStartOfThread                       600 /* callback on thread creation */\n#define cbEndOfThread                         601 /* callback on thread termination */\n#define cbEnterThread                         602 /* callback on reentering thread */\n#define cbStartOfFrame                        603 /* callback on frame creation */\n#define cbEndOfFrame                          604 /* callback on frame exit */\n#define cbSizeChange                          605 /* callback on array variable size change */\n#define cbCreateObj                           700 /* callback on class object creation */\n#define cbReclaimObj                          701 /* callback on class object reclaimed by automatic memory management */\n\n#define cbEndOfObject                         702 /* callback on transient object deletion */\n\n/************************* FUNCTION DECLARATIONS **************************/\n\n\n/**************************************************************************/\n/*************************** Coverage VPI *********************************/\n/**************************************************************************/\n\n/* coverage control */\n#define vpiCoverageStart                      750\n#define vpiCoverageStOp                       751\n#define vpiCoverageReset                      752\n#define vpiCoverageCheck                      753\n#define vpiCoverageMerge                      754\n#define vpiCoverageSave                       755\n\n/* coverage type properties */\n#define vpiAssertCoverage                     760\n#define vpiFsmStateCoverage                   761\n#define vpiStatementCoverage                  762\n#define vpiToggleCoverage                     763\n\n/* coverage status properties */\n#define vpiCovered                            765\n#define vpiCoverMax                           766  /* preserved for backward compatibility */\n#define vpiCoveredMax                         766\n#define vpiCoveredCount                       767\n\n/* assertion-specific coverage status properties */\n#define vpiAssertAttemptCovered               770\n#define vpiAssertSuccessCovered               771\n#define vpiAssertFailureCovered               772\n#define vpiAssertVacuousSuccessCovered        773\n#define vpiAssertDisableCovered               774\n#define vpiAssertKillCovered                  777\n\n/* FSM-specific coverage status properties */\n#define vpiFsmStates                          775\n#define vpiFsmStateExpression                 776\n\n/* FSM handle types */\n#define vpiFsm                                758\n#define vpiFsmHandle                          759\n\n\n/***************************************************************************/\n/***************************** Assertion VPI *******************************/\n/***************************************************************************/\n/* assertion callback types */\n#define cbAssertionStart                      606\n#define cbAssertionSuccess                    607\n#define cbAssertionFailure                    608\n#define cbAssertionVacuousSuccess             657\n#define cbAssertionDisabledEvaluation         658\n#define cbAssertionStepSuccess                609\n#define cbAssertionStepFailure                610\n#define cbAssertionLock                       661\n#define cbAssertionUnlock                     662\n#define cbAssertionDisable                    611\n#define cbAssertionEnable                     612\n#define cbAssertionReset                      613\n#define cbAssertionKill                       614\n#define cbAssertionEnablePassAction           645\n#define cbAssertionEnableFailAction           646\n#define cbAssertionDisablePassAction          647\n#define cbAssertionDisableFailAction          648\n#define cbAssertionEnableNonvacuousAction     649\n#define cbAssertionDisableVacuousAction       650\n\n/* assertion \"system\" callback types */\n#define cbAssertionSysInitialized             615\n#define cbAssertionSysOn                      616\n#define cbAssertionSysOff                     617\n#define cbAssertionSysKill                    631\n#define cbAssertionSysLock                    659\n#define cbAssertionSysUnlock                  660\n#define cbAssertionSysEnd                     618\n#define cbAssertionSysReset                   619\n#define cbAssertionSysEnablePassAction        651\n#define cbAssertionSysEnableFailAction        652\n#define cbAssertionSysDisablePassAction       653\n#define cbAssertionSysDisableFailAction       654\n#define cbAssertionSysEnableNonvacuousAction  655\n#define cbAssertionSysDisableVacuousAction    656\n\n/* assertion control constants */\n#define vpiAssertionLock                      645\n#define vpiAssertionUnlock                    646\n#define vpiAssertionDisable                   620\n#define vpiAssertionEnable                    621\n#define vpiAssertionReset                     622\n#define vpiAssertionKill                      623\n#define vpiAssertionEnableStep                624\n#define vpiAssertionDisableStep               625\n#define vpiAssertionClockSteps                626\n#define vpiAssertionSysLock                   647\n#define vpiAssertionSysUnlock                 648\n#define vpiAssertionSysOn                     627\n#define vpiAssertionSysOff                    628\n#define vpiAssertionSysKill                   632\n#define vpiAssertionSysEnd                    629\n#define vpiAssertionSysReset                  630\n#define vpiAssertionDisablePassAction         633\n#define vpiAssertionEnablePassAction          634\n#define vpiAssertionDisableFailAction         635\n#define vpiAssertionEnableFailAction          636\n#define vpiAssertionDisableVacuousAction      637\n#define vpiAssertionEnableNonvacuousAction    638\n#define vpiAssertionSysEnablePassAction       639\n#define vpiAssertionSysEnableFailAction       640\n#define vpiAssertionSysDisablePassAction      641\n#define vpiAssertionSysDisableFailAction      642\n#define vpiAssertionSysEnableNonvacuousAction 643\n#define vpiAssertionSysDisableVacuousAction   644\n\n\ntypedef struct t_vpi_assertion_step_info {\n   PLI_INT32 matched_expression_count;\n   vpiHandle *matched_exprs;        /* array of expressions */\n   PLI_INT32 stateFrom, stateTo;    /* identify transition */\n} s_vpi_assertion_step_info, *p_vpi_assertion_step_info;\n\ntypedef struct t_vpi_attempt_info {\n   union {\n      vpiHandle failExpr;\n      p_vpi_assertion_step_info step;\n   } detail;\n   s_vpi_time attemptStartTime;     /* Time attempt triggered */\n} s_vpi_attempt_info, *p_vpi_attempt_info;\n\n/* typedef for vpi_register_assertion_cb callback function */\ntypedef PLI_INT32(vpi_assertion_callback_func)(\n   PLI_INT32 reason,                /* callback reason */\n   p_vpi_time cb_time,              /* callback time */\n   vpiHandle assertion,             /* handle to assertion */\n   p_vpi_attempt_info info,         /* attempt related information */\n   PLI_BYTE8 *user_data             /* user data entered upon registration */\n);\n\nvpiHandle vpi_register_assertion_cb(\n   vpiHandle assertion,             /* handle to assertion */\n   PLI_INT32 reason,                /* reason for which callbacks needed */\n   vpi_assertion_callback_func *cb_rtn,\n   PLI_BYTE8 *user_data             /* user data to be supplied to cb */\n);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/cocotb/_vendor/vpi/vpi_compatibility.h",
    "content": "/*******************************************************************************\n* vpi_compatibility.h\n*\n* IEEE Std 1800-2023 SystemVerilog Verification Procedural Interface (VPI)\n*\n* NOTE: THIS FILE IS INCLUDED BY vpi_user.h. DO NOT INCLUDE THIS FILE FROM\n* USER APPLICATION CODE.\n*\n* This file contains the macro definitions used by the SystemVerilog PLI\n* to implement backwards compatibility mode functionality.\n*\n******************************************************************************/\n#ifdef VPI_COMPATIBILITY_H\n#error \"The vpi_compatibility.h file can only be included by vpi_user.h directly.\"\n#endif\n#define VPI_COMPATIBILITY_H\n/* Compatibility-mode variants of functions */\n#if VPI_COMPATIBILITY_VERSION_1800v2023\n  #define VPI_COMPATIBILITY_VERSION_1800v2012\n#endif\n#if VPI_COMPATIBILITY_VERSION_1800v2017\n  #define VPI_COMPATIBILITY_VERSION_1800v2012\n#endif\n#if VPI_COMPATIBILITY_VERSION_1364v1995\n#if VPI_COMPATIBILITY_VERSION_1364v2001 || VPI_COMPATIBILITY_VERSION_1364v2005\n  || VPI_COMPATIBILITY_VERSION_1800v2005 || VPI_COMPATIBILITY_VERSION_1800v2009\n  || VPI_COMPATIBILITY_VERSION_1800v2012\n#error \"Only one VPI_COMPATIBILITY_VERSION symbol definition is allowed.\"\n#endif\n#define vpi_compare_objects vpi_compare_objects_1364v1995\n#define vpi_control vpi_control_1364v1995\n#define vpi_get vpi_get_1364v1995\n#define vpi_get_str vpi_get_str_1364v1995\n#define vpi_get_value vpi_get_value_1364v1995\n#define vpi_handle vpi_handle_1364v1995\n#define vpi_handle_by_index vpi_handle_by_index_1364v1995\n#define vpi_handle_by_multi_index vpi_handle_by_multi_index_1364v1995\n#define vpi_handle_by_name vpi_handle_by_name_1364v1995\n#define vpi_handle_multi vpi_handle_multi_1364v1995\n#define vpi_iterate vpi_iterate_1364v1995\n#define vpi_put_value vpi_put_value_1364v1995\n#define vpi_register_cb vpi_register_cb_1364v1995\n#define vpi_scan vpi_scan_1364v1995\n#elif VPI_COMPATIBILITY_VERSION_1364v2001\n#if VPI_COMPATIBILITY_VERSION_1364v1995 || VPI_COMPATIBILITY_VERSION_1364v2005\n  || VPI_COMPATIBILITY_VERSION_1800v2005 || VPI_COMPATIBILITY_VERSION_1800v2009\n  || VPI_COMPATIBILITY_VERSION_1800v2012\n#error \"Only one VPI_COMPATIBILITY_VERSION symbol definition is allowed.\"\n#endif\n#define vpi_compare_objects vpi_compare_objects_1364v2001\n#define vpi_control vpi_control_1364v2001\n#define vpi_get vpi_get_1364v2001\n#define vpi_get_str vpi_get_str_1364v2001\n#define vpi_get_value vpi_get_value_1364v2001\n#define vpi_handle vpi_handle_1364v2001\n#define vpi_handle_by_index vpi_handle_by_index_1364v2001\n#define vpi_handle_by_multi_index vpi_handle_by_multi_index_1364v2001\n#define vpi_handle_by_name vpi_handle_by_name_1364v2001\n#define vpi_handle_multi vpi_handle_multi_1364v2001\n#define vpi_iterate vpi_iterate_1364v2001\n#define vpi_put_value vpi_put_value_1364v2001\n#define vpi_register_cb vpi_register_cb_1364v2001\n#define vpi_scan vpi_scan_1364v2001\n#elif VPI_COMPATIBILITY_VERSION_1364v2005\n#if VPI_COMPATIBILITY_VERSION_1364v1995 || VPI_COMPATIBILITY_VERSION_1364v2001\n  || VPI_COMPATIBILITY_VERSION_1800v2005 || VPI_COMPATIBILITY_VERSION_1800v2009\n  || VPI_COMPATIBILITY_VERSION_1800v2012\n#error \"Only one VPI_COMPATIBILITY_VERSION symbol definition is allowed.\"\n#endif\n#define vpi_compare_objects vpi_compare_objects_1364v2005\n#define vpi_control vpi_control_1364v2005\n#define vpi_get vpi_get_1364v2005\n#define vpi_get_str vpi_get_str_1364v2005\n#define vpi_get_value vpi_get_value_1364v2005\n#define vpi_handle vpi_handle_1364v2005\n#define vpi_handle_by_index vpi_handle_by_index_1364v2005\n#define vpi_handle_by_multi_index vpi_handle_by_multi_index_1364v2005\n#define vpi_handle_by_name vpi_handle_by_name_1364v2005\n#define vpi_handle_multi vpi_handle_multi_1364v2005\n#define vpi_iterate vpi_iterate_1364v2005\n#define vpi_put_value vpi_put_value_1364v2005\n#define vpi_register_cb vpi_register_cb_1364v2005\n#define vpi_scan vpi_scan_1364v2005\n#elif VPI_COMPATIBILITY_VERSION_1800v2005\n#if VPI_COMPATIBILITY_VERSION_1364v1995 || VPI_COMPATIBILITY_VERSION_1364v2001\n  || VPI_COMPATIBILITY_VERSION_1364v2005 || VPI_COMPATIBILITY_VERSION_1800v2009\n  || VPI_COMPATIBILITY_VERSION_1800v2012\n#error \"Only one VPI_COMPATIBILITY_VERSION symbol definition is allowed.\"\n#endif\n#define vpi_compare_objects vpi_compare_objects_1800v2005\n#define vpi_control vpi_control_1800v2005\n#define vpi_get vpi_get_1800v2005\n#define vpi_get_str vpi_get_str_1800v2005\n#define vpi_get_value vpi_get_value_1800v2005\n#define vpi_handle vpi_handle_1800v2005\n#define vpi_handle_by_index vpi_handle_by_index_1800v2005\n#define vpi_handle_by_multi_index vpi_handle_by_multi_index_1800v2005\n#define vpi_handle_by_name vpi_handle_by_name_1800v2005\n#define vpi_handle_multi vpi_handle_multi_1800v2005\n#define vpi_iterate vpi_iterate_1800v2005\n#define vpi_put_value vpi_put_value_1800v2005\n#define vpi_register_cb vpi_register_cb_1800v2005\n#define vpi_scan vpi_scan_1800v2005\n#elif VPI_COMPATIBILITY_VERSION_1800v2009\n#if VPI_COMPATIBILITY_VERSION_1364v1995 || VPI_COMPATIBILITY_VERSION_1364v2001\n  || VPI_COMPATIBILITY_VERSION_1364v2005 || VPI_COMPATIBILITY_VERSION_1800v2005\n  || VPI_COMPATIBILITY_VERSION_1800v2012\n#error \"Only one VPI_COMPATIBILITY_VERSION symbol definition is allowed.\"\n#endif\n#define vpi_compare_objects vpi_compare_objects_1800v2009\n#define vpi_control vpi_control_1800v2009\n#define vpi_get vpi_get_1800v2009\n#define vpi_get_str vpi_get_str_1800v2009\n#define vpi_get_value vpi_get_value_1800v2009\n#define vpi_handle vpi_handle_1800v2009\n#define vpi_handle_by_index vpi_handle_by_index_1800v2009\n#define vpi_handle_by_multi_index vpi_handle_by_multi_index_1800v2009\n#define vpi_handle_by_name vpi_handle_by_name_1800v2009\n#define vpi_handle_multi vpi_handle_multi_1800v2009\n#define vpi_iterate vpi_iterate_1800v2009\n#define vpi_put_value vpi_put_value_1800v2009\n#define vpi_register_cb vpi_register_cb_1800v2009\n#define vpi_scan vpi_scan_1800v2009\n#elif VPI_COMPATIBILITY_VERSION_1800v2012\n#if VPI_COMPATIBILITY_VERSION_1364v1995 || VPI_COMPATIBILITY_VERSION_1364v2001\n  || VPI_COMPATIBILITY_VERSION_1364v2005 || VPI_COMPATIBILITY_VERSION_1800v2005\n  || VPI_COMPATIBILITY_VERSION_1800v2009\n#error \"Only one VPI_COMPATIBILITY_VERSION symbol definition is allowed.\"\n#endif\n#define vpi_compare_objects vpi_compare_objects_1800v2012\n#define vpi_control vpi_control_1800v2012\n#define vpi_get vpi_get_1800v2012\n#define vpi_get_str vpi_get_str_1800v2012\n#define vpi_get_value vpi_get_value_1800v2012\n#define vpi_handle vpi_handle_1800v2012\n#define vpi_handle_by_index vpi_handle_by_index_1800v2012\n#define vpi_handle_by_multi_index vpi_handle_by_multi_index_1800v2012\n#define vpi_handle_by_name vpi_handle_by_name_1800v2012\n#define vpi_handle_multi vpi_handle_multi_1800v2012\n#define vpi_iterate vpi_iterate_1800v2012\n#define vpi_put_value vpi_put_value_1800v2012\n#define vpi_register_cb vpi_register_cb_1800v2012\n#define vpi_scan vpi_scan_1800v2012\n#endif\n"
  },
  {
    "path": "src/cocotb/_vendor/vpi/vpi_user.h",
    "content": "/*******************************************************************************\n* vpi_user.h\n*\n* IEEE Std 1800 Programming Language Interface (PLI)\n*\n* This file contains the constant definitions, structure definitions, and\n* routine declarations used by the SystemVerilog Verification Procedural\n* Interface (VPI) access routines.\n*\n******************************************************************************/\n\n/*******************************************************************************\n * NOTE: the constant values 1 through 299 are reserved for use in this\n * vpi_user.h file.\n ******************************************************************************/\n\n#ifndef VPI_USER_H\n#define VPI_USER_H\n\n#include <stdarg.h>\n#include <stdint.h>\n\n#ifdef  __cplusplus\nextern \"C\" {\n#endif\n\n/*----------------------------------------------------------------------------*/\n/*----------------------------- Portability Help -----------------------------*/\n/*----------------------------------------------------------------------------*/\n\n/* Define size-critical types on all OS platforms. */\n\n/* Replaced the standard's implementation of fixed-width type definitions with */\n/* the definitions from stdint.h. */\n\n/* Sized variables */\n#ifndef SVPI_TYPES\n#define SVPI_TYPES\ntypedef int64_t PLI_INT64;\ntypedef uint64_t PLI_UINT64;\n#endif\n\n#ifndef PLI_TYPES\n#define PLI_TYPES\ntypedef int             PLI_INT32;\ntypedef unsigned int    PLI_UINT32;\ntypedef short           PLI_INT16;\ntypedef unsigned short  PLI_UINT16;\ntypedef char            PLI_BYTE8;\ntypedef unsigned char   PLI_UBYTE8;\n#endif\n\n/* Use to import a symbol */\n\n#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))\n#ifndef PLI_DLLISPEC\n#define PLI_DLLISPEC __declspec(dllimport)\n#define VPI_USER_DEFINED_DLLISPEC 1\n#endif\n#else\n#ifndef PLI_DLLISPEC\n#define PLI_DLLISPEC\n#endif\n#endif\n\n/* Use to export a symbol */\n\n#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))\n#ifndef PLI_DLLESPEC\n#define PLI_DLLESPEC __declspec(dllexport)\n#define VPI_USER_DEFINED_DLLESPEC 1\n#endif\n#else\n#ifndef PLI_DLLESPEC\n#define PLI_DLLESPEC\n#endif\n#endif\n\n/* Use to mark a function as external */\n\n#ifndef PLI_EXTERN\n#define PLI_EXTERN\n#endif\n\n/* Use to mark a variable as external */\n\n#ifndef PLI_VEXTERN\n#define PLI_VEXTERN extern\n#endif\n\n#ifndef PLI_PROTOTYPES\n#define PLI_PROTOTYPES\n#define PROTO_PARAMS(params) params\n/* object is defined imported by the application */\n#define XXTERN PLI_EXTERN PLI_DLLISPEC\n/* object is exported by the application */\n#define EETERN PLI_EXTERN PLI_DLLESPEC\n#endif\n\n/********************************** TYPEDEFS **********************************/\n\ntypedef PLI_UINT32 *vpiHandle;\n\n/******************************** OBJECT TYPES ********************************/\n\n#define vpiAlways            1 /* always procedure */\n#define vpiAssignStmt        2 /* quasi-continuous assignment */\n#define vpiAssignment        3 /* procedural assignment */\n#define vpiBegin             4 /* block statement */\n#define vpiCase              5 /* case statement */\n#define vpiCaseItem          6 /* case statement item */\n#define vpiConstant          7 /* numerical constant or string literal */\n#define vpiContAssign        8 /* continuous assignment */\n#define vpiDeassign          9 /* deassignment statement */\n#define vpiDefParam          10 /* defparam */\n#define vpiDelayControl      11 /* delay statement (e.g., #10) */\n#define vpiDisable           12 /* named block disable statement */\n#define vpiEventControl      13 /* wait on event, e.g., @e */\n#define vpiEventStmt         14 /* event trigger, e.g., ->e */\n#define vpiFor               15 /* for statement */\n#define vpiForce             16 /* force statement */\n#define vpiForever           17 /* forever statement */\n#define vpiFork              18 /* fork-join block */\n#define vpiFuncCall          19 /* function call */\n#define vpiFunction          20 /* function */\n#define vpiGate              21 /* primitive gate */\n#define vpiIf                22 /* if statement */\n#define vpiIfElse            23 /* if–else statement */\n#define vpiInitial           24 /* initial procedure */\n#define vpiIntegerVar        25 /* integer variable */\n#define vpiInterModPath      26 /* intermodule wire delay */\n#define vpiIterator          27 /* iterator */\n#define vpiIODecl            28 /* input/output declaration */\n#define vpiMemory            29 /* behavioral memory */\n#define vpiMemoryWord        30 /* single word of memory */\n#define vpiModPath           31 /* module path for path delays */\n#define vpiModule            32 /* module instance */\n#define vpiNamedBegin        33 /* named block statement */\n#define vpiNamedEvent        34 /* event variable */\n#define vpiNamedFork         35 /* named fork-join block */\n#define vpiNet               36 /* scalar or vector net */\n#define vpiNetBit            37 /* bit of vector net */\n#define vpiNullStmt          38 /* a semicolon. Ie. #10 ; */\n#define vpiOperation         39 /* behavioral operation */\n#define vpiParamAssign       40 /* module parameter assignment */\n#define vpiParameter         41 /* module parameter */\n#define vpiPartSelect        42 /* part-select */\n#define vpiPathTerm          43 /* terminal of module path */\n#define vpiPort              44 /* module port */\n#define vpiPortBit           45 /* bit of vector module port */\n#define vpiPrimTerm          46 /* primitive terminal */\n#define vpiRealVar           47 /* real variable */\n#define vpiReg               48 /* scalar or vector reg */\n#define vpiRegBit            49 /* bit of vector reg */\n#define vpiRelease           50 /* release statement */\n#define vpiRepeat            51 /* repeat statement */\n#define vpiRepeatControl     52 /* repeat control in an assign stmt */\n#define vpiSchedEvent        53 /* vpi_put_value() event */\n#define vpiSpecParam         54 /* specparam */\n#define vpiSwitch            55 /* transistor switch */\n#define vpiSysFuncCall       56 /* system function call */\n#define vpiSysTaskCall       57 /* system task call */\n#define vpiTableEntry        58 /* UDP state table entry */\n#define vpiTask              59 /* task */\n#define vpiTaskCall          60 /* task call */\n#define vpiTchk              61 /* timing check */\n#define vpiTchkTerm          62 /* terminal of timing check */\n#define vpiTimeVar           63 /* time variable */\n#define vpiTimeQueue         64 /* simulation event queue */\n#define vpiUdp               65 /* user-defined primitive */\n#define vpiUdpDefn           66 /* UDP definition */\n#define vpiUserSystf         67 /* user-defined system task/function */\n#define vpiVarSelect         68 /* variable array selection */\n#define vpiWait              69 /* wait statement */\n#define vpiWhile             70 /* while statement */\n\n/********************** object types added with 1364-2001 *********************/\n\n#define vpiAttribute         105   /* attribute of an object */\n#define vpiBitSelect         106   /* Bit-select of parameter, var select */\n#define vpiCallback          107   /* callback object */\n#define vpiDelayTerm         108   /* Delay term which is a load or driver */\n#define vpiDelayDevice       109   /* Delay object within a net */\n#define vpiFrame             110   /* reentrant task/func frame */\n#define vpiGateArray         111   /* gate instance array */\n#define vpiModuleArray       112   /* module instance array */\n#define vpiPrimitiveArray    113   /* vpiprimitiveArray type */\n#define vpiNetArray          114   /* multidimensional net */\n#define vpiRange             115   /* range declaration */\n#define vpiRegArray          116   /* multidimensional reg */\n#define vpiSwitchArray       117   /* switch instance array */\n#define vpiUdpArray          118   /* UDP instance array */\n#define vpiContAssignBit     128   /* Bit of a vector continuous assignment */\n#define vpiNamedEventArray   129   /* multidimensional named event */\n\n/********************** object types added with 1364-2005 *********************/\n\n#define vpiIndexedPartSelect 130   /* Indexed part-select object */\n#define vpiGenScopeArray     133   /* array of generated scopes */\n#define vpiGenScope          134   /* A generated scope */\n#define vpiGenVar            135   /* Object used to instantiate gen scopes */\n\n/*********************************** METHODS **********************************/\n/**************** methods used to traverse 1 to 1 relationships ***************/\n\n#define vpiCondition          71   /* condition expression */\n#define vpiDelay              72   /* net or gate delay */\n#define vpiElseStmt           73   /* else statement */\n#define vpiForIncStmt         74   /* increment statement in for loop */\n#define vpiForInitStmt        75   /* initialization statement in for loop */\n#define vpiHighConn           76   /* higher connection to port */\n#define vpiLhs                77   /* left-hand side of assignment */\n#define vpiIndex              78   /* index of var select, bit-select, etc. */\n#define vpiLeftRange          79   /* left range of vector or part-select */\n#define vpiLowConn            80   /* lower connection to port */\n#define vpiParent             81   /* parent object */\n#define vpiRhs                82   /* right-hand side of assignment */\n#define vpiRightRange         83   /* right range of vector or part-select */\n#define vpiScope              84   /* containing scope object */\n#define vpiSysTfCall          85   /* task function call */\n#define vpiTchkDataTerm       86   /* timing check data term */\n#define vpiTchkNotifier       87   /* timing check notifier */\n#define vpiTchkRefTerm        88   /* timing check reference term */\n\n/************* methods used to traverse 1 to many relationships ***************/\n\n#define vpiArgument           89   /* argument to (system) task/function */\n#define vpiBit                90   /* bit of vector net or port */\n#define vpiDriver             91   /* driver for a net */\n#define vpiInternalScope      92   /* internal scope in module */\n#define vpiLoad               93   /* load on net or reg */\n#define vpiModDataPathIn      94   /* data terminal of a module path */\n#define vpiModPathIn          95   /* Input terminal of a module path */\n#define vpiModPathOut         96   /* output terminal of a module path */\n#define vpiOperand            97   /* operand of expression */\n#define vpiPortInst           98   /* connected port instance */\n#define vpiProcess            99   /* process in module */\n#define vpiVariables         100   /* variables in module */\n#define vpiUse               101   /* usage */\n\n/******** methods which can traverse 1 to 1, or 1 to many relationships *******/\n\n#define vpiExpr              102   /* connected expression */\n#define vpiPrimitive         103   /* primitive (gate, switch, UDP) */\n#define vpiStmt              104   /* statement in process or task */\n\n/************************ methods added with 1364-2001 ************************/\n\n#define vpiActiveTimeFormat  119 /* active $timeformat() system task */\n#define vpiInTerm            120 /* To get to a delay device's drivers. */\n#define vpiInstanceArray     121 /* vpiInstance arrays */\n#define vpiLocalDriver       122 /* local drivers (within a module */\n#define vpiLocalLoad         123 /* local loads (within a module */\n#define vpiOutTerm           124 /* To get to a delay device's loads. */\n#define vpiPorts             125 /* Module port */\n#define vpiSimNet            126 /* simulated net after collapsing */\n#define vpiTaskFunc          127 /* task/function */\n\n/************************ methods added with 1364-2005 ************************/\n\n#define vpiBaseExpr          131   /* Indexed part-select's base expression  */\n#define vpiWidthExpr         132   /* Indexed part-select's width expression */\n\n/************************ methods added with 1800-2009 ************************/\n\n#define vpiAutomatics        136 /* Automatic variables of a frame */\n\n/********************************* PROPERTIES *********************************/\n/************************** generic object properties *************************/\n\n#define vpiUndefined             -1   /* undefined property */\n#define vpiType                   1   /* type of object */\n#define vpiName                   2   /* local name of object */\n#define vpiFullName               3   /* full hierarchical name */\n#define vpiSize                   4   /* size of gate, net, port, etc. */\n#define vpiFile                   5   /* File name in which the object is used*/\n#define vpiLineNo                 6   /* line number where the object is used */\n\n/***************************** module properties ******************************/\n\n#define vpiTopModule              7   /* top-level module (boolean) */\n#define vpiCellInstance           8   /* cell (boolean) */\n#define vpiDefName                9   /* module definition name */\n#define vpiProtected             10   /* source protected module (boolean) */\n#define vpiTimeUnit              11   /* module time unit */\n#define vpiTimePrecision         12   /* module time precision */\n#define vpiDefNetType            13   /* default net type */\n#define vpiUnconnDrive           14   /* unconnected port drive strength */\n#define vpiHighZ                   1   /* No default drive given */\n#define vpiPull1                   2   /* default pull1 drive */\n#define vpiPull0                   3   /* default pull0 drive */\n#define vpiDefFile               15   /* File name where the module is defined*/\n#define vpiDefLineNo             16   /* line number for module definition */\n#define vpiDefDelayMode          47   /* Default delay mode for a module */\n#define vpiDelayModeNone           1   /* no delay mode specified */\n#define vpiDelayModePath           2   /* path delay mode */\n#define vpiDelayModeDistrib        3   /* distributed delay mode */\n#define vpiDelayModeUnit           4   /* unit delay mode */\n#define vpiDelayModeZero           5   /* zero delay mode */\n#define vpiDelayModeMTM            6   /* min:typ:max delay mode */\n#define vpiDefDecayTime          48   /* Default decay time for a module */\n\n/*************************** port and net properties **************************/\n\n#define vpiScalar                17   /* scalar (Boolean) */\n#define vpiVector                18   /* vector (Boolean) */\n#define vpiExplicitName          19   /* port is explicitly named */\n#define vpiDirection             20   /* direction of port: */\n#define vpiInput                   1   /* input */\n#define vpiOutput                  2   /* output */\n#define vpiInout                   3   /* inout */\n#define vpiMixedIO                 4   /* mixed input-output */\n#define vpiNoDirection             5   /* no direction */\n#define vpiConnByName            21   /* connected by name (Boolean) */\n\n#define vpiNetType               22   /* net subtypes: */\n#define vpiWire                    1   /* wire net */\n#define vpiWand                    2   /* wire-and net */\n#define vpiWor                     3   /* wire-or net */\n#define vpiTri                     4   /* three-state net */\n#define vpiTri0                    5   /* pull-down net */\n#define vpiTri1                    6   /* pull-up net */\n#define vpiTriReg                  7   /* tri state reg net */\n#define vpiTriAnd                  8   /* three-state wire-and net */\n#define vpiTriOr                   9   /* three-state wire-or net */\n#define vpiSupply1                10   /* supply 1 net */\n#define vpiSupply0                11   /* supply zero net */\n#define vpiNone                   12   /* no default net type (1364-2001) */\n#define vpiUwire                  13   /* unresolved wire net (1364-2005) */\n\n#define vpiExplicitScalared      23   /* explicitly scalared (Boolean) */\n#define vpiExplicitVectored      24   /* explicitly vectored (Boolean) */\n#define vpiExpanded              25   /* expanded vector net (Boolean) */\n#define vpiImplicitDecl          26   /* implicitly declared net (Boolean) */\n#define vpiChargeStrength        27   /* charge decay strength of net */\n\n/*  Defined as part of strengths section.\n#define vpiLargeCharge             0x10\n#define vpiMediumCharge            0x04\n#define vpiSmallCharge             0x02\n*/\n\n#define vpiArray                 28   /* variable array (Boolean) */\n#define vpiPortIndex             29   /* Port index */\n\n/************************ gate and terminal properties ************************/\n\n#define vpiTermIndex             30   /* Index of a primitive terminal */\n#define vpiStrength0             31   /* 0-strength of net or gate */\n#define vpiStrength1             32   /* 1-strength of net or gate */\n#define vpiPrimType              33   /* prmitive subtypes: */\n#define vpiAndPrim                 1   /* and gate */\n#define vpiNandPrim                2   /* nand gate */\n#define vpiNorPrim                 3   /* nor gate */\n#define vpiOrPrim                  4   /* or gate */\n#define vpiXorPrim                 5   /* xor gate */\n#define vpiXnorPrim                6   /* xnor gate */\n#define vpiBufPrim                 7   /* buffer */\n#define vpiNotPrim                 8   /* not gate */\n#define vpiBufif0Prim              9   /* zero-enabled buffer */\n#define vpiBufif1Prim             10   /* one-enabled buffer */\n#define vpiNotif0Prim             11   /* zero-enabled not gate */\n#define vpiNotif1Prim             12   /* one-enabled not gate */\n#define vpiNmosPrim               13   /* nmos switch */\n#define vpiPmosPrim               14   /* pmos switch */\n#define vpiCmosPrim               15   /* cmos switch */\n#define vpiRnmosPrim              16   /* resistive nmos switch */\n#define vpiRpmosPrim              17   /* resistive pmos switch */\n#define vpiRcmosPrim              18   /* resistive cmos switch */\n#define vpiRtranPrim              19   /* resistive bidirectional */\n#define vpiRtranif0Prim           20   /* zero-enable resistive bidirectional */\n#define vpiRtranif1Prim           21   /* one-enable resistive bidirectional */\n#define vpiTranPrim               22   /* bidirectional */\n#define vpiTranif0Prim            23   /* zero-enabled bidirectional */\n#define vpiTranif1Prim            24   /* one-enabled bidirectional */\n#define vpiPullupPrim             25   /* pullup */\n#define vpiPulldownPrim           26   /* pulldown */\n#define vpiSeqPrim                27   /* sequential UDP */\n#define vpiCombPrim               28   /* combinational UDP */\n\n/**************** path, path terminal, timing check properties ****************/\n\n#define vpiPolarity              34   /* polarity of module path... */\n#define vpiDataPolarity          35   /* ...or data path: */\n#define vpiPositive                1   /* positive */\n#define vpiNegative                2   /* negative */\n#define vpiUnknown                 3   /* unknown (unspecified) */\n\n#define vpiEdge                  36   /* edge type of module path: */\n#define vpiNoEdge                  0x00     /* no edge */\n#define vpiEdge01                  0x01     /* 0 -> 1 */\n#define vpiEdge10                  0x02     /* 1 -> 0 */\n#define vpiEdge0x                  0x04     /* 0 -> x */\n#define vpiEdgex1                  0x08     /* x -> 1 */\n#define vpiEdge1x                  0x10     /* 1 -> x */\n#define vpiEdgex0                  0x20     /* x -> 0 */\n#define vpiPosedge                 (vpiEdgex1 | vpiEdge01 | vpiEdge0x)\n#define vpiNegedge                 (vpiEdgex0 | vpiEdge10 | vpiEdge1x)\n#define vpiAnyEdge                 (vpiPosedge | vpiNegedge)\n\n#define vpiPathType              37   /* path delay connection subtypes: */\n#define vpiPathFull                1   /* ( a *> b ) */\n#define vpiPathParallel            2   /* ( a => b ) */\n\n#define vpiTchkType              38   /* timing check subtypes: */\n#define vpiSetup                   1   /* $setup */\n#define vpiHold                    2   /* $hold */\n#define vpiPeriod                  3   /* $period */\n#define vpiWidth                   4   /* $width */\n#define vpiSkew                    5   /* $skew */\n#define vpiRecovery                6   /* $recovery */\n#define vpiNoChange                7   /* $nochange */\n#define vpiSetupHold               8   /* $setuphold */\n#define vpiFullskew                9   /* $fullskew -- added for 1364-2001 */\n#define vpiRecrem                 10   /* $recrem   -- added for 1364-2001 */\n#define vpiRemoval                11   /* $removal  -- added for 1364-2001 */\n#define vpiTimeskew               12   /* $timeskew -- added for 1364-2001 */\n\n/**************************** expression properties ***************************/\n\n#define vpiOpType                39   /* operation subtypes: */\n#define vpiMinusOp                 1   /* unary minus */\n#define vpiPlusOp                  2   /* unary plus */\n#define vpiNotOp                   3   /* unary not */\n#define vpiBitNegOp                4   /* bitwise negation */\n#define vpiUnaryAndOp              5   /* bitwise reduction AND */\n#define vpiUnaryNandOp             6   /* bitwise reduction NAND */\n#define vpiUnaryOrOp               7   /* bitwise reduction OR */\n#define vpiUnaryNorOp              8   /* bitwise reduction NOR */\n#define vpiUnaryXorOp              9   /* bitwise reduction XOR */\n#define vpiUnaryXNorOp            10   /* bitwise reduction XNOR */\n#define vpiSubOp                  11   /* binary subtraction */\n#define vpiDivOp                  12   /* binary division */\n#define vpiModOp                  13   /* binary modulus */\n#define vpiEqOp                   14   /* binary equality */\n#define vpiNeqOp                  15   /* binary inequality */\n#define vpiCaseEqOp               16   /* case (x and z) equality */\n#define vpiCaseNeqOp              17   /* case inequality */\n#define vpiGtOp                   18   /* binary greater than */\n#define vpiGeOp                   19   /* binary greater than or equal */\n#define vpiLtOp                   20   /* binary less than */\n#define vpiLeOp                   21   /* binary less than or equal */\n#define vpiLShiftOp               22   /* binary left shift */\n#define vpiRShiftOp               23   /* binary right shift */\n#define vpiAddOp                  24   /* binary addition */\n#define vpiMultOp                 25   /* binary multiplication */\n#define vpiLogAndOp               26   /* binary logical AND */\n#define vpiLogOrOp                27   /* binary logical OR */\n#define vpiBitAndOp               28   /* binary bitwise AND */\n#define vpiBitOrOp                29   /* binary bitwise OR */\n#define vpiBitXorOp               30   /* binary bitwise XOR */\n#define vpiBitXNorOp              31   /* binary bitwise XNOR */\n#define vpiBitXnorOp              vpiBitXNorOp /* added with 1364-2001 */\n#define vpiConditionOp            32   /* ternary conditional */\n#define vpiConcatOp               33   /* n-ary concatenation */\n#define vpiMultiConcatOp          34   /* repeated concatenation */\n#define vpiEventOrOp              35   /* event or */\n#define vpiNullOp                 36   /* null operation */\n#define vpiListOp                 37   /* list of expressions */\n#define vpiMinTypMaxOp            38   /* min:typ:max: delay expression */\n#define vpiPosedgeOp              39   /* posedge */\n#define vpiNegedgeOp              40   /* negedge */\n#define vpiArithLShiftOp          41   /* arithmetic left shift  (1364-2001) */\n#define vpiArithRShiftOp          42   /* arithmetic right shift (1364-2001) */\n#define vpiPowerOp                43   /* arithmetic power op    (1364-2001) */\n\n#define vpiConstType             40   /* constant subtypes: */\n#define vpiDecConst                1   /* decimal integer */\n#define vpiRealConst               2   /* real */\n#define vpiBinaryConst             3   /* binary integer */\n#define vpiOctConst                4   /* octal integer */\n#define vpiHexConst                5   /* hexadecimal integer */\n#define vpiStringConst             6   /* string literal */\n#define vpiIntConst                7   /* HDL integer constant (1364-2001) */\n#define vpiTimeConst               8   /* time constant */\n\n#define vpiBlocking              41   /* blocking assignment (boolean) */\n#define vpiCaseType              42   /* case statement subtypes: */\n#define vpiCaseExact               1   /* exact match */\n#define vpiCaseX                   2   /* ignore X's */\n#define vpiCaseZ                   3   /* ignore Z's */\n#define vpiNetDeclAssign         43   /* assign part of decl (boolean) */\n\n/************************** task/function properties **************************/\n\n#define vpiFuncType              44   /* HDL function & system function type */\n#define vpiIntFunc                 1   /* returns integer */\n#define vpiRealFunc                2   /* returns real */\n#define vpiTimeFunc                3   /* returns time */\n#define vpiSizedFunc               4   /* returns an arbitrary size */\n#define vpiSizedSignedFunc         5   /* returns sized signed value */\n\n/** alias 1364-1995 system function subtypes to 1364-2001 function subtypes ***/\n\n#define vpiSysFuncType             vpiFuncType\n#define vpiSysFuncInt              vpiIntFunc\n#define vpiSysFuncReal             vpiRealFunc\n#define vpiSysFuncTime             vpiTimeFunc\n#define vpiSysFuncSized            vpiSizedFunc\n\n#define vpiUserDefn              45   /*user defined system task/func(Boolean)*/\n#define vpiScheduled             46   /* object still scheduled (Bboolean) */\n\n/*********************** properties added with 1364-2001 **********************/\n\n#define vpiActive                49  /* reentrant task/func frame is active */\n#define vpiAutomatic             50  /* task/func obj is automatic */\n#define vpiCell                  51  /* configuration cell */\n#define vpiConfig                52  /* configuration config file */\n#define vpiConstantSelect        53  /* (Boolean) bit-select or part-select\n                                        indices are constant expressions */\n#define vpiDecompile             54  /* decompile the object */\n#define vpiDefAttribute          55  /* Attribute defined for the obj */\n#define vpiDelayType             56  /* delay subtype */\n#define vpiModPathDelay            1  /* module path delay */\n#define vpiInterModPathDelay       2  /* intermodule path delay */\n#define vpiMIPDelay                3  /* module input port delay */\n#define vpiIteratorType          57  /* object type of an iterator */\n#define vpiLibrary               58  /* configuration library */\n#define vpiMultiArray            59  /* Object is a multidimensional array */\n#define vpiOffset                60  /* offset from LSB */\n#define vpiResolvedNetType       61  /* net subtype after resolution, returns\n                                        same subtypes as vpiNetType */\n#define vpiSaveRestartID         62  /* unique ID for save/restart data */\n#define vpiSaveRestartLocation   63  /* name of save/restart data file */\n#define vpiValid                 64  /* reentrant task/func frame is valid */\n#define vpiValidFalse              0\n#define vpiValidTrue               1\n#define vpiSigned                65  /* TRUE for vpiIODecl and any object in\n                                        the expression class if the object\n                                        has the signed attribute */\n#define vpiLocalParam            70  /* TRUE when a param is declared as a\n                                        localparam */\n#define vpiModPathHasIfNone      71  /* Mod path has an ifnone statement */\n\n/*********************** properties added with 1364-2005 **********************/\n\n#define vpiIndexedPartSelectType 72  /* Indexed part-select type */\n#define vpiPosIndexed              1  /* +: */\n#define vpiNegIndexed              2  /* -: */\n#define vpiIsMemory              73  /* TRUE for a one-dimensional reg array */\n#define vpiIsProtected           74  /* TRUE for protected design information */\n\n/*************** vpi_control() constants (added with 1364-2001) ***************/\n\n#define vpiStop                  66  /* execute simulator's $stop */\n#define vpiFinish                67  /* execute simulator's $finish */\n#define vpiReset                 68  /* execute simulator's $reset */\n#define vpiSetInteractiveScope   69  /* set simulator's interactive scope */\n\n/**************************** I/O related defines *****************************/\n\n#define VPI_MCD_STDOUT  0x00000001\n\n/*************************** STRUCTURE DEFINITIONS ****************************/\n\n/******************************* time structure *******************************/\n\n#ifndef VPI_TIME  /* added in 1800-2023 */\n#define VPI_TIME\ntypedef struct t_vpi_time\n{\n  PLI_INT32  type;               /* [vpiScaledRealTime, vpiSimTime,\n                                     vpiSuppressTime] */\n  PLI_UINT32 high, low;          /* for vpiSimTime */\n  double     real;               /* for vpiScaledRealTime */\n} s_vpi_time, *p_vpi_time;\n\n/* time types */\n\n#define vpiScaledRealTime 1\n#define vpiSimTime        2\n#define vpiSuppressTime   3\n\n#endif\n\n/****************************** delay structures ******************************/\n\ntypedef struct t_vpi_delay\n{\n  struct t_vpi_time *da;         /* pointer to application-allocated\n                                    array of delay values */\n  PLI_INT32 no_of_delays;        /* number of delays */\n  PLI_INT32 time_type;           /* [vpiScaledRealTime, vpiSimTime,\n                                     vpiSuppressTime] */\n  PLI_INT32 mtm_flag;            /* true for mtm values */\n  PLI_INT32 append_flag;         /* true for append */\n  PLI_INT32 pulsere_flag;        /* true for pulsere values */\n} s_vpi_delay, *p_vpi_delay;\n\n/***************************** value structures *******************************/\n\n/* vector value */\n\n#ifndef VPI_VECVAL  /* added in 1364-2005 */\n#define VPI_VECVAL\n\ntypedef struct t_vpi_vecval\n{\n  /* following fields are repeated enough times to contain vector */\nPLI_INT32 aval, bval; /* bit encoding: ab: 00=0, 10=1, 11=X, 01=Z */\n} s_vpi_vecval, *p_vpi_vecval;\n\n#endif\n\n/* strength (scalar) value */\n\ntypedef struct t_vpi_strengthval\n{\n  PLI_INT32 logic;               /* vpi[0,1,X,Z] */\n  PLI_INT32 s0, s1;              /* refer to strength coding below */\n} s_vpi_strengthval, *p_vpi_strengthval;\n\n/* strength values */\n\n#define vpiSupplyDrive     0x80\n#define vpiStrongDrive     0x40\n#define vpiPullDrive       0x20\n#define vpiWeakDrive       0x08\n#define vpiLargeCharge     0x10\n#define vpiMediumCharge    0x04\n#define vpiSmallCharge     0x02\n#define vpiHiZ             0x01\n\n/* generic value */\n\ntypedef struct t_vpi_value\n{\n  PLI_INT32 format; /* vpi[[Bin,Oct,Dec,Hex]Str,Scalar,Int,Real,String,\n                           Vector,Strength,Suppress,Time,ObjType]Val */\n  union\n    {\n      PLI_BYTE8                *str;       /* string value */\n      PLI_INT32                 scalar;    /* vpi[0,1,X,Z] */\n      PLI_INT32                 integer;   /* integer value */\n      double                    real;      /* real value */\n      struct t_vpi_time        *time;      /* time value */\n      struct t_vpi_vecval      *vector;    /* vector value */\n      struct t_vpi_strengthval *strength;  /* strength value */\n      PLI_BYTE8                *misc;      /* ...other */\n    } value;\n} s_vpi_value, *p_vpi_value;\n\ntypedef struct t_vpi_arrayvalue\n{\n  PLI_UINT32 format;  /* vpi[Int,Real,Time,ShortInt,LongInt,ShortReal,RawTwoState,RawFourState]Val */\n  PLI_UINT32 flags;  /* array bit flags- vpiUserAllocFlag */\n  union\n    {\n      PLI_INT32 *integers;                 /* integer values */\n      PLI_INT16 *shortints;                /* short integer values */\n      PLI_INT64 *longints;                 /* long integer values */\n      PLI_BYTE8 *rawvals;                  /* 2/4-state vector elements */\n      struct t_vpi_vecval *vectors;        /* 4-state vector elements */\n      struct t_vpi_time *times;            /* time values */\n      double *reals;                       /* real values */\n      float *shortreals;                   /* short real values */\n   } value;\n} s_vpi_arrayvalue, *p_vpi_arrayvalue;\n\n/* value formats */\n\n#define vpiBinStrVal          1\n#define vpiOctStrVal          2\n#define vpiDecStrVal          3\n#define vpiHexStrVal          4\n#define vpiScalarVal          5\n#define vpiIntVal             6\n#define vpiRealVal            7\n#define vpiStringVal          8\n#define vpiVectorVal          9\n#define vpiStrengthVal       10\n#define vpiTimeVal           11\n#define vpiObjTypeVal        12\n#define vpiSuppressVal       13\n#define vpiShortIntVal       14\n#define vpiLongIntVal        15\n#define vpiShortRealVal      16\n#define vpiRawTwoStateVal    17\n#define vpiRawFourStateVal   18\n\n/* delay modes */\n\n#define vpiNoDelay            1\n#define vpiInertialDelay      2\n#define vpiTransportDelay     3\n#define vpiPureTransportDelay 4\n\n/* force and release flags */\n\n#define vpiForceFlag          5\n#define vpiReleaseFlag        6\n\n/* scheduled event cancel flag */\n\n#define vpiCancelEvent        7\n\n/* bit mask for the flags argument to vpi_put_value() */\n\n#define vpiReturnEvent        0x1000\n\n/* bit flags for vpi_get_value_array flags field */\n\n#define vpiUserAllocFlag      0x2000\n\n/* bit flags for vpi_put_value_array flags field */\n\n#define vpiOneValue           0x4000\n#define vpiPropagateOff       0x8000\n\n/* scalar values */\n\n#define vpi0                  0\n#define vpi1                  1\n#define vpiZ                  2\n#define vpiX                  3\n#define vpiH                  4\n#define vpiL                  5\n#define vpiDontCare           6\n/*\n#define vpiNoChange           7   Defined under vpiTchkType, but\n                                  can be used here.\n*/\n\n/*********************** system task/function structure ***********************/\n\ntypedef struct t_vpi_systf_data\n{\n  PLI_INT32 type;                       /* vpiSysTask, vpiSysFunc */\n  PLI_INT32 sysfunctype;                /* vpiSysTask, vpi[Int,Real,Time,Sized,\n                                                           SizedSigned]Func */\n  PLI_BYTE8 *tfname;                    /* first character must be '$' */\n  PLI_INT32 (*calltf)(PLI_BYTE8 *);\n  PLI_INT32 (*compiletf)(PLI_BYTE8 *);\n  PLI_INT32 (*sizetf)(PLI_BYTE8 *);     /* for sized function callbacks only */\n  PLI_BYTE8 *user_data;\n} s_vpi_systf_data, *p_vpi_systf_data;\n\n#define vpiSysTask            1\n#define vpiSysFunc            2\n\n/* the subtypes are defined under the vpiFuncType property */\n\n/****************** Verilog execution information structure *******************/\n\ntypedef struct t_vpi_vlog_info\n{\n  PLI_INT32 argc;\n  PLI_BYTE8 **argv;\n  PLI_BYTE8 *product;\n  PLI_BYTE8 *version;\n} s_vpi_vlog_info, *p_vpi_vlog_info;\n\n/*********************** PLI error information structure **********************/\n\ntypedef struct t_vpi_error_info\n{\n  PLI_INT32 state;           /* vpi[Compile,PLI,Run] */\n  PLI_INT32 level;           /* vpi[Notice,Warning,Error,System,Internal] */\n  PLI_BYTE8 *message;\n  PLI_BYTE8 *product;\n  PLI_BYTE8 *code;\n  PLI_BYTE8 *file;\n  PLI_INT32 line;\n} s_vpi_error_info, *p_vpi_error_info;\n\n/* state when error occurred */\n\n#define vpiCompile              1\n#define vpiPLI                  2\n#define vpiRun                  3\n\n/* error severity levels */\n\n#define vpiNotice               1\n#define vpiWarning              2\n#define vpiError                3\n#define vpiSystem               4\n#define vpiInternal             5\n\n/**************************** callback structures *****************************/\n\n/* normal callback structure */\n\ntypedef struct t_cb_data\n{\n  PLI_INT32    reason;                        /* callback reason */\n  PLI_INT32    (*cb_rtn)(struct t_cb_data *); /* call routine */\n  vpiHandle    obj;                           /* trigger object */\n  p_vpi_time   time;                          /* callback time */\n  p_vpi_value  value;                         /* trigger object value */\n  PLI_INT32    index;                         /* index of the memory word or\n                                                 var select that changed */\n  PLI_BYTE8   *user_data;\n} s_cb_data, *p_cb_data;\n\n/****************************** CALLBACK REASONS ******************************/\n/***************************** Simulation related *****************************/\n\n#define cbValueChange             1\n#define cbStmt                    2\n#define cbForce                   3\n#define cbRelease                 4\n\n/******************************** Time related ********************************/\n\n#define cbAtStartOfSimTime        5\n#define cbReadWriteSynch          6\n#define cbReadOnlySynch           7\n#define cbNextSimTime             8\n#define cbAfterDelay              9\n\n/******************************* Action related *******************************/\n\n#define cbEndOfCompile           10\n#define cbStartOfSimulation      11\n#define cbEndOfSimulation        12\n#define cbError                  13\n#define cbTchkViolation          14\n#define cbStartOfSave            15\n#define cbEndOfSave              16\n#define cbStartOfRestart         17\n#define cbEndOfRestart           18\n#define cbStartOfReset           19\n#define cbEndOfReset             20\n#define cbEnterInteractive       21\n#define cbExitInteractive        22\n#define cbInteractiveScopeChange 23\n#define cbUnresolvedSystf        24\n\n/**************************** Added with 1364-2001 ****************************/\n\n#define cbAssign                 25\n#define cbDeassign               26\n#define cbDisable                27\n#define cbPLIError               28\n#define cbSignal                 29\n\n/**************************** Added with 1364-2005 ****************************/\n#define cbNBASynch               30\n#define cbAtEndOfSimTime         31\n\n/************************* FUNCTION DECLARATIONS **************************/\n\n/* Include compatibility mode macro definitions. */\n#include \"vpi_compatibility.h\"\n\n/* callback related */\n\nXXTERN vpiHandle  vpi_register_cb     PROTO_PARAMS((p_cb_data cb_data_p));\nXXTERN PLI_INT32  vpi_remove_cb       PROTO_PARAMS((vpiHandle cb_obj));\nXXTERN void       vpi_get_cb_info     PROTO_PARAMS((vpiHandle object,\n                                                    p_cb_data cb_data_p));\nXXTERN vpiHandle  vpi_register_systf  PROTO_PARAMS((p_vpi_systf_data\n                                                      systf_data_p));\nXXTERN void       vpi_get_systf_info  PROTO_PARAMS((vpiHandle object,\n                                                    p_vpi_systf_data\n                                                      systf_data_p));\n\n/* for obtaining handles */\n\nXXTERN vpiHandle  vpi_handle_by_name  PROTO_PARAMS((PLI_BYTE8 *name,\n                                                    vpiHandle scope));\nXXTERN vpiHandle  vpi_handle_by_index PROTO_PARAMS((vpiHandle object,\n                                                    PLI_INT32 indx));\n\n/* for traversing relationships */\n\nXXTERN vpiHandle  vpi_handle          PROTO_PARAMS((PLI_INT32 type,\n                                                    vpiHandle refHandle));\nXXTERN vpiHandle  vpi_handle_multi    PROTO_PARAMS((PLI_INT32 type,\n                                                    vpiHandle refHandle1,\n                                                    vpiHandle refHandle2,\n                                                    ... ));\nXXTERN vpiHandle  vpi_iterate         PROTO_PARAMS((PLI_INT32 type,\n                                                    vpiHandle refHandle));\nXXTERN vpiHandle  vpi_scan            PROTO_PARAMS((vpiHandle iterator));\n\n/* for processing properties */\n\nXXTERN PLI_INT32  vpi_get             PROTO_PARAMS((PLI_INT32 property,\n                                                    vpiHandle object));\nXXTERN PLI_INT64  vpi_get64           PROTO_PARAMS((PLI_INT32 property,\n                                                    vpiHandle object));\nXXTERN PLI_BYTE8 *vpi_get_str         PROTO_PARAMS((PLI_INT32 property,\n                                                    vpiHandle object));\n\n/* delay processing */\n\nXXTERN void       vpi_get_delays      PROTO_PARAMS((vpiHandle object,\n                                                    p_vpi_delay delay_p));\nXXTERN void       vpi_put_delays      PROTO_PARAMS((vpiHandle object,\n                                                    p_vpi_delay delay_p));\n\n/* value processing */\n\nXXTERN void       vpi_get_value       PROTO_PARAMS((vpiHandle expr,\n                                                    p_vpi_value value_p));\nXXTERN vpiHandle  vpi_put_value       PROTO_PARAMS((vpiHandle object,\n                                                    p_vpi_value value_p,\n                                                    p_vpi_time time_p,\n                                                    PLI_INT32 flags));\n\n/* arrayvalue processing */\nXXTERN void       vpi_get_value_array PROTO_PARAMS((vpiHandle expr,\n                                                    p_vpi_arrayvalue arrayvalue_p,\n                                                    PLI_INT32 *index_p,\n                                                    PLI_UINT32 num));\n\nXXTERN void       vpi_put_value_array PROTO_PARAMS((vpiHandle object,\n                                                    p_vpi_arrayvalue arrayvalue_p,\n                                                    PLI_INT32 *index_p,\n                                                    PLI_UINT32 num));\n\n/* time processing */\n\nXXTERN void       vpi_get_time        PROTO_PARAMS((vpiHandle object,\n                                                    p_vpi_time time_p));\n\n/* I/O routines */\n\nXXTERN PLI_UINT32 vpi_mcd_open        PROTO_PARAMS((PLI_BYTE8 *fileName));\nXXTERN PLI_UINT32 vpi_mcd_close       PROTO_PARAMS((PLI_UINT32 mcd));\nXXTERN PLI_BYTE8 *vpi_mcd_name        PROTO_PARAMS((PLI_UINT32 cd));\nXXTERN PLI_INT32  vpi_mcd_printf      PROTO_PARAMS((PLI_UINT32 mcd,\n                                                    PLI_BYTE8 *format,\n                                                    ...));\nXXTERN PLI_INT32  vpi_printf          PROTO_PARAMS((PLI_BYTE8 *format,\n                                                    ...));\n\n/* utility routines */\n\nXXTERN PLI_INT32  vpi_compare_objects PROTO_PARAMS((vpiHandle object1,\n                                                    vpiHandle object2));\nXXTERN PLI_INT32  vpi_chk_error       PROTO_PARAMS((p_vpi_error_info\n                                                      error_info_p));\nXXTERN PLI_INT32  vpi_free_object     PROTO_PARAMS((vpiHandle object));\nXXTERN PLI_INT32  vpi_release_handle  PROTO_PARAMS((vpiHandle object));\nXXTERN PLI_INT32  vpi_get_vlog_info   PROTO_PARAMS((p_vpi_vlog_info\n                                                      vlog_info_p));\n\n/* routines added with 1364-2001 */\n\nXXTERN PLI_INT32  vpi_get_data        PROTO_PARAMS((PLI_INT32 id,\n                                                    PLI_BYTE8 *dataLoc,\n                                                    PLI_INT32 numOfBytes));\nXXTERN PLI_INT32  vpi_put_data        PROTO_PARAMS((PLI_INT32 id,\n                                                    PLI_BYTE8 *dataLoc,\n                                                    PLI_INT32 numOfBytes));\nXXTERN void      *vpi_get_userdata    PROTO_PARAMS((vpiHandle obj));\nXXTERN PLI_INT32  vpi_put_userdata    PROTO_PARAMS((vpiHandle obj,\n                                                    void *userdata));\nXXTERN PLI_INT32  vpi_vprintf         PROTO_PARAMS((PLI_BYTE8 *format,\n                                                    va_list ap));\nXXTERN PLI_INT32  vpi_mcd_vprintf     PROTO_PARAMS((PLI_UINT32 mcd,\n                                                    PLI_BYTE8 *format,\n                                                    va_list ap));\nXXTERN PLI_INT32  vpi_flush           PROTO_PARAMS((void));\nXXTERN PLI_INT32  vpi_mcd_flush       PROTO_PARAMS((PLI_UINT32 mcd));\nXXTERN PLI_INT32  vpi_control         PROTO_PARAMS((PLI_INT32 operation,\n                                                    ...));\nXXTERN vpiHandle  vpi_handle_by_multi_index PROTO_PARAMS((vpiHandle obj,\n                                                    PLI_INT32 num_index,\n                                                    PLI_INT32 *index_array));\n\n/****************************** GLOBAL VARIABLES ******************************/\n\nPLI_VEXTERN PLI_DLLESPEC void (*vlog_startup_routines[])();\n\n  /* array of function pointers, last pointer should be null */\n\n#undef PLI_EXTERN\n#undef PLI_VEXTERN\n\n#ifdef VPI_USER_DEFINED_DLLISPEC\n#undef VPI_USER_DEFINED_DLLISPEC\n#undef PLI_DLLISPEC\n#endif\n#ifdef VPI_USER_DEFINED_DLLESPEC\n#undef VPI_USER_DEFINED_DLLESPEC\n#undef PLI_DLLESPEC\n#endif\n\n#ifdef PLI_PROTOTYPES\n#undef PLI_PROTOTYPES\n#undef PROTO_PARAMS\n#undef XXTERN\n#undef EETERN\n#endif\n\n#ifdef  __cplusplus\n}\n#endif\n\n#endif /* VPI_USER_H */\n"
  },
  {
    "path": "src/cocotb/_version.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport importlib.metadata\n\n__all__ = (\"__version__\",)\n\n__version__ = importlib.metadata.version(\"cocotb\")\n"
  },
  {
    "path": "src/cocotb/_xunit_reporter.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport re\nimport xml.etree.ElementTree as ET\nfrom xml.etree.ElementTree import Element, SubElement, indent\n\n\n# Shamelessly ripped from pytest source code.\n# https://github.com/pytest-dev/pytest/blob/d036b12bb6fa09f9a8a3b690cc7336113c93fa44/src/_pytest/junitxml.py#L37C1-L61C50\ndef bin_xml_escape(arg: object) -> str:\n    r\"\"\"Visually escape invalid XML characters.\n\n    For example, transforms\n        'hello\\aworld\\b'\n    into\n        'hello#x07world#x08'\n    Note that the #xABs are *not* XML escapes - missing the ampersand &#xAB.\n    The idea is to escape visually for the user rather than for XML itself.\n    \"\"\"\n\n    def repl(matchobj: re.Match[str]) -> str:\n        i = ord(matchobj.group())\n        if i <= 0xFF:\n            return f\"#x{i:02X}\"\n        else:\n            return f\"#x{i:04X}\"\n\n    # The spec range of valid chars is:\n    # Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]\n    # For an unknown(?) reason, we disallow #x7F (DEL) as well.\n    illegal_xml_re = (\n        \"[^\\u0009\\u000a\\u000d\\u0020-\\u007e\\u0080-\\ud7ff\\ue000-\\ufffd\\u10000-\\u10ffff]\"\n    )\n    return re.sub(illegal_xml_re, repl, str(arg))\n\n\nclass XUnitReporter:\n    last_testsuite: Element\n    last_testcase: Element\n\n    def __init__(self, filename: str = \"results.xml\") -> None:\n        self.results = Element(\"testsuites\", name=\"results\")\n        self.filename = filename\n\n    def add_testsuite(self, **kwargs: str) -> Element:\n        self.last_testsuite = SubElement(self.results, \"testsuite\", kwargs)\n        return self.last_testsuite\n\n    def add_testcase(self, testsuite: Element | None = None, **kwargs: str) -> Element:\n        if testsuite is None:\n            testsuite = self.last_testsuite\n        self.last_testcase = SubElement(testsuite, \"testcase\", kwargs)\n        return self.last_testcase\n\n    def add_property(self, testsuite: Element | None = None, **kwargs: str) -> Element:\n        if testsuite is None:\n            testsuite = self.last_testsuite\n        self.last_property = SubElement(testsuite, \"property\", kwargs)\n        return self.last_property\n\n    def add_failure(self, testcase: Element | None = None, **kwargs: str) -> None:\n        if testcase is None:\n            testcase = self.last_testcase\n        SubElement(testcase, \"failure\", kwargs)\n\n    def add_skipped(self, testcase: Element | None = None, **kwargs: str) -> None:\n        if testcase is None:\n            testcase = self.last_testcase\n        SubElement(testcase, \"skipped\", kwargs)\n\n    def write(self) -> None:\n        indent(self.results)\n        ET.ElementTree(self.results).write(self.filename, encoding=\"UTF-8\")\n"
  },
  {
    "path": "src/cocotb/clock.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"A clock class.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nimport sys\nimport warnings\nfrom decimal import Decimal\nfrom fractions import Fraction\nfrom functools import cached_property\nfrom logging import Logger\nfrom typing import ClassVar, Literal\n\nimport cocotb\nimport cocotb.simulator\nfrom cocotb.handle import (\n    Deposit,\n    Force,\n    Immediate,\n    LogicObject,\n    _GPISetAction,\n    _trust_inertial,\n)\nfrom cocotb.simtime import TimeUnit\nfrom cocotb.task import Task\nfrom cocotb.triggers import (\n    Event,\n    FallingEdge,\n    NullTrigger,\n    RisingEdge,\n    Timer,\n    ValueChange,\n)\nfrom cocotb.utils import get_sim_steps, get_time_from_sim_steps\n\nif sys.version_info >= (3, 10):\n    from typing import TypeAlias\n\n__all__ = (\"Clock\",)\n\nImpl: TypeAlias = Literal[\"gpi\", \"py\"]\n\n\n_valid_impls = (\"gpi\", \"py\")\n\n\nclass Clock:\n    r\"\"\"Simple 50:50 duty cycle clock driver.\n\n    .. code-block:: python\n\n        c = Clock(dut.clk, 10, \"ns\")\n        c.start()\n\n    Args:\n        signal: The clock pin/signal to be driven.\n        period:\n            The clock period.\n            Must be a multiple of the time precision of the simulator.\n\n        unit:\n            One of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``.\n            When *unit* is ``'step'``,\n            the timestep is determined by the simulator (see :make:var:`COCOTB_HDL_TIMEPRECISION`).\n\n            .. versionchanged:: 2.0\n                Renamed from ``units``.\n\n        impl:\n            One of ``'auto'``, ``'gpi'``, ``'py'``.\n            Specify whether the clock is implemented with a :class:`~cocotb.simulator.cpp_clock` (faster), or with a Python coroutine.\n            When ``'auto'`` is used (default), the fastest implementation that supports your environment and use case is picked.\n\n            .. versionadded:: 2.0\n\n        set_action:\n            One of :class:`.Immediate`, :class:`.Deposit`, or :class:`.Force`.\n            Specify the action to use when setting the clock signal value.\n            Defaults to the value of :attr:`default_set_action`.\n\n            .. versionadded:: 2.0\n\n        period_high:\n            The period of time when the clock is driven to ``1``.\n            Defaults to half of the *period*.\n            Must be a multiple of the time precision of the simulator and less than *period*.\n\n            .. versionadded:: 2.0\n\n    When *impl* is ``'auto'``, if :envvar:`COCOTB_TRUST_INERTIAL_WRITES` is defined,\n    the :class:`~cocotb.simulator.cpp_clock` implementation will be used.\n    Otherwise, the Python coroutine implementation will be used.\n    See the environment variable's documentation for more information on the consequences\n    of using the simulator's inertial write mechanism.\n\n    If you need more features like a phase shift and an asymmetric duty cycle,\n    it is simple to create your own clock generator (that you then :func:`cocotb.start_soon`):\n\n    .. code-block:: python\n\n        async def custom_clock():\n            # pre-construct triggers for performance\n            high_time = Timer(high_delay, unit=\"ns\")\n            low_time = Timer(low_delay, unit=\"ns\")\n            await Timer(initial_delay, unit=\"ns\")\n            while True:\n                dut.clk.value = 1\n                await high_time\n                dut.clk.value = 0\n                await low_time\n\n    If you also want to change the timing during simulation,\n    use this slightly more inefficient example instead where\n    the :class:`Timer`\\ s inside the while loop are created with\n    current delay values:\n\n    .. code-block:: python\n\n        async def custom_clock():\n            while True:\n                dut.clk.value = 1\n                await Timer(high_delay, unit=\"ns\")\n                dut.clk.value = 0\n                await Timer(low_delay, unit=\"ns\")\n\n\n        high_delay = low_delay = 100\n        cocotb.start_soon(custom_clock())\n        await Timer(1000, unit=\"ns\")\n        high_delay = low_delay = 10  # change the clock speed\n        await Timer(1000, unit=\"ns\")\n\n    .. versionadded:: 1.5\n        Support ``'step'`` as the *unit* argument to mean \"simulator time step\".\n\n    .. versionremoved:: 2.0\n        Passing ``None`` as the *unit* argument was removed, use ``'step'`` instead.\n\n    .. versionchanged:: 2.0\n        :meth:`start` now automatically calls :func:`cocotb.start_soon` and stores the Task\n        on the Clock object, so that it may later be :meth:`stop`\\ ped.\n    \"\"\"\n\n    _impl: Impl\n\n    default_set_action: ClassVar[type[Immediate] | type[Deposit] | type[Force]] = (\n        Deposit\n    )\n    \"\"\"The default action used to set the clock signal value.\n    One of :class:`.Immediate`, :class:`.Deposit`, or :class:`.Force`.\n\n    .. versionadded:: 2.0\n    \"\"\"\n\n    def __init__(\n        self,\n        signal: LogicObject,\n        period: float | Fraction | Decimal,\n        unit: TimeUnit = \"step\",\n        impl: Impl | None = None,\n        *,\n        units: None = None,\n        set_action: type[Immediate] | type[Deposit] | type[Force] | None = None,\n        period_high: float | Fraction | Decimal | None = None,\n    ) -> None:\n        self._signal = signal\n\n        if units is not None:\n            warnings.warn(\n                \"The 'units' argument has been renamed to 'unit'.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n            unit = units\n        self._unit: TimeUnit = unit\n\n        self._period = period\n        try:\n            self._period_steps = get_sim_steps(self._period, self._unit)\n        except ValueError as e:\n            raise ValueError(f\"Bad `period`: {e}\") from None\n\n        if set_action is None:\n            set_action = type(self).default_set_action\n        if set_action not in (Immediate, Deposit, Force):\n            raise TypeError(\n                \"Invalid value for `set_action`. `set_action` must be one of Immediate, Deposit, or Force\"\n            )\n        self._set_action = set_action\n\n        if impl is None:\n            self._impl = \"gpi\" if _trust_inertial else \"py\"\n        elif impl in _valid_impls:\n            self._impl = impl\n        else:\n            valid_impls_str = \", \".join([repr(i) for i in _valid_impls])\n            raise ValueError(\n                f\"Invalid clock impl {impl!r}, must be one of: {valid_impls_str}\"\n            )\n\n        self._period_high: float | Fraction | Decimal\n        if period_high is not None:\n            if period_high >= self._period:\n                raise ValueError(\"`period_high` must be strictly less than `period`.\")\n            self._period_high = period_high\n            try:\n                self._period_high_steps = get_sim_steps(self._period_high, self._unit)\n            except ValueError as e:\n                raise ValueError(f\"Bad `period_high`: {e}\") from None\n        else:\n            if self._period_steps % 2 != 0:\n                raise ValueError(\n                    \"Bad `period`: Must be divisible by 2 if `period_high` is not given.\"\n                )\n            self._period_high = period / 2\n            self._period_high_steps = self._period_steps // 2\n\n        self._task: Task[None] | None = None\n\n    @property\n    def signal(self) -> LogicObject:\n        \"\"\"The clock signal being driven.\"\"\"\n        return self._signal\n\n    @property\n    def period(self) -> float | Fraction | Decimal:\n        \"\"\"The clock period.\n\n        The unit is :attr:`unit`.\n        \"\"\"\n        return self._period\n\n    @property\n    def period_high(self) -> float | Fraction | Decimal:\n        \"\"\"The period of time when the clock is driven to ``1``.\n\n        The unit is :attr:`unit`.\n\n        .. versionadded:: 2.0\n        \"\"\"\n        return self._period_high\n\n    @property\n    def unit(self) -> TimeUnit:\n        \"\"\"The unit of the clock period.\n\n        .. versionadded:: 2.0\n        \"\"\"\n        return self._unit\n\n    @property\n    def impl(self) -> Impl:\n        \"\"\"The concrete implementation of the clock used.\n\n        ``\"gpi\"`` if the clock is implemented in C in the GPI layer,\n        or ``\"py\"`` if the clock is implemented in Python using cocotb Tasks.\n\n        .. versionadded:: 2.0\n        \"\"\"\n        return self._impl\n\n    @property\n    def set_action(self) -> type[Immediate] | type[Deposit] | type[Force]:\n        \"\"\"The value setting action used to set the clock signal value.\n\n        .. versionadded:: 2.0\n        \"\"\"\n        return self._set_action\n\n    def start(self, start_high: bool = True) -> Task[None]:\n        r\"\"\"Start driving the clock signal.\n\n        You can later stop the clock by calling :meth:`stop`.\n\n        Args:\n            start_high: Whether to start the clock with a ``1``\n                for the first half of the period.\n                Default is ``True``.\n\n                .. versionadded:: 1.3\n\n        Raises:\n            RuntimeError: If attempting to start a clock that has already been started.\n\n        Returns:\n            Object which can be passed to :func:`cocotb.start_soon` or ignored.\n\n        .. versionremoved:: 2.0\n            Removed ``cycles`` arguments for toggling for a finite amount of cycles.\n            Use :meth:`stop` to stop a clock from running.\n\n        .. versionchanged:: 2.0\n            Previously, this method returned a :term:`coroutine` which needed to be passed to :func:`cocotb.start_soon`.\n            Now the Clock object keeps track of its own driver Task, so this is no longer necessary.\n            Simply call ``clock.start()`` to start running the clock.\n        \"\"\"\n        if self._task is not None:\n            raise RuntimeError(\"Starting clock that has already been started.\")\n\n        if self._impl == \"gpi\":\n            clkobj = cocotb.simulator.clock_create(self._signal._handle)\n            set_action = {\n                Deposit: _GPISetAction.DEPOSIT,\n                Immediate: _GPISetAction.NO_DELAY,\n                Force: _GPISetAction.FORCE,\n            }[self._set_action]\n            clkobj.start(\n                self._period_steps,\n                self._period_high_steps,\n                start_high,\n                set_action.value,\n            )\n\n            async def drive() -> None:\n                # The clock is meant to toggle forever, so awaiting this should\n                # never return by awaiting on Event that's never set.\n                e = Event()\n                try:\n                    await e.wait()\n                finally:\n                    clkobj.stop()\n\n        else:\n\n            async def drive() -> None:\n                timer_high = Timer(self._period_high_steps)\n                timer_low = Timer(self._period_steps - self._period_high_steps)\n                if start_high:\n                    self._signal.set(self._set_action(1))\n                    await timer_high\n                while True:\n                    self._signal.set(self._set_action(0))\n                    await timer_low\n                    self._signal.set(self._set_action(1))\n                    await timer_high\n\n        self._task = cocotb.start_soon(drive())\n        return self._task\n\n    def stop(self) -> None:\n        \"\"\"Stop driving the clock signal.\n\n        You can later start the clock again by calling :meth:`start`.\n\n        Raises:\n            RuntimeError: If attempting to stop a clock that has never been started.\n\n        .. versionadded:: 2.0\n        \"\"\"\n        if self._task is None:\n            raise RuntimeError(\"Stopping a clock that was never started.\")\n        self._task.cancel()\n        self._task = None\n\n    async def cycles(\n        self,\n        num_cycles: int,\n        edge_type: type[RisingEdge]\n        | type[FallingEdge]\n        | type[ValueChange] = RisingEdge,\n    ) -> None:\n        \"\"\"Wait for a number of clock cycles.\n\n        Args:\n            num_cycles: The number of clock cycles to wait.\n            edge_type:\n                The edge of the clock to wait on.\n                Must be one of :class:`.RisingEdge`, :class:`.FallingEdge`, or :class:`.ValueChange`.\n\n        Raises:\n            ValueError: if *num_cycles* is negative.\n        \"\"\"\n        if num_cycles == 0:\n            await NullTrigger()\n            return\n        elif num_cycles < 0:\n            raise ValueError(\"`num_cycles` cannot be negative\")\n\n        # Synchronize first.\n        await edge_type(self._signal)\n        num_cycles -= 1\n\n        # Use Timer as an optimization if we are waiting long enough.\n        if num_cycles >= 2:\n            # NOTE: num_cycles must end 1 higher than expected because all edge_types occur\n            # strictly after beginning of time steps, so the last edge_type will jump within\n            # the same time step.\n            if edge_type is ValueChange:\n                # Make cycles_skipped the nearest even number so division by 2 doesn't cause issues.\n                cycles_skipped = (num_cycles // 2) * 2\n                await Timer(self._period_steps * cycles_skipped / 2, \"step\")\n                num_cycles = num_cycles - cycles_skipped + 1\n            else:\n                await Timer(self._period_steps * num_cycles, \"step\")\n                num_cycles = 1\n\n        # Run N edge_type trigger.\n        for _ in range(num_cycles):\n            await edge_type(self._signal)\n\n    def __repr__(self) -> str:\n        freq_mhz = 1 / get_time_from_sim_steps(\n            get_sim_steps(self._period, self._unit), \"us\"\n        )\n        return f\"<{type(self).__qualname__}, {self._signal._path} @ {freq_mhz} MHz>\"\n\n    @cached_property\n    def _log(self) -> Logger:\n        return logging.getLogger(\n            f\"cocotb.{type(self).__qualname__}.{self._signal._name}\"\n        )\n"
  },
  {
    "path": "src/cocotb/debug.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom cocotb_tools import _env\n\ndebug: bool = _env.as_bool(\"COCOTB_SCHEDULER_DEBUG\")\n\"\"\"Global flag to enable additional debugging functionality.\n\nDefaults to ``True`` if the :envvar:`COCOTB_SCHEDULER_DEBUG` environment variable is set,\nbut can be programmatically set by the user afterwards.\n\nThe ``\"cocotb\"`` logger should have its logging level set to :data:`logging.DEBUG`\nto see additional debugging information in the test log.\nThis can be accomplished by setting the :envvar:`COCOTB_LOG_LEVEL` environment variable\nto ``DEBUG``,\nor using the following code.\n\n.. code-block:: python\n\n    import logging\n    logging.getLogger(\"cocotb\").setLevel(logging.DEBUG)\n\n\"\"\"\n"
  },
  {
    "path": "src/cocotb/handle.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport enum\nimport logging\nimport re\nfrom abc import ABC, abstractmethod\nfrom collections.abc import Iterable, Iterator, Sequence\nfrom functools import cached_property\nfrom logging import Logger\nfrom typing import (\n    Any,\n    Callable,\n    Generic,\n    NoReturn,\n    TypeVar,\n    Union,\n    cast,\n)\n\nimport cocotb.simulator\nfrom cocotb._base_triggers import TriggerCallback\nfrom cocotb._deprecation import deprecated\nfrom cocotb._gpi_triggers import (\n    Edge,\n    FallingEdge,\n    ReadOnly,\n    ReadWrite,\n    RisingEdge,\n    ValueChange,\n    current_gpi_trigger,\n)\nfrom cocotb._utils import DocIntEnum\nfrom cocotb.types import Array, Logic, LogicArray, Range\nfrom cocotb.types._indexing import do_indexing_changed_warning, indexing_changed\nfrom cocotb.types._logic_array import _str_literals\nfrom cocotb_tools import _env\n\n__all__ = (\n    \"ArrayObject\",\n    \"Deposit\",\n    \"EnumObject\",\n    \"Force\",\n    \"Freeze\",\n    \"GPIDiscovery\",\n    \"HierarchyArrayObject\",\n    \"HierarchyObject\",\n    \"Immediate\",\n    \"IntegerObject\",\n    \"LogicArrayObject\",\n    \"LogicObject\",\n    \"RealObject\",\n    \"Release\",\n    \"SimHandleBase\",\n    \"StringObject\",\n    \"ValueObjectBase\",\n)\n\n\nclass SimHandleBase(ABC):\n    \"\"\"Base class for all simulation objects.\n\n    All simulation objects are hashable and equatable by identity.\n\n    .. code-block:: python\n\n        a = dut.clk\n        b = dut.clk\n        assert a == b\n\n    .. versionchanged:: 2.0\n        ``get_definition_name()`` and ``get_definition_file()`` were removed in favor of :meth:`_def_name` and :meth:`_def_file`, respectively.\n    \"\"\"\n\n    @abstractmethod\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        self._handle = handle\n        self._path: str = self._name if path is None else path\n        \"\"\"The path to this handle, or its name if this is the root handle.\n\n        :meta public:\n        \"\"\"\n\n    @cached_property\n    def _name(self) -> str:\n        \"\"\"The name of an object.\n\n        :meta public:\n        \"\"\"\n        return self._handle.get_name_string()\n\n    @cached_property\n    def _type(self) -> str:\n        \"\"\"The type of an object as a string.\n\n        :meta public:\n        \"\"\"\n        return self._handle.get_type_string()\n\n    @cached_property\n    def _log(self) -> Logger:\n        return logging.getLogger(f\"cocotb.{self._name}\")\n\n    @cached_property\n    def _def_name(self) -> str:\n        \"\"\"The name of a GPI object's definition.\n\n        This is the value of ``vpiDefName`` for VPI, ``vhpiNameP`` for VHPI,\n        and ``mti_GetPrimaryName`` for FLI.\n        Support for this depends on the specific object type and simulator used.\n\n        :meta public:\n        \"\"\"\n        return self._handle.get_definition_name()\n\n    @cached_property\n    def _def_file(self) -> str:\n        \"\"\"The name of the file that sources the object's definition.\n\n        This is the value of ``vpiDefFile`` for VPI, ``vhpiFileNameP`` for VHPI,\n        and ``mti_GetRegionSourceName`` for FLI.\n        Support for this depends on the specific object type and simulator used.\n\n        :meta public:\n        \"\"\"\n        return self._handle.get_definition_file()\n\n    def __hash__(self) -> int:\n        return hash(self._handle)\n\n    def __eq__(self, other: object) -> bool:\n        if not isinstance(other, SimHandleBase):\n            return NotImplemented\n        return self._handle == other._handle\n\n    def __repr__(self) -> str:\n        desc = self._path\n        defname = self._def_name\n        if defname:\n            desc += \" with definition \" + defname\n            deffile = self._def_file\n            if deffile:\n                desc += \" (at \" + deffile + \")\"\n        return type(self).__qualname__ + \"(\" + desc + \")\"\n\n    def __bool__(self) -> NoReturn:\n        raise TypeError(\n            \"This object cannot be cast to bool or used in conditionals. Use `obj is not None` check in conditionals.\"\n        )\n\n    def __getstate__(self) -> NoReturn:\n        raise NotImplementedError(\"Cannot pickle simulator objects\")\n\n\nclass _RangeableObjectMixin(SimHandleBase):\n    \"\"\"Base class for simulation objects that have a range.\"\"\"\n\n    @cached_property\n    def range(self) -> Range:\n        \"\"\"Return a :class:`~cocotb.types.Range` over the indexes of the array/vector.\"\"\"\n        left, right, direction = self._handle.get_range()\n        if direction == cocotb.simulator.RANGE_NO_DIR:\n            raise RuntimeError(\"Expected range to have a direction but got none!\")\n        return Range(\n            left, \"to\" if direction == cocotb.simulator.RANGE_UP else \"downto\", right\n        )\n\n    @property\n    def left(self) -> int:\n        \"\"\"Return the leftmost index in the array/vector.\"\"\"\n        return self.range.left\n\n    @property\n    def direction(self) -> str:\n        \"\"\"Return the direction (``\"to\"``/``\"downto\"``) of indexes in the array/vector.\"\"\"\n        return self.range.direction\n\n    @property\n    def right(self) -> int:\n        \"\"\"Return the rightmost index in the array/vector.\"\"\"\n        return self.range.right\n\n    def __len__(self) -> int:\n        return len(self.range)\n\n\n#: Type of keys (name or index) in HierarchyObjectBase.\nKeyType = TypeVar(\"KeyType\")\n\n#: Subtype of :class:`SimHandleBase` returned when iterating or indexing a :class:`HierarchyArrayObject`.\nHierarchyChildObjectT = TypeVar(\"HierarchyChildObjectT\", bound=SimHandleBase)\n\n\nclass GPIDiscovery(DocIntEnum):\n    \"\"\"Simulator object discovery strategy.\"\"\"\n\n    AUTO = (0, \"Automatic discovery using all registered interfaces.\")\n    NATIVE = (1, \"Native discovery using only the parent's native interface.\")\n\n\nclass _HierarchyObjectBase(SimHandleBase, Generic[KeyType]):\n    \"\"\"Base class for hierarchical simulation objects.\n\n    Hierarchical objects don't have values, they are just scopes/namespaces of other objects.\n    This includes array-like hierarchical structures like \"generate loops\"\n    and named hierarchical structures like \"generate blocks\" or \"module\"/\"entity\" instantiations.\n\n    This base class defines logic to discover, cache, and inspect child objects.\n    It provides a :class:`dict`-like interface for doing so.\n\n    :meth:`_keys`, :meth:`_values`, and :meth:`_items` mimic their :class:`dict` counterparts.\n    You can also iterate over an object, which returns child objects, not keys like in :class:`dict`;\n    and can check the :func:`len`.\n\n    See :class:`HierarchyObject` and :class:`HierarchyArrayObject` for examples.\n    \"\"\"\n\n    @abstractmethod\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n        self._sub_handles: dict[KeyType, SimHandleBase] = {}\n        self._discovered = False\n\n    def _keys(self) -> Iterable[KeyType]:\n        \"\"\"Iterate over the keys (name or index) of the child objects.\n\n        :meta public:\n        \"\"\"\n        self._discover_all()\n        return self._sub_handles.keys()\n\n    def _values(self) -> Iterable[SimHandleBase]:\n        \"\"\"Iterate over the child objects.\n\n        :meta public:\n        \"\"\"\n        self._discover_all()\n        return self._sub_handles.values()\n\n    def _items(self) -> Iterable[tuple[KeyType, SimHandleBase]]:\n        \"\"\"Iterate over ``(key, object)`` tuples of child objects.\n\n        :meta public:\n        \"\"\"\n        self._discover_all()\n        return self._sub_handles.items()\n\n    def _discover_all(self) -> None:\n        \"\"\"When iterating or performing IPython tab completion, we run through ahead of\n        time and discover all possible children, populating the :any:`_sub_handles`\n        mapping. Hierarchy can't change after elaboration so we only have to\n        do this once.\n        \"\"\"\n        if self._discovered:\n            return\n\n        for thing in self._handle.iterate(cocotb.simulator.OBJECTS):\n            name = thing.get_name_string()\n\n            # translate HDL name into a consistent key name\n            try:\n                key = self._sub_handle_key(name)\n            except ValueError:\n                self._log.exception(\n                    \"Unable to translate handle >%s< to a valid _sub_handle key\",\n                    name,\n                )\n                continue\n\n            # compute a full path using the key name\n            path = self._child_path(key)\n\n            # attempt to create the child object\n            try:\n                hdl = _make_sim_object(thing, path)\n            except NotImplementedError:\n                self._log.exception(\n                    \"Unable to construct a SimHandle object for %s\", path\n                )\n                continue\n\n            # add to cache\n            self._sub_handles[key] = hdl\n\n        self._discovered = True\n\n    def _get(\n        self, key: KeyType, discovery_method: GPIDiscovery = GPIDiscovery.AUTO\n    ) -> SimHandleBase | None:\n        \"\"\"Query the simulator for an object with the specified *key*.\n\n        Like Python's native dictionary ``get``-function, this returns ``None`` if the object\n        is not found instead of raising an :exc:`AttributeError`.\n\n        Generally, use the ``handle[child_name]`` syntax instead, unless you have to change the\n        *discovery_method* or want to check for optional signals.\n\n        :meta public:\n\n        Args:\n            key: The child object by name.\n            discovery_method: Optional selection of discovery strategy. :data:`~cocotb.handle.GPIDiscovery.AUTO` by default.\n\n        Returns:\n            The child object, or ``None`` if not found.\n        \"\"\"\n        # try to use cached value\n        try:\n            return self._sub_handles[key]\n        except KeyError:\n            pass\n\n        # try to get value from GPI\n        new_handle = self._get_handle_by_key(key, discovery_method)\n        if new_handle is None:\n            return None\n\n        # if successful, construct and cache\n        sub_handle = _make_sim_object(new_handle, self._child_path(key))\n        self._sub_handles[key] = sub_handle\n\n        return sub_handle\n\n    @abstractmethod\n    def _get_handle_by_key(\n        self, key: KeyType, discovery_method: GPIDiscovery\n    ) -> cocotb.simulator.sim_obj | None:\n        \"\"\"Get child object by key from the simulator.\n\n        Args:\n            key: The key of the child object.\n            discovery_method: How to discover the object using the GPI.\n\n        Returns:\n            A raw simulator handle for the child object at the given key, or ``None``.\n        \"\"\"\n\n    @abstractmethod\n    def _child_path(self, key: KeyType) -> str:\n        \"\"\"Compute the path string of a child object at the given key.\n\n        Args:\n            key: The key of the child object.\n\n        Returns:\n            A path string of the child object at the a given key.\n        \"\"\"\n\n    @abstractmethod\n    def _sub_handle_key(self, name: str) -> KeyType:\n        \"\"\"Translate a discovered child object name into a key.\n\n        Args:\n            name: The GPI name of the child object.\n\n        Returns:\n            A unique key for the child object.\n\n        Raises:\n            ValueError: if unable to translate handle to a valid _sub_handle key.\n        \"\"\"\n\n    def __iter__(self) -> Iterator[SimHandleBase]:\n        return iter(self._values())\n\n    def __len__(self) -> int:\n        self._discover_all()\n        return len(self._sub_handles)\n\n    def __dir__(self) -> Iterable[str]:\n        \"\"\"Permits IPython tab completion and debuggers to work.\"\"\"\n        self._discover_all()\n        return set(super().__dir__()) | {str(k) for k in self._keys()}\n\n\nclass HierarchyObject(_HierarchyObjectBase[str]):\n    r\"\"\"A simulation object that is a name-indexed collection of hierarchical simulation objects.\n\n    Inherits from :class:`SimHandleBase`.\n\n    This class is used for named hierarchical structures, such as \"generate blocks\" or \"module\"/\"entity\" instantiations.\n\n    Children under this structure are found by using the name of the child with either the attribute syntax or index syntax.\n    For example, if in your :envvar:`COCOTB_TOPLEVEL` entity/module you have a signal/net named ``count``, you could do either of the following.\n\n    .. code-block:: python\n\n        dut.count  # attribute syntax\n        dut[\"count\"]  # index syntax\n\n    Attribute syntax is usually shorter and easier to read, and is more common.\n    However, it has limitations:\n\n    - the name cannot start with a number\n    - the name cannot start with a ``_`` character\n    - the name can only contain ASCII letters, numbers, and the ``_`` character.\n\n    Any possible name of an object is supported with the index syntax,\n    but it can be more verbose.\n\n    Accessing a non-existent child with attribute syntax results in an :class:`AttributeError`,\n    and accessing a non-existent child with index syntax results in a :class:`KeyError`.\n\n    .. note::\n        If you need to access signals/nets that start with ``_``,\n        or use escaped identifier (Verilog) or extended identifier (VHDL) characters,\n        you have to use the index syntax.\n        Accessing escaped/extended identifiers requires enclosing the name\n        with leading and trailing double backslashes (``\\\\``).\n\n        .. code-block:: python\n\n            dut[\"_underscore_signal\"]\n            dut[\"\\\\%extended !ID\\\\\"]\n\n    Iteration yields all child objects in no particular order.\n    The :func:`len` function can be used to find the number of children.\n\n    .. code-block:: python\n\n        # discover all children in 'some_module'\n        total = 0\n        for handle in dut.some_module:\n            cocotb.log(\"Found %r\", handle._path)\n            total += 1\n\n        # make sure we found them all\n        assert len(dut.some_module) == total\n    \"\"\"\n\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n\n    def __setattr__(self, name: str, value: object) -> None:\n        # private attributes pass through directly\n        if name.startswith(\"_\"):\n            return object.__setattr__(self, name, value)\n\n        try:\n            getattr(self, name)\n        except AttributeError:\n            raise AttributeError(\n                f\"Cannot set attribute {name!r} on simulation object {self._path}. No such object exists.\"\n            ) from None\n        else:\n            raise AttributeError(\n                f\"Cannot set attribute {name!r} on simulation object {self._path}. Did you forget to add `.value`?\"\n            )\n\n    def __getattr__(self, name: str) -> SimHandleBase:\n        if name.startswith(\"_\"):\n            return object.__getattribute__(self, name)\n\n        handle = self._get(name)\n        if handle is None:\n            raise AttributeError(f\"{self._path} contains no child object named {name}\")\n        return handle\n\n    def __getitem__(self, key: str) -> SimHandleBase:\n        handle = self._get(key)\n        if handle is None:\n            raise KeyError(f\"{self._path} contains no child object named {key}\")\n        return handle\n\n    @deprecated(\n        \"Use `handle[child_name]` syntax instead. If extended identifiers are needed simply add a '\\\\' character before and after the name.\"\n    )\n    def _id(self, name: str, extended: bool = True) -> SimHandleBase:\n        \"\"\"Query the simulator for an object with the specified *name*.\n\n        If *extended* is ``True``, run the query only for VHDL extended identifiers.\n        For Verilog, only ``extended=False`` is supported.\n\n        :meta public:\n\n        Args:\n            name: The child object by name.\n            extended: If ``True``, treat the *name* as an extended identifier.\n\n        Returns:\n            The child object.\n\n        Raises:\n            AttributeError: If the child object is not found.\n\n        .. deprecated:: 2.0\n            Use ``handle[child_name]`` syntax instead.\n            If extended identifiers are needed simply add a ``\\\\`` character before and after the name.\n\n        \"\"\"\n        if extended:\n            name = \"\\\\\" + name + \"\\\\\"\n\n        handle = self._get(name)\n        if handle is None:\n            raise AttributeError(f\"{self._path} contains no child object named {name}\")\n        return handle\n\n    def _child_path(self, key: str) -> str:\n        delimiter = \"::\" if self._type == \"GPI_PACKAGE\" else \".\"\n        return f\"{self._path}{delimiter}{key}\"\n\n    def _sub_handle_key(self, name: str) -> str:\n        return name\n\n    def _get_handle_by_key(\n        self, key: str, discovery_method: GPIDiscovery\n    ) -> cocotb.simulator.sim_obj | None:\n        return self._handle.get_handle_by_name(key, discovery_method)\n\n\nclass HierarchyArrayObject(\n    _HierarchyObjectBase[int], _RangeableObjectMixin, Generic[HierarchyChildObjectT]\n):\n    \"\"\"A simulation object that is an array of hierarchical simulation objects.\n\n    Inherits from :class:`SimHandleBase`.\n\n    This class is used for array-like hierarchical structures like \"generate loops\".\n\n    Children of this object are found by supplying a numerical index using index syntax.\n    For example, if you have a design with a generate loop ``gen_pipe_stages`` from the range ``0`` to ``7``:\n\n    .. code-block:: python\n\n        block_0 = dut.gen_pipe_stages[0]\n        block_7 = dut.gen_pipe_stages[7]\n\n    Accessing a non-existent child results in an :class:`IndexError`.\n\n    Iteration yields all child objects in order.\n\n    .. code-block:: python\n\n        # set all 'reg's in each pipe stage to 0\n        for pipe_stage in dut.gen_pipe_stages:\n            pipe_stage.reg.value = 0\n\n    Use the :meth:`range` property if you want to iterate over the indexes.\n    The :func:`len` function can be used to find the number of elements.\n\n    .. code-block:: python\n\n        # set all 'reg's in each pipe stage to 0\n        for idx in dut.gen_pipe_stages.range:\n            dut.gen_pipe_stages[idx].reg.value = 0\n\n        # make sure we have all the pipe stages\n        assert len(dut.gen_pipe_stage) == len(dut.gen_pipe_stages.range)\n    \"\"\"\n\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n\n    def _sub_handle_key(self, name: str) -> int:\n        # This is slightly hacky, but we need to extract the index from the name\n        # See also GEN_IDX_SEP_* in VhpiImpl.h for the VHPI separators.\n        #\n        # FLI and VHPI:       _name(X) where X is the index\n        # VHPI(ALDEC):        _name__X where X is the index\n        # VPI:                _name[X] where X is the index\n        result = re.match(rf\"{re.escape(self._name)}__(?P<index>\\d+)$\", name)\n        if not result:\n            result = re.match(\n                rf\"{re.escape(self._name)}\\((?P<index>\\d+)\\)$\", name, re.IGNORECASE\n            )\n        if not result:\n            result = re.match(rf\"{re.escape(self._name)}\\[(?P<index>\\d+)\\]$\", name)\n\n        if result:\n            return int(result.group(\"index\"))\n        else:\n            raise ValueError(f\"Unable to match an index pattern: {name}\")\n\n    def _child_path(self, key: int) -> str:\n        return f\"{self._path}[{key}]\"\n\n    def _get_handle_by_key(\n        self, key: int, discovery_method: GPIDiscovery\n    ) -> cocotb.simulator.sim_obj | None:\n        if discovery_method is not GPIDiscovery.AUTO:\n            raise NotImplementedError(\n                f\"Only GPIDiscovery.AUTO is supported for {type(self).__qualname__} right now\"\n            )\n        return self._handle.get_handle_by_index(key)\n\n    def __getitem__(self, key: int) -> HierarchyChildObjectT:\n        if isinstance(key, slice):\n            raise TypeError(\"Slice indexing is not supported\")\n\n        handle = self._get(key)\n        if handle is None:\n            raise IndexError(f\"{self._path} contains no child object at index {key}\")\n        return cast(\"HierarchyChildObjectT\", handle)\n\n    # ideally `__len__` could be implemented in terms of `range`, but `range` doesn't work universally.\n\n    def __iter__(self) -> Iterator[HierarchyChildObjectT]:\n        # must use `sorted(self._keys())` instead of the range because `range` doesn't work universally.\n        for i in sorted(self._keys()):\n            yield self[i]\n\n\nclass _GPISetAction(enum.Enum):\n    # TODO make this a PyGPI exposed Enum\n    DEPOSIT = 0\n    FORCE = 1\n    RELEASE = 2\n    NO_DELAY = 3\n    OLD_IMMEDIATE = 0\n\n\n_ValueT = TypeVar(\"_ValueT\")\n\n\nclass _Action(Generic[_ValueT]):\n    @abstractmethod\n    def _dispatch(self, obj: ValueObjectBase[Any, _ValueT]) -> None: ...\n\n\nclass Deposit(_Action[_ValueT]):\n    r\"\"\":term:`Inertially deposit <inertial deposit>` the given value on a simulator object.\n\n    If another :term:`deposit` comes after this deposit, the newer deposit overwrites the old value.\n    If an HDL process is :term:`driving` the signal/net/register where a deposit from cocotb is made,\n    the deposited value will be overwritten at the end of the next delta cycle,\n    essentially causing a single delta cycle \"glitch\" in the waveform.\n\n    .. note::\n        VHDL applies writes according to their definition.\n        ``signal`` writes are set inertially, regardless of using this class;\n        while ``variable`` writes are set immediately, regardless of using this class.\n    \"\"\"\n\n    def __init__(self, value: _ValueT) -> None:\n        self.value = value\n\n    def _dispatch(self, obj: ValueObjectBase[Any, _ValueT]) -> None:\n        return obj._set_value(self.value, _GPISetAction.DEPOSIT)\n\n\nclass Force(_Action[_ValueT]):\n    r\"\"\":term:`Force <force>` the given value on a simulator object immediately.\n\n    Further :term:`deposits <deposit>` from cocotb or :term:`drives <driving>` from HDL processes\n    do not cause the value to change until the handle is :term:`released <release>` by cocotb or HDL code.\n    Further :term:`forces <force>` will overwrite the value and leave the value forced.\n\n    .. note::\n        VHDL applies writes according to their definition.\n        ``signal`` writes are set inertially, regardless of using this class;\n        while ``variable`` writes are set immediately, regardless of using this class.\n\n    .. note::\n        Verilog :class:`!Force`\\ s are always immediate.\n        This also means that if there are multiple cocotb Tasks or multiple ``always`` blocks writing to the same object,\n        the resulting value is non-deterministic.\n\n    .. note::\n        Issuing a :class:`!Force` and :class:`Release` in the same evaluation cycle in VHDL will result in the :class:`!Force` \"winning\".\n    \"\"\"\n\n    def __init__(self, value: _ValueT) -> None:\n        self.value = value\n\n    def _dispatch(self, obj: ValueObjectBase[Any, _ValueT]) -> None:\n        return obj._set_value(self.value, _GPISetAction.FORCE)\n\n\nclass Freeze(_Action[_ValueT]):\n    r\"\"\":term:`Force <force>` the simulator object with its current value.\n\n    Useful if you have done a :term:`deposit` and later decide to lock the value from changing.\n    Does not change the current value of the simulation object.\n    See :class:`Force` for information on behavior after this write completes.\n\n    .. note::\n        VHDL applies writes according to their definition.\n        ``signal`` writes are set inertially, regardless of using this class;\n        while ``variable`` writes are set immediately, regardless of using this class.\n\n    .. note::\n        Verilog :class:`Force`\\ s are always immediate.\n        This also means that if there are multiple cocotb Tasks or multiple ``always`` blocks writing to the same object,\n        the resulting value is non-deterministic.\n\n    .. note::\n        Issuing a :class:`!Force` and :class:`Release` in the same evaluation cycle in VHDL will result in the :class:`!Force` \"winning\".\n    \"\"\"\n\n    def _dispatch(self, obj: ValueObjectBase[Any, _ValueT]) -> None:\n        return obj._set_value(obj.get(), _GPISetAction.FORCE)\n\n\nclass Release(_Action[_ValueT]):\n    r\"\"\":term:`Release <release>` a :term:`forced <force>` simulation object.\n\n    Does not change the current value of the simulation object.\n    See :class:`Deposit` for information on behavior after this write completes.\n\n    .. note::\n        VHDL applies writes according to their definition.\n        ``signal`` writes are set inertially, regardless of using this class,\n        while ``variable`` writes are set immediately, regardless of using this class.\n\n    .. note::\n        Verilog :class:`!Release`\\ s are always immediate.\n        This also means that if there are multiple cocotb Tasks or multiple ``always`` blocks writing to the same object,\n        the resulting value is non-deterministic.\n\n    .. note::\n        Issuing a :class:`Force` and :class:`!Release` in the same evaluation cycle in VHDL will result in the :class:`!Force` \"winning\".\n\n    .. note::\n        Releasing a ``reg`` or ``logic`` in Verilog will leave the current value.\n        Releasing a ``wire`` in Verilog will cause the value to be recomputed from the wire's drivers current values.\n        Releasing a ``signal`` in VHDL will cause the value to be recomputed from the signal's drivers current value.\n        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.\n    \"\"\"\n\n    def _dispatch(self, obj: ValueObjectBase[Any, _ValueT]) -> None:\n        return obj._set_value(obj.get(), _GPISetAction.RELEASE)\n\n\nclass Immediate(_Action[_ValueT]):\n    \"\"\":term:`Deposit <no-delay deposit>` a value on a simulator object without delay.\n\n    The value of the signal will be changed immediately\n    and should be able to be read back immediately following the write.\n    Otherwise, behaves like :class:`Deposit`.\n\n    .. note::\n        VHDL applies writes according to their definition.\n        ``signal`` writes are set inertially, regardless of using this class;\n        while ``variable`` writes are set immediately, regardless of using this class.\n\n    .. note::\n        In Verilog, because these writes are immediate,\n        if there are multiple cocotb Tasks or multiple ``always`` blocks writing to the same object,\n        the resulting value is non-deterministic.\n    \"\"\"\n\n    def __init__(self, value: _ValueT) -> None:\n        self.value = value\n\n    def _dispatch(self, obj: ValueObjectBase[Any, _ValueT]) -> None:\n        return obj._set_value(self.value, _GPISetAction.NO_DELAY)\n\n\nclass _OldImmediate(_Action[_ValueT]):\n    def __init__(self, value: _ValueT) -> None:\n        self.value = value\n\n    def _dispatch(self, obj: ValueObjectBase[Any, _ValueT]) -> None:\n        return obj._set_value(self.value, _GPISetAction.OLD_IMMEDIATE)\n\n\n_apply_writes_cb: TriggerCallback | None = None\n\n\n_trust_inertial: bool = _env.as_bool(\"COCOTB_TRUST_INERTIAL_WRITES\")\nif _trust_inertial:\n\n    def _apply_scheduled_writes() -> None:\n        pass\n\n    def _schedule_write(\n        handle: ValueObjectBase[Any, Any],\n        write_func: Callable[[int, _ValueT], None],\n        action: _GPISetAction,\n        value: _ValueT,\n    ) -> None:\n        # Trust the simulator and just write.\n        write_func(action.value, value)\n\nelse:\n    # A dictionary of pending (write_func, args), keyed by handle.\n    # Writes are applied oldest to newest (least recently used).\n    # Only the last scheduled write to a particular handle in a timestep is performed.\n    _write_calls: dict[\n        ValueObjectBase[Any, Any], tuple[Callable[[int, Any], None], _GPISetAction, Any]\n    ] = {}\n\n    def _apply_scheduled_writes() -> None:\n        for func, action, value in _write_calls.values():\n            func(action.value, value)\n        _write_calls.clear()\n\n        # Clear variable so the next scheduled writes re-primes ReadWrite()\n        # for the next set of writes.\n        global _apply_writes_cb\n        _apply_writes_cb = None\n\n    def _schedule_write(\n        handle: ValueObjectBase[Any, Any],\n        write_func: Callable[[int, _ValueT], None],\n        action: _GPISetAction,\n        value: _ValueT,\n    ) -> None:\n        if isinstance(current_gpi_trigger(), ReadWrite):\n            # If we are already in the ReadWrite phase,\n            # apply writes immediately as an optimization.\n            write_func(action.value, value)\n        elif action is _GPISetAction.DEPOSIT:\n            # Queue write for the beginning of the next ReadWrite phase because we can't trust the simulator. =(\n            if handle in _write_calls:\n                del _write_calls[handle]\n            _write_calls[handle] = (write_func, action, value)\n\n            # Register ReadWrite to occur but do nothing. ReadWrite._do_callbacks() is\n            # set up so _apply_scheduled_writes() executes first.\n            global _apply_writes_cb\n            if _apply_writes_cb is None:\n                _apply_writes_cb = ReadWrite()._register(lambda: None)\n\n        else:\n            # If we are writing anything that isn't an inertial write,\n            # it must be applied immediately.\n            write_func(action.value, value)\n\n\n#: Type returned by the :attr:`~ValueObjectBase.value` getter and returned by the :meth:`~ValueObjectBase.get` method.\nValueGetT = TypeVar(\"ValueGetT\")\n\n\n#: Type accepted by the :attr:`~ValueObjectBase.value` setter and the :meth:`~ValueObjectBase.set` and :meth:`~ValueObjectBase.setimmediatevalue` methods.\nValueSetT = TypeVar(\"ValueSetT\")\n\n\nclass ValueObjectBase(SimHandleBase, Generic[ValueGetT, ValueSetT]):\n    \"\"\"Abstract base class for simulation objects that have a value.\n\n    Inherits from :class:`SimHandleBase`.\n    \"\"\"\n\n    @property\n    def value(self) -> ValueGetT:\n        \"\"\"Get or set the value of the simulation object.\n\n        :getter: Return the current value of the simulation object.\n\n        :setter:\n            Set the value of the simulation object.\n\n            See :class:`Deposit`, :class:`Force`, :class:`Freeze`, :class:`Release`, and :class:`Immediate`\n            for additional actions that can be taken when setting a value.\n            These are used like so:\n\n            .. code-block:: python\n\n                dut.handle.value = 1  # default Deposit action\n                dut.handle.value = Deposit(2)\n                dut.handle.value = Force(3)\n                dut.handle.value = Freeze()\n                dut.handle.value = Release()\n                dut.handle.value = Immediate(4)\n        \"\"\"\n        return self.get()\n\n    @value.setter\n    def value(\n        self,\n        value: ValueSetT\n        | Deposit[ValueSetT]\n        | Force[ValueSetT]\n        | Freeze\n        | Release\n        | Immediate[ValueSetT],\n    ) -> None:\n        if isinstance(current_gpi_trigger(), ReadOnly):\n            raise RuntimeError(\"Attempting settings a value during the ReadOnly phase.\")\n        if self.is_const:\n            raise TypeError(\"Attempted setting an immutable object\")\n        if isinstance(value, _Action):\n            return value._dispatch(self)\n        else:\n            # default to deposit without creating a new object\n            return self._set_value(value, _GPISetAction.DEPOSIT)\n\n    @abstractmethod\n    def get(self) -> ValueGetT:\n        \"\"\"Return the current value of the simulation object.\"\"\"\n\n    @abstractmethod\n    def set(\n        self,\n        value: ValueSetT\n        | Deposit[ValueSetT]\n        | Force[ValueSetT]\n        | Freeze\n        | Release\n        | Immediate[ValueSetT],\n    ) -> None:\n        \"\"\"Set the value of the simulation object.\n\n        See :class:`Deposit`, :class:`Force`, :class:`Freeze`, :class:`Release`, and :class:`Immediate`\n        for additional actions that can be taken when setting a value.\n\n        Args:\n            value: The value to set the simulation object to. This may include type conversion.\n\n        Raises:\n            TypeError: If the *value* is of a type that cannot be converted to a simulation value,\n                or if the simulation object is immutable.\n            ValueError: If the *value* is of the correct type, but the value fails to convert.\n        \"\"\"\n\n    @deprecated(\n        \"Use `handle.set(Immediate(...))` or `handle.value = Immediate(...)` instead.\"\n    )\n    def setimmediatevalue(\n        self,\n        value: ValueSetT\n        | Deposit[ValueSetT]\n        | Force[ValueSetT]\n        | Freeze\n        | Release\n        | Immediate[ValueSetT],\n    ) -> None:\n        r\"\"\"Set the value of the simulation object immediately.\n\n        See :class:`Deposit`, :class:`Force`, :class:`Freeze`, :class:`Release`, and :class:`Immediate`\n        for additional actions that can be taken when setting a value.\n\n        Passing :class:`Deposit`\\ s and unwrapped values is equivalent to passing an :class:`Immediate` to :meth:`set`.\n\n        .. deprecated:: 2.0\n            Use ``handle.set(Immediate(...))`` or ``handle.value = Immediate(...)`` instead.\n            This could result in a change in behavior because prior to version 2.0 this function did not set values immediately.\n        \"\"\"\n        if isinstance(value, Deposit):\n            value = _OldImmediate(value.value)  # type: ignore\n        elif not isinstance(value, (Force, Freeze, Release, Immediate)):\n            value = _OldImmediate(value)  # type: ignore\n        self.value = value\n\n    @cached_property\n    def is_const(self) -> bool:\n        \"\"\"``True`` if the simulator object is immutable, e.g. a Verilog parameter or VHDL constant or generic.\"\"\"\n        return self._handle.get_const()\n\n    @abstractmethod\n    def _set_value(\n        self,\n        value: ValueSetT,\n        action: _GPISetAction,\n    ) -> None:\n        \"\"\"Schedule a write of the given value to a simulator object.\n\n        Conversion from multiple Python types into a type understood by the simulator is expected.\n        This is used to implement the :attr:`value` property setter, :meth:`setimmediatevalue`, and :meth:`set`.\n        Implementations can assume that handle isn't :meth:`const <is_const>`\n        and the Scheduler is not in the :data:`ReadOnly <cocotb.SimPhase.READ_ONLY>` phase.\n\n        Args:\n            value: A value used to set the handle.\n            action: Whether to deposit, force, or release the value on the handle.\n        \"\"\"\n\n\n#: Type of value of each element in an :class:`ArrayObject`.\nElemValueT = TypeVar(\"ElemValueT\")\n\n#: Subtype of :class:`ValueObjectBase` returned when iterating or indexing a :class:`ArrayObject`.\nChildObjectT = TypeVar(\"ChildObjectT\", bound=ValueObjectBase[Any, Any])\n\n\nclass ArrayObject(\n    ValueObjectBase[Array[ElemValueT], Union[Array[ElemValueT], Sequence[ElemValueT]]],\n    _RangeableObjectMixin,\n    Generic[ElemValueT, ChildObjectT],\n):\n    \"\"\"A simulation object that is an array of value-having simulation objects.\n\n    Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`.\n\n    With Verilog simulation objects, unpacked vectors are mapped to this type.\n    Packed vectors are typically mapped to :class:`LogicArrayObject`.\n\n    With VHDL simulation objects, all arrayed objects that aren't ``std_(u)logic``,\n    ``sfixed``, ``ufixed``, ``unsigned``, ``signed``, and ``string`` are mapped to this type.\n\n    These objects can be iterated over to yield child objects:\n\n    .. code-block:: python\n\n        for child in dut.array_object:\n            print(child._path)\n\n    A particular child can be retrieved using its index:\n\n    .. code-block:: python\n\n        child = dut.array_object[0]\n\n        # reversed iteration over children\n        for child_idx in reversed(dut.array_object.range):\n            dut.array_object[child_idx]\n    \"\"\"\n\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n        self._sub_handles: dict[int, ChildObjectT] = {}\n\n    def get(self) -> Array[ElemValueT]:\n        \"\"\"Return the current value as an :class:`~cocotb.types.Array`.\n\n        Given the HDL array ``arr``, getting the value is equivalent to:\n\n        +--------------+---------------------+--------------------------------------------------------------------------------------------------+\n        | Verilog      | VHDL                | ``arr.get()`` is equivalent to                                                                   |\n        +==============+=====================+==================================================================================================+\n        | ``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))``     |\n        +--------------+---------------------+--------------------------------------------------------------------------------------------------+\n        | ``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))`` |\n        +--------------+---------------------+--------------------------------------------------------------------------------------------------+\n        \"\"\"\n        r = self.range\n        return Array._from_handle(\n            value=[self[i].value for i in r],\n            range=r,\n            warn_indexing=indexing_changed(r) if do_indexing_changed_warning else False,\n        )\n\n    def set(\n        self,\n        value: Array[ElemValueT]\n        | Sequence[ElemValueT]\n        | Deposit[Array[ElemValueT] | Sequence[ElemValueT]]\n        | Force[Array[ElemValueT] | Sequence[ElemValueT]]\n        | Freeze\n        | Release\n        | Immediate[Array[ElemValueT] | Sequence[ElemValueT]],\n    ) -> None:\n        \"\"\"Set the value using an :class:`.Array`-like value.\n\n        The simulation object is set, element-by-element, left-to-right, using the corresponding element of *value*.\n        The indexes of *value* and the simulation object are not taken into account, only position.\n\n        .. warning::\n            Assigning a value to a sub-handle:\n\n            - **Wrong**: ``dut.some_array.value[0] = 1`` (gets value as an Array, updates index 0, then throws it away)\n            - **Correct**: ``dut.some_array[0].value = 1``\n\n        Args:\n            value: The value to set the signal to. This may include type conversion.\n\n        Raises:\n            TypeError: If *value* is of a type that can't be assigned to the simulation object.\n\n        .. warning::\n            Exceptions from array element :meth:`.ValueObjectBase.set` calls will be propagated up,\n            so the actual set of exceptions possible is greater than this list.\n        \"\"\"\n        self.value = value\n\n    def _set_value(\n        self,\n        value: Array[ElemValueT] | Sequence[ElemValueT],\n        action: _GPISetAction,\n    ) -> None:\n        if len(value) != len(self):\n            raise ValueError(\n                f\"Assigning list of length {len(value)} to object {self._name} of length {len(self)}\"\n            )\n        for elem, self_idx in zip(value, self.range):\n            self[self_idx]._set_value(elem, action)\n\n    def __getitem__(self, index: int) -> ChildObjectT:\n        if isinstance(index, slice):\n            raise TypeError(\"Slicing is not supported\")\n        if index in self._sub_handles:\n            return self._sub_handles[index]\n        new_handle = self._handle.get_handle_by_index(index)\n        if not new_handle:\n            raise IndexError(f\"{self._path} contains no object at index {index}\")\n        path = self._path + \"[\" + str(index) + \"]\"\n        self._sub_handles[index] = cast(\n            \"ChildObjectT\", _make_sim_object(new_handle, path)\n        )\n        return self._sub_handles[index]\n\n    def __iter__(self) -> Iterable[ChildObjectT]:\n        for i in self.range:\n            yield self[i]\n\n\nclass _NonIndexableValueObjectBase(ValueObjectBase[ValueGetT, ValueSetT]):\n    \"\"\"ValueObject that is treated as a single object in the GPI.\n\n    NonArrayValueObjects support :meth:`value_change` triggers.\n    \"\"\"\n\n    @cached_property\n    def value_change(self) -> ValueChange:\n        \"\"\"A trigger which fires whenever the value changes.\"\"\"\n        if self.is_const:\n            raise TypeError(\"Can't get ValueChange on immutable signal.\")\n        return ValueChange._make(self)\n\n    @cached_property\n    def _edge(self) -> Edge:\n        if self.is_const:\n            raise TypeError(\"Can't get Edge on immutable signal.\")\n        return Edge._make(self)\n\n\nclass LogicObject(\n    _NonIndexableValueObjectBase[Logic, Union[Logic, int, str, LogicArray]]\n):\n    \"\"\"A scalar logic simulation object.\n\n    Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`.\n\n    Verilog data types that map to this object:\n\n        * ``logic``\n        * ``bit``\n\n    VHDL types that map to this object:\n\n        * ``std_logic``\n        * ``std_ulogic``\n        * ``bit``\n    \"\"\"\n\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n\n    def _set_value(\n        self,\n        value: Logic | int | str | LogicArray,\n        action: _GPISetAction,\n    ) -> None:\n        value_: str\n        if isinstance(value, (int, str)):\n            value_ = str(Logic(value))\n\n        elif isinstance(value, LogicArray):\n            if len(value) != 1:\n                raise ValueError(\n                    f\"Cannot assign value of length {len(value)} to handle of length 1\"\n                )\n            value_ = str(value)\n\n        elif isinstance(value, Logic):\n            value_ = str(value)\n\n        else:\n            raise TypeError(\n                f\"Unsupported type for value assignment: {type(value)} ({value!r})\"\n            )\n\n        _schedule_write(self, self._handle.set_signal_val_binstr, action, value_)\n\n    def get(self) -> Logic:\n        \"\"\"Return the current value of the simulation object as a :class:`.Logic`.\"\"\"\n        binstr = self._handle.get_signal_val_binstr()\n        return Logic(binstr)\n\n    def set(\n        self,\n        value: Logic\n        | int\n        | str\n        | LogicArray\n        | Deposit[Logic | int | str | LogicArray]\n        | Force[Logic | int | str | LogicArray]\n        | Freeze\n        | Release\n        | Immediate[Logic | int | str | LogicArray],\n    ) -> None:\n        \"\"\"Set the value of the simulation object using a :class:`.Logic`-like value.\n\n        Args:\n            value: The value to set the simulation object to.\n\n        Raises:\n            TypeError: If *value* is of a type that can't be assigned to the simulation object, or readily converted into a type that can.\n            ValueError: If *value* would not fit in the bounds of the simulation object.\n        \"\"\"\n        self.value = value\n\n    @cached_property\n    def rising_edge(self) -> RisingEdge:\n        \"\"\"A trigger which fires whenever the value changes to a ``1``.\"\"\"\n        if self.is_const:\n            raise TypeError(\"Can't get RisingEdge on immutable signal\")\n        return RisingEdge._make(self)\n\n    @cached_property\n    def falling_edge(self) -> FallingEdge:\n        \"\"\"A trigger which fires whenever the value changes to a ``0``.\"\"\"\n        if self.is_const:\n            raise TypeError(\"Can't get FallingEdge on immutable signal\")\n        return FallingEdge._make(self)\n\n    def __len__(self) -> int:\n        return 1\n\n    @deprecated(\n        \"`int(handle)` casts have been deprecated. Use `int(handle.value)` instead.\"\n    )\n    def __int__(self) -> int:\n        return int(self.value)\n\n    @deprecated(\n        \"`str(handle)` casts have been deprecated. Use `str(handle.value)` instead.\"\n    )\n    def __str__(self) -> str:\n        return str(self.value)\n\n\nclass _SignednessObjectMixin(SimHandleBase):\n    @abstractmethod\n    def __len__(self) -> int: ...\n\n    @cached_property\n    def is_signed(self) -> bool:\n        signed = self._handle.get_signed()\n        if signed == -1:\n            raise RuntimeError(f\"Simulator failed to get signedness of {self._path!r}.\")\n        return bool(signed)\n\n    @cached_property\n    def _min_val(self) -> int:\n        signed = self._handle.get_signed()\n        if signed == 0:\n            return 0\n        else:\n            return -(2 ** (len(self) - 1))\n\n    @cached_property\n    def _max_val(self) -> int:\n        signed = self._handle.get_signed()\n        if signed == 1:\n            return (2 ** (len(self) - 1)) - 1\n        else:\n            return (2 ** len(self)) - 1\n\n\nclass LogicArrayObject(\n    _NonIndexableValueObjectBase[LogicArray, Union[LogicArray, Logic, int, str]],\n    _RangeableObjectMixin,\n    _SignednessObjectMixin,\n):\n    \"\"\"A logic array simulation object.\n\n    Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`.\n\n    Verilog packed vectors, structs, and unions do not map to this type, but :class:`PackedObject`.\n    Unpacked vectors of type ``logic`` and ``bit`` map to :class:`ArrayObject`.\n\n    VHDL types that map to this object:\n\n        * ``std_logic_vector`` and ``std_ulogic_vector``\n        * ``unsigned``\n        * ``signed``\n        * ``ufixed``\n        * ``sfixed``\n        * ``float``\n\n    .. versionchanged:: 2.1\n        Verilog packed objects no longer map to this type, but :class:`PackedObject`.\n    \"\"\"\n\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n\n    def _set_value(\n        self,\n        value: LogicArray | Logic | int | str,\n        action: _GPISetAction,\n    ) -> None:\n        value_: str\n        if isinstance(value, int):\n            if not self._min_val <= value <= self._max_val:\n                raise ValueError(\n                    f\"Int value ({value!r}) out of range for assignment of {len(self)!r}-bit signal ({self._name!r})\"\n                )\n\n            if len(self) <= 32:\n                return _schedule_write(\n                    self, self._handle.set_signal_val_int, action, value\n                )\n            else:\n                if value < 0:\n                    value += 1 << len(self)\n                value_ = f\"{value:0{len(self)}b}\"\n\n        elif isinstance(value, str):\n            value_ = value.replace(\"_\", \"\")  # remove visual separators\n            value_ = value_.upper()  # normalize to uppercase\n            nonliterals = set(value_) - _str_literals\n            if nonliterals:\n                nonliteral_str = \", \".join(repr(c) for c in sorted(nonliterals))\n                raise ValueError(\n                    f\"String literal contains invalid logic values: {nonliteral_str}\"\n                )\n\n        elif isinstance(value, (LogicArray, Logic)):\n            value_ = str(value)\n\n        else:\n            raise TypeError(\n                f\"Unsupported type for value assignment: {type(value)} ({value!r})\"\n            )\n\n        if len(value_) != len(self):\n            raise ValueError(\n                f\"Cannot assign value of length {len(value_)} to handle of length {len(self)}\"\n            )\n        _schedule_write(self, self._handle.set_signal_val_binstr, action, value_)\n\n    def get(self) -> LogicArray:\n        \"\"\"Return the current value of the simulation object as a :class:`.LogicArray`.\"\"\"\n        binstr = self._handle.get_signal_val_binstr()\n        return LogicArray._from_handle(\n            value=binstr,\n            warn_indexing=indexing_changed(self.range)\n            if do_indexing_changed_warning\n            else False,\n        )\n\n    def set(\n        self,\n        value: LogicArray\n        | Logic\n        | int\n        | str\n        | Deposit[LogicArray | Logic | int | str]\n        | Force[LogicArray | Logic | int | str]\n        | Freeze\n        | Release\n        | Immediate[LogicArray | Logic | int | str],\n    ) -> None:\n        \"\"\"Set the value of the simulation object using a :class:`.LogicArray`-like value.\n\n        Args:\n            value: The value to set the simulation object to.\n\n        Raises:\n            TypeError: If *value* is of a type that can't be assigned to the simulation object, or readily converted into a type that can.\n            ValueError: If *value* would not fit in the bounds of the simulation object.\n\n        .. versionchanged:: 2.0\n            Using :class:`ctypes.Structure` objects to set values was removed.\n            Convert the struct object to a :class:`~cocotb.types.LogicArray` before assignment using\n            ``LogicArray(\"\".join(format(int(byte), \"08b\") for byte in bytes(struct_obj)))`` instead.\n\n        .. versionchanged:: 2.0\n            Using :class:`dict` objects to set values was removed.\n            Convert the dictionary to an integer before assignment using\n            ``sum(v << (d['bits'] * i) for i, v in enumerate(d['values']))`` instead.\n\n        .. versionchanged:: 2.0\n            Supplying too large of an :class:`int` value results in raising a :exc:`ValueError` instead of an :exc:`OverflowError`.\n        \"\"\"\n        self.value = value\n\n    @deprecated(\n        \"`int(handle)` casts have been deprecated. Use `int(handle.value)` instead.\"\n    )\n    def __int__(self) -> int:\n        return int(self.value)\n\n    @deprecated(\n        \"`str(handle)` casts have been deprecated. Use `str(handle.value)` instead.\"\n    )\n    def __str__(self) -> str:\n        return str(self.value)\n\n    def __len__(self) -> int:\n        # can't use `range` to get length because `range` is for outer-most dimension only\n        # and this object needs to support multi-dimensional packed arrays.\n        return self._handle.get_num_elems()\n\n    def __getitem__(self, index: int) -> LogicObject:\n        handle = self._handle.get_handle_by_index(index)\n        if handle is None:\n            raise IndexError\n\n        return LogicObject(handle, self._path)\n\n    @cached_property\n    def _min_val(self) -> int:\n        # Backwards compatibility. Always wrap negative values.\n        return -(2 ** (len(self) - 1))\n\n    @cached_property\n    def _max_val(self) -> int:\n        # Backwards compatibility. Always wrap negative values.\n        return (2 ** len(self)) - 1\n\n    @cached_property\n    def rising_edge(self) -> RisingEdge:\n        \"\"\"A trigger which fires whenever the value changes to a ``1``.\"\"\"\n        if len(self) != 1:\n            raise TypeError(f\"Can't get RisingEdge on {len(self)}-bit signal\")\n        if self.is_const:\n            raise TypeError(\"Can't get RisingEdge on immutable signal\")\n        return RisingEdge._make(self)\n\n    @cached_property\n    def falling_edge(self) -> FallingEdge:\n        \"\"\"A trigger which fires whenever the value changes to a ``0``.\"\"\"\n        if len(self) != 1:\n            raise TypeError(f\"Can't get FallingEdge on {len(self)}-bit signal\")\n        if self.is_const:\n            raise TypeError(\"Can't get FallingEdge on immutable signal\")\n        return FallingEdge._make(self)\n\n\nclass PackedObject(LogicArrayObject):\n    \"\"\"A packed Verilog struct, union, or vector simulation object.\n\n    Verilog types that map to this object:\n\n        * packed any-dimensional vectors of ``logic`` or ``bit``.\n        * packed any-dimensional vectors of packed structures or unions.\n\n    .. versionadded:: 2.1\n    \"\"\"\n\n    def __getitem__(self, _: object) -> NoReturn:\n        raise TypeError(\n            \"Indexing into Verilog packed objects (arrays, structs, or unions) is not currently supported.\\n\"\n            \"Try instead reading the whole value and slicing: `t = handle.value; t[0:3]`.\\n\"\n            \"If you need to use an element in an Edge Trigger, consider making the array or struct unpacked.\\n\"\n            \"Alternatively, use `ValueChange` on the whole object and check the bit(s) you care about for changes afterwards.\"\n        )\n\n\nclass RealObject(_NonIndexableValueObjectBase[float, float]):\n    \"\"\"A floating point simulation object.\n\n    Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`.\n\n    This type is used when a ``real`` object in VHDL or ``float`` object in Verilog is seen.\n    \"\"\"\n\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n\n    def _set_value(\n        self,\n        value: float,\n        action: _GPISetAction,\n    ) -> None:\n        if not isinstance(value, (float, int)):\n            raise TypeError(\n                f\"Unsupported type for real value assignment: {type(value)} ({value!r})\"\n            )\n\n        _schedule_write(self, self._handle.set_signal_val_real, action, value)\n\n    def get(self) -> float:\n        \"\"\"Return the current value of the simulation object as a :class:`float`.\"\"\"\n        return self._handle.get_signal_val_real()\n\n    def set(\n        self,\n        value: float\n        | Deposit[float]\n        | Force[float]\n        | Freeze\n        | Release\n        | Immediate[float],\n    ) -> None:\n        \"\"\"Set the value of the simulation object using a :class:`float` value.\n\n        Args:\n            value: The value to set the simulation object to.\n\n        Raises:\n            TypeError: If *value* is any type other than :class:`float`.\n        \"\"\"\n        self.value = value\n\n    @deprecated(\n        \"`float(handle)` casts have been deprecated. Use `float(handle.value)` instead.\"\n    )\n    def __float__(self) -> float:\n        return self.value\n\n\nclass EnumObject(\n    _NonIndexableValueObjectBase[int, int],\n    _SignednessObjectMixin,\n):\n    \"\"\"An enumeration simulation object.\n\n    Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`.\n\n    This type is used when an enumerated-type simulation object is seen that aren't a \"logic\" or similar type.\n    The value of this object is represented with an :class:`int`.\n\n    For VHDL objects, the value being represented is the enumeration value at the integer index into the original ``type`` declaration,\n    as if it were a 1-based array.\n\n    For Verilog objects, enumerations are little more than named integer values.\n    There may be many enumeration values that a given :class:`int` value represents.\n    \"\"\"\n\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n\n    def _set_value(\n        self,\n        value: int,\n        action: _GPISetAction,\n    ) -> None:\n        if not isinstance(value, int):\n            raise TypeError(\n                f\"Unsupported type for enum value assignment: {type(value)} ({value!r})\"\n            )\n\n        if not self._min_val <= value <= self._max_val:\n            raise ValueError(\n                f\"Int value ({value!r}) out of range for assignment of enum signal ({self._name!r})\"\n            )\n\n        if len(self) <= 32:\n            # set_signal_val_int is limited to 32 bits.\n            return _schedule_write(self, self._handle.set_signal_val_int, action, value)\n        else:\n            return _schedule_write(\n                self,\n                self._handle.set_signal_val_binstr,\n                action,\n                format(value, f\"0{len(self)}b\"),\n            )\n\n    def get(self) -> int:\n        \"\"\"Return the current value of the simulation object as an :class:`int`.\n\n        See :class:`EnumObject` for details on what :class:`int` values correspond to which enumeration values.\n        \"\"\"\n        if len(self) <= 32:\n            res = self._handle.get_signal_val_long()\n        else:\n            res = int(self._handle.get_signal_val_binstr(), 2)\n        if res > self._max_val:\n            res -= 1 << len(self)\n        elif self._handle.get_signed() == 0 and res < 0:\n            res += 1 << len(self)\n        return res\n\n    def set(\n        self,\n        value: int | Deposit[int] | Force[int] | Freeze | Release | Immediate[int],\n    ) -> None:\n        \"\"\"Set the value of the simulation object using an :class:`int`.\n\n        See :class:`EnumObject` for details on what :class:`int` values correspond to which enumeration values.\n\n        Args:\n            value: The value to set the simulation object to.\n\n        Raises:\n            TypeError: If *value* is any type other than :class:`int`.\n            ValueError: If *value* would not fit in a 32-bit signed integer.\n\n        .. versionchanged:: 2.0\n            Supplying too large of a value results in raising a :exc:`ValueError` instead of an :exc:`OverflowError`.\n        \"\"\"\n        self.value = value\n\n    @deprecated(\n        \"`int(handle)` casts have been deprecated. Use `int(handle.value)` instead.\"\n    )\n    def __int__(self) -> int:\n        return int(self.value)\n\n    def __len__(self) -> int:\n        return self._handle.get_num_elems()\n\n\nclass IntegerObject(_NonIndexableValueObjectBase[int, int], _SignednessObjectMixin):\n    \"\"\"An integer simulation object.\n\n    Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`.\n\n    Verilog types that map to this object:\n\n        * ``byte``\n        * ``shortint``\n        * ``int``\n        * ``longint``\n\n    This type should not be used for the 4-state integer types ``integer`` and ``time``.\n\n    VHDL types that map to this object:\n\n        * ``integer``\n        * ``natural``\n        * ``positive``\n\n    Objects that use this type are assumed to be two's complement 32-bit integers with 2-state (``0`` and ``1``) bits.\n    \"\"\"\n\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n\n    def _set_value(\n        self,\n        value: int,\n        action: _GPISetAction,\n    ) -> None:\n        if not isinstance(value, int):\n            raise TypeError(\n                f\"Unsupported type for integer value assignment: {type(value)} ({value!r})\"\n            )\n\n        if not self._min_val <= value <= self._max_val:\n            raise ValueError(\n                f\"Int value ({value!r}) out of range for assignment of integer signal ({self._name!r})\"\n            )\n\n        if len(self) <= 32:\n            # set_signal_val_int is limited to 32 bits.\n            return _schedule_write(self, self._handle.set_signal_val_int, action, value)\n        else:\n            if value < 0:\n                value += 1 << len(self)\n            value_ = format(value, f\"0{len(self)}b\")\n\n            return _schedule_write(\n                self,\n                self._handle.set_signal_val_binstr,\n                action,\n                value_,\n            )\n\n    def get(self) -> int:\n        \"\"\"Return the current value of the simulation object as an :class:`int`.\"\"\"\n        if len(self) <= 32:\n            res = self._handle.get_signal_val_long()\n        else:\n            res = int(self._handle.get_signal_val_binstr(), 2)\n        if res > self._max_val:\n            res -= 1 << len(self)\n        elif self._handle.get_signed() == 0 and res < 0:\n            res += 1 << len(self)\n        return res\n\n    def set(\n        self,\n        value: int | Deposit[int] | Force[int] | Freeze | Release | Immediate[int],\n    ) -> None:\n        \"\"\"Set the the value of the simulation object using an :class:`int` value.\n\n        Args:\n            value: The value to set the simulation object to.\n\n        Raises:\n            TypeError: If *value* is any type other than :class:`int`.\n            ValueError: If *value* would not fit in a 32-bit signed integer.\n\n        .. versionchanged:: 2.0\n            Supplying too large of a value results in raising a :exc:`ValueError` instead of an :exc:`OverflowError`.\n        \"\"\"\n        self.value = value\n\n    @deprecated(\n        \"`int(handle)` casts have been deprecated. Use `int(handle.value)` instead.\"\n    )\n    def __int__(self) -> int:\n        return self.value\n\n    def __len__(self) -> int:\n        return self._handle.get_num_elems()\n\n\nclass StringObject(\n    _NonIndexableValueObjectBase[bytes, bytes],\n    _RangeableObjectMixin,\n):\n    \"\"\"A string simulation object.\n\n    Inherits from :class:`SimHandleBase` and :class:`ValueObjectBase`.\n\n    This type is used when a ``string`` (VHDL or Verilog) simulation object is seen.\n    \"\"\"\n\n    def __init__(self, handle: cocotb.simulator.sim_obj, path: str | None) -> None:\n        super().__init__(handle, path)\n\n    def _set_value(\n        self,\n        value: bytes,\n        action: _GPISetAction,\n    ) -> None:\n        if not isinstance(value, (bytes, bytearray)):\n            raise TypeError(\n                f\"Unsupported type for string value assignment: {type(value)} ({value!r})\"\n            )\n        _schedule_write(self, self._handle.set_signal_val_str, action, value)\n\n    def get(self) -> bytes:\n        \"\"\"Return the current value of the simulation object as a :class:`bytes`.\"\"\"\n        return self._handle.get_signal_val_str()\n\n    def set(\n        self,\n        value: bytes\n        | Deposit[bytes]\n        | Force[bytes]\n        | Freeze\n        | Release\n        | Immediate[bytes],\n    ) -> None:\n        \"\"\"Set the value of the simulation object with a :class:`bytes` or :class:`bytearray` value.\n\n        When *value*'s length is less than the simulation object's,\n        the value is padded with NUL (``'\\0'``) characters up to the appropriate length.\n        When the value's length is greater than the simulation object's,\n        the value is truncated without a NUL terminator to the appropriate length,\n        without warning.\n\n        Strings in both Verilog and VHDL are byte arrays without any particular encoding.\n        Encoding must be done to turn Python strings into byte arrays.\n        Because `there are many encodings <https://docs.python.org/3/library/codecs.html#standard-encodings>`_,\n        this step is left up to the user.\n\n        An example of how encoding and decoding could be accomplished using an ASCII string.\n\n        .. code-block:: python\n\n            # lowercase a string\n            value = dut.string_handle.value.decode(\"ascii\")\n            value = value.lower()\n            dut.string_handle.value = value.encode(\"ascii\")\n\n        Args:\n            value: The value to set the simulation object to.\n\n        Raises:\n            TypeError: If *value* is any type other than :class:`bytes`.\n\n        .. versionchanged:: 1.4\n            Takes :class:`bytes` instead of :class:`str`.\n            Users are now expected to choose an encoding when using these objects.\n        \"\"\"\n        self.value = value\n\n    @deprecated(\n        '`str(handle)` casts have been deprecated. Use `handle.value.decode(\"ascii\")` instead.'\n    )\n    def __str__(self) -> str:\n        return self.value.decode(\"ascii\")\n\n\n_ConcreteHandleTypes = Union[\n    HierarchyObject,\n    HierarchyArrayObject[SimHandleBase],\n    LogicObject,\n    LogicArrayObject,\n    PackedObject,\n    ArrayObject[Any, ValueObjectBase[Any, Any]],\n    RealObject,\n    IntegerObject,\n    EnumObject,\n    StringObject,\n]\n\n\n_handle2obj: dict[\n    cocotb.simulator.sim_obj,\n    _ConcreteHandleTypes,\n] = {}\n\n_type2cls: dict[int, type[_ConcreteHandleTypes]] = {\n    cocotb.simulator.MODULE: HierarchyObject,\n    cocotb.simulator.STRUCTURE: HierarchyObject,\n    cocotb.simulator.PACKED_STRUCTURE: LogicArrayObject,\n    cocotb.simulator.LOGIC: LogicObject,\n    cocotb.simulator.LOGIC_ARRAY: LogicArrayObject,\n    cocotb.simulator.PACKED_OBJECT: PackedObject,\n    cocotb.simulator.NETARRAY: ArrayObject[Any, ValueObjectBase[Any, Any]],\n    cocotb.simulator.REAL: RealObject,\n    cocotb.simulator.INTEGER: IntegerObject,\n    cocotb.simulator.ENUM: EnumObject,\n    cocotb.simulator.STRING: StringObject,\n    cocotb.simulator.GENARRAY: HierarchyArrayObject[SimHandleBase],\n    cocotb.simulator.PACKAGE: HierarchyObject,\n}\n\n\ndef _make_sim_object(\n    handle: cocotb.simulator.sim_obj, path: str | None = None\n) -> SimHandleBase:\n    \"\"\"Factory function to create the correct type of `SimHandle` object.\n\n    Args:\n        handle: The GPI handle to the simulator object.\n        path: Path to this handle.\n\n    Returns:\n        An appropriate :class:`SimHandleBase` object.\n\n    Raises:\n        NotImplementedError: If no matching object for GPI type could be found.\n    \"\"\"\n\n    # Enforce singletons since it's possible to retrieve handles avoiding\n    # the hierarchy by getting driver/load information\n    try:\n        return _handle2obj[handle]\n    except KeyError:\n        pass\n\n    t = handle.get_type()\n    if t not in _type2cls:\n        raise NotImplementedError(\n            f\"Couldn't find a matching object for GPI type {handle.get_type_string()}({t}) (path={path})\"\n        )\n    obj = _type2cls[t](handle, path)\n    _handle2obj[handle] = obj\n    return obj\n"
  },
  {
    "path": "src/cocotb/logging.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"\nEverything related to logging\n\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nimport os\nimport re\nimport sys\nimport time\nimport warnings\nfrom functools import wraps\nfrom typing import Callable\n\nimport cocotb.simtime\nimport cocotb.simulator\nfrom cocotb._ANSI import ANSI\nfrom cocotb._deprecation import deprecated\nfrom cocotb.simtime import TimeUnit, get_sim_time\nfrom cocotb.utils import get_time_from_sim_steps\nfrom cocotb_tools import _env\n\n__all__ = (\n    \"ANSI\",\n    \"SimLog\",\n    \"SimLogFormatter\",\n    \"SimTimeContextFilter\",\n    \"default_config\",\n    \"strip_ansi\",\n)\n\nANSI.__module__ = __name__\n\n# Custom log level\nlogging.TRACE = 5  # type: ignore[attr-defined]  # type checkers don't like adding module attributes after the fact\nlogging.addLevelName(5, \"TRACE\")\n\n\nstrip_ansi: bool = False\n\"\"\"Whether the default formatter should strip ANSI (color) escape codes from log messages.\n\nDefaults to ``True`` if ``stdout`` is not a TTY and ``False`` otherwise;\nbut can be overridden with the :envvar:`NO_COLOR` or :envvar:`COCOTB_ANSI_OUTPUT` environment variable.\n\"\"\"\n\n\ndef default_config(\n    reduced_log_fmt: bool = True,\n    strip_ansi: bool | None = None,\n    prefix_format: str | None = None,\n    multiline_indent: int | Callable[[str], int] | None = None,\n) -> None:\n    \"\"\"Apply the default cocotb log formatting to the root logger.\n\n    This hooks up the logger to write to stdout, using :class:`SimLogFormatter` for formatting.\n    It also adds a :class:`SimTimeContextFilter` filter so that the\n    :attr:`~logging.LogRecord.created_sim_time` attribute on :class:`~logging.LogRecord`\n    is available to the formatter.\n\n    If desired, this logging configuration can be overwritten by calling\n    ``logging.basicConfig(..., force=True)`` (in Python 3.8 onwards),\n    or by manually resetting the root logger instance.\n    An example of this can be found in the section on :ref:`rotating-logger`.\n\n    Args:\n        reduced_log_fmt:\n            If ``True``, use a reduced log format that does not include the\n            filename, line number, and function name in the log prefix.\n\n            .. versionadded:: 2.0\n\n        strip_ansi:\n            If ``True``, strip ANSI (color) escape codes in log messages.\n            If ``False``, do not strip ANSI escape codes in log messages.\n            If ``None``, use the value of :data:`strip_ansi`.\n\n            .. versionadded:: 2.0\n\n        prefix_format:\n            An f-string to build a prefix for each log message.\n\n            .. versionadded:: 2.0\n\n        multiline_indent:\n            Controls the indentation of subsequent log lines in a multiline\n            log message.\n            If the argument is a callable, it will be called every time with\n            the stripped formatted prefix string and should return the number\n            of spaces to indent.\n            If a non-negative integer, it will be used directly as the number\n            of spaces to indent.\n            If a negative integer, the indentation will be the length of the\n            stripped prefix, when formatted with an empty LogRecord. This is\n            calculated only on initialization, so it's fast but assumes that\n            the prefix length does not change.\n            If ``None``, the length of the stripped prefix will be used.\n\n            .. versionadded:: 2.1\n\n    .. versionadded:: 1.4\n\n    .. versionchanged:: 2.0\n        Now captures warnings and outputs them through the logging system using\n        :func:`logging.captureWarnings`.\n    \"\"\"\n    # Using the stream=sys.stdout argument will ensure that the root logger without any handlers\n    # will be always configured to have the stdout stream handler\n    logging.basicConfig(stream=sys.stdout)\n\n    # Pytest or other frameworks can add custom log handlers, we need to ensure that log output will be consistent\n    for handler in logging.getLogger().handlers:\n        handler.addFilter(SimTimeContextFilter())\n\n        handler.setFormatter(\n            SimLogFormatter(\n                reduced_log_fmt=reduced_log_fmt,\n                strip_ansi=strip_ansi,\n                prefix_format=prefix_format,\n                multiline_indent=multiline_indent,\n            )\n        )\n\n    logging.getLogger(\"cocotb\").setLevel(logging.INFO)\n    logging.getLogger(\"gpi\").setLevel(logging.INFO)\n\n    logging.captureWarnings(True)\n\n\ndef _init() -> None:\n    \"\"\"cocotb-specific logging setup.\n\n    - Decides whether ANSI escape code stripping is desired by checking\n      :envvar:`NO_COLOR` and :envvar:`COCOTB_ANSI_OUTPUT`.\n    - Initializes the GPI logger and sets up the GPI logging optimization.\n    - Sets the log level of the ``\"cocotb\"`` and ``\"gpi\"`` loggers based on\n      :envvar:`COCOTB_LOG_LEVEL` and :envvar:`GPI_LOG_LEVEL`, respectively.\n    \"\"\"\n    global strip_ansi\n\n    strip_ansi = not _env.as_bool(\n        \"COCOTB_ANSI_OUTPUT\",\n        sys.stdout.isatty() and not _env.as_str(\"NO_COLOR\") and not _env.as_bool(\"GUI\"),\n    )\n\n    _setup_gpi_logger()\n\n    # Set \"cocotb\" and \"gpi\" logger based on environment variables\n    def set_level(logger_name: str, envvar: str) -> None:\n        log_level: str = _env.as_str(envvar).upper()\n        if not log_level:\n            return\n\n        logger = logging.getLogger(logger_name)\n\n        try:\n            logger.setLevel(log_level)\n        except ValueError:\n            valid_levels = \", \".join(\n                (\"CRITICAL\", \"ERROR\", \"WARNING\", \"INFO\", \"DEBUG\", \"TRACE\", \"NOTSET\")\n            )\n            raise ValueError(\n                f\"Invalid log level {log_level!r} passed through the \"\n                f\"{envvar} environment variable. Valid log \"\n                f\"levels: {valid_levels}\"\n            ) from None\n\n    set_level(\"gpi\", \"GPI_LOG_LEVEL\")\n    set_level(\"cocotb\", \"COCOTB_LOG_LEVEL\")\n\n\ndef _setup_gpi_logger() -> None:\n    \"\"\"Setup logger for GPI.\"\"\"\n    # Monkeypatch \"gpi\" logger with function that also sets a PyGPI-local logger level\n    # as an optimization.\n    gpi_logger = logging.getLogger(\"gpi\")\n    old_setLevel = gpi_logger.setLevel\n\n    @wraps(old_setLevel)\n    def setLevel(level: int | str) -> None:\n        old_setLevel(level)\n        cocotb.simulator.set_gpi_log_level(gpi_logger.getEffectiveLevel())\n\n    gpi_logger.setLevel = setLevel  # type: ignore[method-assign]\n\n    # Initialize PyGPI logging\n    cocotb.simulator.initialize_logger(_log_from_c, logging.getLogger)\n\n\ndef _configure() -> None:\n    \"\"\"Configure basic logging.\"\"\"\n    reduced_log_fmt: bool = _env.as_bool(\"COCOTB_REDUCED_LOG_FMT\", True)\n    prefix_format: str = os.getenv(\"COCOTB_LOG_PREFIX\", \"\")\n    default_config(reduced_log_fmt=reduced_log_fmt, prefix_format=prefix_format)\n\n\n@deprecated('Use `logging.getLogger(f\"{name}.0x{ident:x}\")` instead')\ndef SimLog(name: str, ident: int | None = None) -> logging.Logger:\n    \"\"\"Like :func:`logging.getLogger`, but append a numeric identifier to the name.\n\n    Args:\n        name: Logger name.\n        ident: Unique integer identifier.\n\n    Returns:\n        The Logger named ``{name}.0x{ident:x}``.\n\n    .. deprecated:: 2.0\n\n        Use ``logging.getLogger(f\"{name}.0x{ident:x}\")`` instead.\n    \"\"\"\n    if ident is not None:\n        name = f\"{name}.0x{ident:x}\"\n    return logging.getLogger(name)\n\n\nclass SimTimeContextFilter(logging.Filter):\n    \"\"\"\n    A filter to inject simulator times into the log records.\n\n    This uses the approach described in the :ref:`Python logging cookbook <python:filters-contextual>`\n    which adds the :attr:`~logging.LogRecord.created_sim_time` attribute.\n\n    .. versionadded:: 1.4\n    \"\"\"\n\n    def filter(self, record: logging.LogRecord) -> bool:\n        try:\n            record.created_sim_time = get_sim_time()\n        except RecursionError:\n            # get_sim_time may try to log - if that happens, we can't\n            # attach a simulator time to this message.\n            record.created_sim_time = None\n        return True\n\n\n# Justify and truncate\ndef _ljust(string: str, chars: int) -> str:\n    if len(string) > chars:\n        return \"..\" + string[(chars - 2) * -1 :]\n    return string.ljust(chars)\n\n\ndef _rjust(string: str, chars: int) -> str:\n    if len(string) > chars:\n        return \"..\" + string[(chars - 2) * -1 :]\n    return string.rjust(chars)\n\n\n# Default simtime formatter\ndef _simtime_fmt(record: logging.LogRecord, unit: TimeUnit) -> str:\n    sim_time = getattr(record, \"created_sim_time\", None)\n    if sim_time is None:\n        return f\"-.--{unit}\"\n    time_ns = get_time_from_sim_steps(sim_time, unit)\n    return f\"{time_ns:.2f}{unit}\"\n\n\nclass SimLogFormatter(logging.Formatter):\n    \"\"\"Log formatter to provide consistent log message handling.\n\n    This will only add simulator timestamps if the handler object this\n    formatter is attached to has a :class:`SimTimeContextFilter` filter\n    attached, which cocotb ensures by default.\n\n    See :func:`.default_config` for a description of the arguments.\n    \"\"\"\n\n    loglevel2colour = {\n        logging.TRACE: \"\",  # type: ignore[attr-defined]  # type checkers don't like adding module attributes after the fact\n        logging.DEBUG: \"\",\n        logging.INFO: \"\",\n        logging.WARNING: ANSI.YELLOW_FG,\n        logging.ERROR: ANSI.RED_FG,\n        logging.CRITICAL: ANSI.RED_BG + ANSI.BLACK_FG,\n    }\n\n    prefix_func_globals = {\n        \"time\": time,\n        \"simtime\": cocotb.simtime,\n        \"ANSI\": ANSI,\n        \"ljust\": _ljust,\n        \"rjust\": _rjust,\n        \"simtime_fmt\": _simtime_fmt,\n    }\n\n    def __init__(\n        self,\n        *,\n        reduced_log_fmt: bool = True,\n        strip_ansi: bool | None = None,\n        prefix_format: str | None = None,\n        multiline_indent: int | Callable[[str], int] | None = None,\n    ) -> None:\n        self._reduced_log_fmt = reduced_log_fmt\n        self._strip_ansi = strip_ansi\n        self._ansi_escape_pattern = re.compile(\n            r\"\"\"\n                \\x1B\n                (?: # either 7-bit C1, two bytes, ESC Fe (omitting CSI)\n                    [@-Z\\\\-_]\n                | # or 7-bit CSI (ESC [) + control codes\n                    \\[\n                    [0-?]*  # Parameter bytes\n                    [ -/]*  # Intermediate bytes\n                    [@-~]   # Final byte\n                )\n            \"\"\",\n            re.VERBOSE,\n        )\n\n        if not prefix_format:\n            prefix_format = \"{simtime_fmt(record,'ns'):>11} {level_color_start}{record.levelname:<8}{level_color_end} {ljust(record.name, 34)} \"\n            if not self._reduced_log_fmt:\n                prefix_format = (\n                    prefix_format\n                    + \"{rjust(record.filename, 20)}:{record.lineno:<4} in {ljust(str(record.funcName), 31)} \"\n                )\n            if multiline_indent is None:\n                # The default prefix_formats length is fixed, so unless explicitly\n                # overridden, precompute indentation on initialization.\n                multiline_indent = -1\n\n        self._prefix_func = eval(\n            f\"lambda record, level_color_start, level_color_end: f'''{prefix_format}'''\",\n            type(self).prefix_func_globals,\n        )\n\n        if isinstance(multiline_indent, int) and multiline_indent < 0:\n            # Compute the indentation based on the length of the prefix\n            # when formatted with an empty LogRecord.\n            record = logging.getLogger().makeRecord(\n                \"\", logging.INFO, \"\", 0, \"\", (), None, func=\"\"\n            )\n            multiline_indent = len(\n                self._ansi_escape_pattern.sub(\"\", self._prefix_func(record, \"\", \"\"))\n            )\n\n        if multiline_indent is None:\n            self._multiline_indent: int | Callable[[str], int] = len\n        else:\n            self._multiline_indent = multiline_indent\n\n    def strip_ansi(self) -> bool:\n        return strip_ansi if self._strip_ansi is None else self._strip_ansi\n\n    # Justify and truncate\n    @staticmethod\n    def ljust(string: str, chars: int) -> str:\n        return _ljust(string, chars)\n\n    @staticmethod\n    def rjust(string: str, chars: int) -> str:\n        return _rjust(string, chars)\n\n    def formatExcInfo(self, record: logging.LogRecord) -> str:\n        msg = \"\"\n\n        # these lines are copied and updated from the built-in logger\n        if record.exc_info:\n            # Cache the traceback text to avoid converting it multiple times\n            # (it's constant anyway)\n            if not record.exc_text:\n                record.exc_text = self.formatException(record.exc_info)\n        if record.exc_text:\n            msg += record.exc_text\n        if record.stack_info:\n            if not msg.endswith(\"\\n\"):\n                msg += \"\\n\"\n            msg += self.formatStack(record.stack_info)\n\n        return msg\n\n    def format(self, record: logging.LogRecord) -> str:\n        msg = record.getMessage()\n\n        if self.strip_ansi():\n            level_color_start = \"\"\n            level_color_end = \"\"\n        else:\n            level_color_start = self.loglevel2colour.get(record.levelno, \"\")\n            level_color_end = ANSI.DEFAULT if level_color_start else \"\"\n\n        prefix = self._prefix_func(record, level_color_start, level_color_end)\n\n        if self.strip_ansi():\n            output = self._ansi_escape_pattern.sub(\"\", f\"{prefix}{msg}\")\n        elif level_color_start:\n            # NOTE: this handles the case where the string to log applies some\n            # custom coloring, but then reverts to default. The default should\n            # be this log level's default and not the terminal's. This assumes\n            # that ANSI.DEFAULT is used to revert.\n            output = f\"{prefix}{level_color_start}{msg.replace(ANSI.DEFAULT, level_color_start)}{ANSI.DEFAULT}\"\n        else:\n            # Just in case the log message itself contains ANSI codes,\n            # always revert to default at the end.\n            output = f\"{prefix}{msg}{ANSI.DEFAULT}\"\n\n        exc_info = self.formatExcInfo(record)\n        if exc_info:\n            multiline = True\n            output = f\"{output}\\n{exc_info}\"\n        else:\n            multiline = \"\\n\" in msg\n\n        if (not multiline) or (self._multiline_indent == 0):\n            return output\n\n        lines = output.splitlines()\n\n        # add padding to each line of message\n        if isinstance(self._multiline_indent, int):\n            indent = self._multiline_indent\n        else:\n            indent = self._multiline_indent(self._ansi_escape_pattern.sub(\"\", prefix))\n        pad = \"\\n\" + \" \" * indent\n\n        return pad.join(lines)\n\n\nclass SimColourLogFormatter(SimLogFormatter):\n    \"\"\"Log formatter similar to :class:`SimLogFormatter`, but with colored output by default.\n\n    .. deprecated:: 2.0\n        Use :class:`!SimLogFormatter` with ``strip_ansi=False`` instead.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        reduced_log_fmt: bool = True,\n        strip_ansi: bool | None = False,\n        prefix_format: str | None = None,\n    ) -> None:\n        warnings.warn(\n            \"SimColourLogFormatter is deprecated and will be removed in a future release. \"\n            \"Use SimLogFormatter with `strip_ansi=False` instead.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        super().__init__(\n            reduced_log_fmt=reduced_log_fmt,\n            strip_ansi=strip_ansi,\n            prefix_format=prefix_format,\n        )\n\n\ndef _log_from_c(\n    logger: logging.Logger,\n    level: int,\n    filename: str,\n    lineno: int,\n    msg: str,\n    function_name: str,\n) -> None:\n    \"\"\"\n    This is for use from the C world, and allows us to insert C stack\n    information.\n    \"\"\"\n    if logger.isEnabledFor(level):\n        record = logger.makeRecord(\n            logger.name, level, filename, lineno, msg, (), None, function_name\n        )\n        logger.handle(record)\n"
  },
  {
    "path": "src/cocotb/py.typed",
    "content": ""
  },
  {
    "path": "src/cocotb/queue.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport asyncio.queues\nimport collections\nimport heapq\nimport sys\nfrom abc import abstractmethod\nfrom typing import Generic, Protocol, TypeVar\n\nimport cocotb\nimport cocotb.task\nfrom cocotb._utils import pointer_str\nfrom cocotb.task import Task\nfrom cocotb.triggers import Event\n\nif sys.version_info >= (3, 11):\n    from typing import Self\n\n__all__ = (\n    \"AbstractQueue\",\n    \"LifoQueue\",\n    \"PriorityQueue\",\n    \"Queue\",\n    \"QueueEmpty\",\n    \"QueueFull\",\n)\n\n\nclass QueueFull(asyncio.queues.QueueFull):\n    \"\"\"Raised when the :meth:`Queue.put_nowait()` method is called on a full :class:`Queue`.\"\"\"\n\n\nclass QueueEmpty(asyncio.queues.QueueEmpty):\n    \"\"\"Raised when the :meth:`Queue.get_nowait()` method is called on an empty :class:`Queue`.\"\"\"\n\n\nT = TypeVar(\"T\")\n\n\nclass AbstractQueue(Generic[T]):\n    \"\"\"A queue, useful for coordinating producer and consumer coroutines.\n\n    If *maxsize* is less than or equal to 0, the queue size is infinite. If it\n    is an integer greater than 0, then :meth:`put` will block when the queue\n    reaches *maxsize*, until an item is removed by :meth:`get`.\n    \"\"\"\n\n    def __init__(self, maxsize: int = 0) -> None:\n        self._maxsize: int = maxsize\n        self._getters: collections.deque[tuple[Event, Task[object]]] = (\n            collections.deque()\n        )\n        self._putters: collections.deque[tuple[Event, Task[object]]] = (\n            collections.deque()\n        )\n\n    @abstractmethod\n    def _get(self) -> T:\n        \"\"\"Remove and return the next element from the queue.\"\"\"\n\n    @abstractmethod\n    def _put(self, item: T) -> None:\n        \"\"\"Place a new element on the queue.\"\"\"\n\n    @abstractmethod\n    def _size(self) -> int:\n        \"\"\"Return the number of elements in the queue.\"\"\"\n\n    @abstractmethod\n    def _repr(self) -> str:\n        \"\"\"Return a string representation of the state of the queue.\"\"\"\n\n    def _wakeup_next(\n        self, waiters: collections.deque[tuple[Event, Task[object]]]\n    ) -> None:\n        while waiters:\n            event, task = waiters.popleft()\n            if not task.done():\n                event.set()\n                break\n\n    def __repr__(self) -> str:\n        return f\"<{type(self).__name__} {self._format()} at {pointer_str(self)}>\"\n\n    def __str__(self) -> str:\n        return f\"<{type(self).__name__} {self._format()}>\"\n\n    def _format(self) -> str:\n        result = f\"maxsize={self._maxsize!r}\"\n        if getattr(self, \"_queue\", None):\n            result += f\" _queue={self._repr()}\"\n        if self._getters:\n            result += f\" _getters[{len(self._getters)}]\"\n        if self._putters:\n            result += f\" _putters[{len(self._putters)}]\"\n        return result\n\n    def qsize(self) -> int:\n        \"\"\"Number of items in the queue.\"\"\"\n        return self._size()\n\n    @property\n    def maxsize(self) -> int:\n        \"\"\"Number of items allowed in the queue.\"\"\"\n        return self._maxsize\n\n    def empty(self) -> bool:\n        \"\"\"Return ``True`` if the queue is empty, ``False`` otherwise.\"\"\"\n        return self._size() == 0\n\n    def full(self) -> bool:\n        \"\"\"Return ``True`` if there are :meth:`maxsize` items in the queue.\n\n        .. note::\n            If the Queue was initialized with ``maxsize=0`` (the default), then\n            :meth:`full` is never ``True``.\n        \"\"\"\n        if self._maxsize <= 0:\n            return False\n        else:\n            return self.qsize() >= self._maxsize\n\n    async def put(self, item: T) -> None:\n        \"\"\"Put an *item* into the queue.\n\n        If the queue is full, wait until a free\n        slot is available before adding the item.\n        \"\"\"\n        while self.full():\n            event = Event()\n            self._putters.append((event, cocotb.task.current_task()))\n            await event.wait()\n        self.put_nowait(item)\n\n    def put_nowait(self, item: T) -> None:\n        \"\"\"Put an *item* into the queue without blocking.\n\n        If no free slot is immediately available, raise :exc:`~cocotb.queue.QueueFull`.\n        \"\"\"\n        if self.full():\n            raise QueueFull()\n        self._put(item)\n        self._wakeup_next(self._getters)\n\n    async def get(self) -> T:\n        \"\"\"Remove and return an item from the queue.\n\n        If the queue is empty, wait until an item is available.\n        \"\"\"\n        while self.empty():\n            event = Event()\n            self._getters.append((event, cocotb.task.current_task()))\n            await event.wait()\n        return self.get_nowait()\n\n    def get_nowait(self) -> T:\n        \"\"\"Remove and return an item from the queue.\n\n        Return an item if one is immediately available, else raise\n        :exc:`~cocotb.queue.QueueEmpty`.\n        \"\"\"\n        if self.empty():\n            raise QueueEmpty()\n        item = self._get()\n        self._wakeup_next(self._putters)\n        return item\n\n\nclass Queue(AbstractQueue[T]):\n    \"\"\"A subclass of :class:`AbstractQueue`; retrieves oldest entries first (FIFO).\"\"\"\n\n    def __init__(self, maxsize: int = 0) -> None:\n        super().__init__(maxsize)\n        self._queue: collections.deque[T] = collections.deque()\n\n    def _put(self, item: T) -> None:\n        self._queue.append(item)\n\n    def _get(self) -> T:\n        return self._queue.popleft()\n\n    def _size(self) -> int:\n        return len(self._queue)\n\n    def _repr(self) -> str:\n        return repr(self._queue)\n\n\nclass SupportsRichComparison(Protocol):\n    def __eq__(self, other: object) -> bool: ...\n    def __lt__(self, other: Self) -> bool: ...\n    def __le__(self, other: Self) -> bool: ...\n    def __gt__(self, other: Self) -> bool: ...\n    def __ge__(self, other: Self) -> bool: ...\n\n\nSupportsRichComparisonT = TypeVar(\n    \"SupportsRichComparisonT\", bound=\"SupportsRichComparison\"\n)\n\n\nclass PriorityQueue(AbstractQueue[SupportsRichComparisonT]):\n    r\"\"\"A subclass of :class:`AbstractQueue`; retrieves entries in priority order (smallest item first).\n\n    Entries are typically tuples of the form ``(priority number, data)``.\n    \"\"\"\n\n    def __init__(self, maxsize: int = 0) -> None:\n        super().__init__(maxsize)\n        self._queue: list[SupportsRichComparisonT] = []\n\n    def _put(self, item: SupportsRichComparisonT) -> None:\n        heapq.heappush(self._queue, item)\n\n    def _get(self) -> SupportsRichComparisonT:\n        return heapq.heappop(self._queue)\n\n    def _size(self) -> int:\n        return len(self._queue)\n\n    def _repr(self) -> str:\n        return repr(self._queue)\n\n\nclass LifoQueue(AbstractQueue[T]):\n    \"\"\"A subclass of :class:`AbstractQueue`; retrieves most recently added entries first (LIFO).\"\"\"\n\n    def __init__(self, maxsize: int = 0) -> None:\n        super().__init__(maxsize)\n        self._queue: collections.deque[T] = collections.deque()\n\n    def _put(self, item: T) -> None:\n        self._queue.append(item)\n\n    def _get(self) -> T:\n        return self._queue.pop()\n\n    def _size(self) -> int:\n        return len(self._queue)\n\n    def _repr(self) -> str:\n        return repr(self._queue)\n"
  },
  {
    "path": "src/cocotb/regression.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"All things relating to regression capabilities.\"\"\"\n\nfrom __future__ import annotations\n\nimport hashlib\nimport inspect\nimport logging\nimport os\nimport random\nimport re\nimport sys\nimport time\nimport warnings\nfrom enum import Enum, auto\nfrom importlib import import_module\nfrom typing import Any, cast\n\nimport pytest\n\nimport cocotb\nimport cocotb._event_loop\nimport cocotb._shutdown as shutdown\nimport cocotb.handle\nimport cocotb.simulator\nimport cocotb.types._resolve\nfrom cocotb import logging as cocotb_logging\nfrom cocotb._decorators import Test, TestGenerator\nfrom cocotb._gpi_triggers import Timer\nfrom cocotb._test_factory import TestFactory\nfrom cocotb._test_manager import TestManager, TestSuccess\nfrom cocotb._utils import DocEnum, safe_divide\nfrom cocotb._xunit_reporter import XUnitReporter, bin_xml_escape\nfrom cocotb.logging import ANSI\nfrom cocotb.simtime import get_sim_time\nfrom cocotb_tools import _env\n\n__all__ = (\n    \"RegressionManager\",\n    \"RegressionMode\",\n    \"SimFailure\",\n    \"Test\",\n    \"TestFactory\",\n    \"TestGenerator\",\n)\n\n# Set __module__ on re-exports\nTestGenerator.__module__ = __name__\nTest.__module__ = __name__\nTestFactory.__module__ = __name__\n\n\n_TestFailures: tuple[type[BaseException], ...] = (\n    AssertionError,\n    pytest.raises.Exception,  # type: ignore[attr-defined]\n)\n\nif hasattr(pytest, \"RaisesGroup\") and hasattr(pytest, \"RaisesExc\"):\n\n    def handle_pytest_exception_matchers(\n        exc: BaseException,\n        expected_error_set: set[\n            type[BaseException] | pytest.RaisesExc | pytest.RaisesGroup\n        ],\n    ) -> tuple[set[pytest.RaisesExc | pytest.RaisesGroup], bool]:\n        \"\"\"Filter out :class:`pytest.RaisesExc` and :class:`pytest.RaisesGroup` exceptions and do checking on them.\n\n        Args:\n            exc: The exception result of the test.\n            expected_error_set: The set of expected exceptions and :class:`!pytest.RaisesExc` and :class:`!pytest.RaisesGroup` objects.\n\n        Returns:\n            A tuple of the filtered out :class:`!pytest.RaisesExc` and :class:`!pytest.RaisesGroup` objects\n            (so that the caller may remove them from the exception set)\n            and a boolean whether there was a match.\n        \"\"\"\n        exception_matcher_excs = cast(\n            \"set[pytest.RaisesExc | pytest.RaisesGroup]\",\n            {\n                exc\n                for exc in expected_error_set\n                if isinstance(exc, (pytest.RaisesExc, pytest.RaisesGroup))\n            },\n        )\n\n        for exception_matcher_exc in exception_matcher_excs:\n            if exception_matcher_exc.matches(exc):\n                # We got an exception that matches an exception matcher, so we consider the test passed.\n                return exception_matcher_excs, True\n\n        return exception_matcher_excs, False\n\nelse:\n\n    def handle_pytest_exception_matchers(\n        exc: BaseException,\n        expected_error_set: set[\n            type[BaseException] | pytest.RaisesExc | pytest.RaisesGroup\n        ],\n    ) -> tuple[set[pytest.RaisesExc | pytest.RaisesGroup], bool]:\n        return set(), False\n\n\nclass SimFailure(BaseException):\n    \"\"\"A Test failure due to simulator failure.\n\n    .. caution::\n        Not to be raised or caught within a test.\n        Only used for marking expected failure with ``expect_error`` in :func:`cocotb.test`.\n    \"\"\"\n\n\nclass RegressionTerminated(BaseException):\n    \"\"\"Indicates the regression was terminated early.\n\n    The regression can be terminated early by setting :envvar:`COCOTB_MAX_FAILURES`.\n\n\n    .. caution::\n        Not intended to be raised or caught by user code.\n        Used internally by the :class:`RegressionManager`.\n    \"\"\"\n\n\n_logger = logging.getLogger(__name__)\n\n\ndef _format_doc(docstring: str | None) -> str:\n    if docstring is None:\n        return \"\"\n    else:\n        brief = docstring.split(\"\\n\")[0]\n        return f\"\\n    {brief}\"\n\n\nclass RegressionMode(DocEnum):\n    \"\"\"The mode of the :class:`RegressionManager`.\"\"\"\n\n    REGRESSION = (\n        auto(),\n        \"\"\"Tests are run if included. Skipped tests are skipped, expected failures and errors are respected.\"\"\",\n    )\n\n    TESTCASE = (\n        auto(),\n        \"\"\"Like :attr:`REGRESSION`, but skipped tests are *not* skipped if included.\"\"\",\n    )\n\n\nclass _TestOutcome(Enum):\n    PASS = auto()\n    FAIL = auto()\n    SKIP = auto()\n    XFAIL = auto()\n\n\nclass _TestResults:\n    def __init__(\n        self,\n        test_fullname: str,\n        outcome: _TestOutcome,\n        wall_time_s: float,\n        sim_time_ns: float,\n    ) -> None:\n        self.test_fullname = test_fullname\n        self.outcome = outcome\n        self.wall_time_s = wall_time_s\n        self.sim_time_ns = sim_time_ns\n\n    @property\n    def ratio(self) -> float:\n        return safe_divide(self.sim_time_ns, self.wall_time_s)\n\n\nclass RegressionManager:\n    \"\"\"Object which manages tests.\n\n    This object uses the builder pattern to build up a regression.\n    Tests are added using :meth:`register_test` or :meth:`discover_tests`.\n    Inclusion filters for tests can be added using :meth:`add_filters`.\n    The \"mode\" of the regression can be controlled using :meth:`set_mode`.\n    These methods can be called in any order any number of times before :meth:`start_regression` is called,\n    and should not be called again after that.\n\n    Once all the tests, filters, and regression behavior configuration is done,\n    the user starts the regression with :meth:`start_regression`.\n    This method must be called exactly once.\n\n    Until the regression is started, :attr:`total_tests`, :attr:`count`, :attr:`passed`,\n    :attr:`skipped`, and :attr:`failures` hold placeholder values.\n    \"\"\"\n\n    COLOR_TEST = ANSI.BLUE_FG\n    COLOR_PASSED = ANSI.GREEN_FG\n    COLOR_SKIPPED = ANSI.YELLOW_FG\n    COLOR_FAILED = ANSI.RED_FG\n    COLOR_XFAILED = ANSI.YELLOW_FG\n\n    _timer1 = Timer(1)\n\n    def __init__(self) -> None:\n        self._test: Test\n        self._running_test: TestManager\n        self.log = _logger\n        self._regression_start_time: float\n        self._test_results: list[_TestResults] = []\n        self.total_tests = 0\n        \"\"\"Total number of tests that will be run or skipped.\"\"\"\n        self.count = 0\n        \"\"\"The current test count.\"\"\"\n        self.passed = 0\n        \"\"\"The current number of passed tests.\"\"\"\n        self.skipped = 0\n        \"\"\"The current number of skipped tests.\"\"\"\n        self.failures = 0\n        \"\"\"The current number of failed tests.\"\"\"\n        self._tearing_down = False\n        self._test_queue: list[Test] = []\n        self._filters: list[re.Pattern[str]] = []\n        self._mode = RegressionMode.REGRESSION\n        self._included: list[bool]\n        self._regression_terminated: BaseException | None = None\n        self._regression_seed = cocotb.RANDOM_SEED\n        self._random_test_order = _env.as_bool(\n            \"COCOTB_RANDOM_TEST_ORDER\", default=False\n        )\n        self._random_state: Any\n        self._max_failures = _env.as_int(\"COCOTB_MAX_FAILURES\", default=0)\n        self._random_x_resolver_state: Any\n\n        # Setup XUnit\n        ###################\n\n        results_filename = os.getenv(\"COCOTB_RESULTS_FILE\", \"results.xml\")\n        suite_name = os.getenv(\"COCOTB_RESULT_TESTSUITE\", \"all\")\n        package_name = os.getenv(\"COCOTB_RESULT_TESTPACKAGE\", \"all\")\n\n        self.xunit = XUnitReporter(filename=results_filename)\n        self.xunit.add_testsuite(name=suite_name, package=package_name)\n        self.xunit.add_property(name=\"random_seed\", value=str(cocotb.RANDOM_SEED))\n\n    def discover_tests(self, *modules: str) -> None:\n        \"\"\"Discover tests in files automatically.\n\n        Should be called before :meth:`start_regression` is called.\n\n        Args:\n            modules: Each argument given is the name of a module where tests are found.\n        \"\"\"\n        for module_name in modules:\n            mod = import_module(module_name)\n\n            found_test: bool = False\n            for obj_name, obj in vars(mod).items():\n                if isinstance(obj, Test):\n                    found_test = True\n                    self.register_test(obj)\n                elif isinstance(obj, TestGenerator):\n                    found_test = True\n                    generated_tests: bool = False\n                    for test in obj.generate_tests():\n                        generated_tests = True\n                        self.register_test(test)\n                    if not generated_tests:\n                        warnings.warn(\n                            f\"TestGenerator generated no tests: {module_name}.{obj_name}\",\n                            stacklevel=2,\n                        )\n\n            if not found_test:\n                warnings.warn(\n                    f\"No tests were discovered in module: {module_name}\", stacklevel=2\n                )\n\n        # error if no tests were discovered\n        if not self._test_queue:\n            modules_str = \", \".join(repr(m) for m in modules)\n            raise RuntimeError(f\"No tests were discovered in any module: {modules_str}\")\n\n    def add_filters(self, *filters: str) -> None:\n        \"\"\"Add regular expressions to filter-in registered tests.\n\n        Only those tests which match at least one of the given filters are included;\n        the rest are excluded.\n\n        Should be called before :meth:`start_regression` is called.\n\n        Args:\n            filters: Each argument given is a regex pattern for test names.\n                A match *includes* the test.\n        \"\"\"\n        for filter in filters:\n            compiled_filter = re.compile(filter)\n            self._filters.append(compiled_filter)\n\n    def set_mode(self, mode: RegressionMode) -> None:\n        \"\"\"Set the regression mode.\n\n        See :class:`RegressionMode` for more details on how each mode affects :class:`RegressionManager` behavior.\n        Should be called before :meth:`start_regression` is called.\n\n        Args:\n            mode: The regression mode to set.\n        \"\"\"\n        self._mode = mode\n\n    def register_test(self, test: Test) -> None:\n        \"\"\"Register a test with the :class:`RegressionManager`.\n\n        Should be called before :meth:`start_regression` is called.\n\n        Args:\n            test: The test object to register.\n        \"\"\"\n        self.log.debug(\"Registered test %r\", test.fullname)\n        self._test_queue.append(test)\n\n    @classmethod\n    def setup_pytest_assertion_rewriting(cls) -> None:\n        \"\"\"Configure pytest to rewrite assertions for better failure messages.\n\n        Must be called before all modules containing tests are imported.\n        \"\"\"\n        # Install the assertion rewriting hook, which must be done before we\n        # import the test modules.\n        from _pytest.assertion import install_importhook  # noqa: PLC0415\n        from _pytest.config import Config  # noqa: PLC0415\n\n        python_files = os.getenv(\"COCOTB_REWRITE_ASSERTION_FILES\", \"*.py\").strip()\n        if not python_files:\n            # Even running the hook causes exceptions in some cases, so if the user\n            # selects nothing, don't install the hook at all.\n            return\n\n        pytest_conf = Config.fromdictargs(\n            {}, [\"--capture=no\", \"-o\", f\"python_files={python_files}\"]\n        )\n        install_importhook(pytest_conf)\n\n    def start_regression(self) -> None:\n        \"\"\"Start the regression.\"\"\"\n\n        self.log.info(\"Running tests\")\n\n        # if needed, randomize tests before sorting into stages\n        if self._random_test_order:\n            random.shuffle(self._test_queue)\n\n        # sort tests into stages\n        self._test_queue.sort(key=lambda test: test.stage)\n\n        # mark tests for running and count included tests\n        if self._filters:\n            self.total_tests = 0\n            for test in self._test_queue:\n                test.included = False\n                for filter in self._filters:\n                    if filter.search(test.fullname):\n                        test.included = True\n                        self.total_tests += 1\n        else:\n            self.total_tests = sum(1 for test in self._test_queue if test.included)\n\n        # compute counts\n        self.count = 1\n        if self.total_tests == 0:\n            self.log.warning(\n                \"No tests left after filtering with: %s\",\n                \", \".join(f.pattern for f in self._filters),\n            )\n\n        # start test loop\n        self._regression_start_time = time.time()\n        self._first_test = True\n        self._execute()\n\n    def _execute(self) -> None:\n        \"\"\"Run the main regression loop.\n\n        Used by :meth:`start_regression` and :meth:`_test_complete` to continue to the main test running loop,\n        and by :meth:`_fail_regression` to shutdown the regression when a simulation failure occurs.\n        \"\"\"\n        while self._test_queue:\n            self._test = self._test_queue.pop(0)\n\n            # if the test is not included, record and continue\n            if not self._test.included:\n                self._record_test_excluded()\n                continue\n\n            # if the test is skipped, record and continue\n            if self._test.skip and self._mode != RegressionMode.TESTCASE:\n                self._record_test_skipped(wall_time_s=0, sim_time_ns=0, msg=None)\n                continue\n\n            # if the test should be run, but the simulator has failed, record and continue\n            if self._regression_terminated is not None:\n                self._score_test(\n                    self._regression_terminated,\n                    0,\n                    0,\n                )\n                continue\n\n            # initialize the test, if it fails, record and continue\n            try:\n                self._running_test = self._init_test()\n            except Exception:\n                self._record_test_init_failed()\n                continue\n\n            self._log_test_start()\n\n            if self._first_test:\n                self._first_test = False\n                return self._schedule_next_test()\n            else:\n                self._timer1._register(self._schedule_next_test)\n                return\n\n        return self._tear_down()\n\n    def _init_test(self) -> TestManager:\n        coro = self._test.func(cocotb.top, *self._test.args, **self._test.kwargs)\n        return TestManager(\n            coro,\n            test_complete_cb=self._test_complete,\n            name=self._test.name,\n            timeout=self._test.timeout,\n        )\n\n    def _schedule_next_test(self) -> None:\n        # seed random number generator based on test module, name, and COCOTB_RANDOM_SEED\n        hasher = hashlib.sha1()\n        hasher.update(self._test.fullname.encode())\n        test_seed = self._regression_seed + int(hasher.hexdigest(), 16)\n\n        # seed random number generators with test seed\n        self._random_state = random.getstate()\n        random.seed(test_seed)\n        self._random_x_resolver_state = (\n            cocotb.types._resolve._randomResolveRng.getstate()\n        )\n        cocotb.types._resolve._randomResolveRng.seed(test_seed)\n        cocotb.RANDOM_SEED = test_seed\n\n        self._start_sim_time = get_sim_time(\"ns\")\n        self._start_time = time.time()\n\n        self._running_test.start()\n\n    def _tear_down(self) -> None:\n        \"\"\"Called by :meth:`_execute` when there are no more tests to run to finalize the regression.\"\"\"\n        # prevent re-entering the tear down procedure\n        if not self._tearing_down:\n            self._tearing_down = True\n        else:\n            return\n\n        # Clean up the write_scheduler\n        if cocotb.handle._apply_writes_cb is not None:\n            cocotb.handle._apply_writes_cb.cancel()\n            cocotb.handle._apply_writes_cb = None\n\n        # Write out final log messages\n        self._log_test_summary()\n\n        # Generate output reports\n        self.xunit.write()\n\n        # We shut down here since the shutdown callback isn't called if stop_simulator is called.\n        shutdown._shutdown()\n\n        # Setup simulator finalization\n        cocotb.simulator.stop_simulator()\n\n    def _test_complete(self) -> None:\n        \"\"\"Callback given to the test to be called when the test finished.\"\"\"\n\n        # compute wall time\n        wall_time = time.time() - self._start_time\n        sim_time_ns = get_sim_time(\"ns\") - self._start_sim_time\n\n        # restore random number generators state\n        cocotb.RANDOM_SEED = self._regression_seed\n        random.setstate(self._random_state)\n        cocotb.types._resolve._randomResolveRng.setstate(self._random_x_resolver_state)\n\n        exc: BaseException | None\n        if self._regression_terminated is not None:\n            # When the simulation is failing, we override the typical test results.\n            exc = self._regression_terminated\n        else:\n            exc = self._running_test.exception()\n\n        # Judge and record pass/fail.\n        self._score_test(\n            exc,\n            wall_time,\n            sim_time_ns,\n        )\n\n        # Run next test.\n        return self._execute()\n\n    def _score_test(\n        self,\n        exc: BaseException | None,\n        wall_time_s: float,\n        sim_time_ns: float,\n    ) -> None:\n        test = self._test\n\n        if exc is not None:\n            # These special exceptions take precedence over expect_error and expect_fail.\n            if isinstance(exc, pytest.skip.Exception):\n                # We got a skip exception, so we consider the test skipped.\n                return self._record_test_skipped(\n                    wall_time_s=wall_time_s,\n                    sim_time_ns=sim_time_ns,\n                    msg=exc.msg,\n                )\n            elif isinstance(exc, pytest.xfail.Exception):\n                # We got an xfail exception, so we consider the test xfailed.\n                return self._record_test_xfail(\n                    wall_time_s=wall_time_s,\n                    sim_time_ns=sim_time_ns,\n                    result=None,\n                    msg=exc.msg,\n                )\n            elif isinstance(exc, TestSuccess):\n                return self._record_test_passed(\n                    wall_time_s=wall_time_s,\n                    sim_time_ns=sim_time_ns,\n                )\n            if test.expect_error:\n                expected_error_set = set(test.expect_error)\n\n                # Filter out RaisesExc or RaisesGroup, which need to be handled differently.\n                exception_matcher_excs, matched = handle_pytest_exception_matchers(\n                    exc, expected_error_set\n                )\n                if matched:\n                    # We got an RaisesExc or RaisesGroup that matches the expected exception.\n                    return self._record_test_xfail(\n                        wall_time_s=wall_time_s,\n                        sim_time_ns=sim_time_ns,\n                        result=exc,\n                        msg=\"errored as expected\",\n                    )\n\n                # Use isinstance with the remaining expected exceptions, which should all be exception types.\n                expected_excs_set = cast(\n                    \"set[type[BaseException]]\",\n                    expected_error_set - exception_matcher_excs,\n                )\n\n                if isinstance(exc, tuple(expected_excs_set)):\n                    # Non-exception group error with expected type.\n                    return self._record_test_xfail(\n                        wall_time_s=wall_time_s,\n                        sim_time_ns=sim_time_ns,\n                        result=exc,\n                        msg=\"errored as expected\",\n                    )\n                elif isinstance(exc, _TestFailures):\n                    # We got a failure exception but expected an error.\n                    return self._record_test_failed(\n                        wall_time_s=wall_time_s,\n                        sim_time_ns=sim_time_ns,\n                        result=exc,\n                        msg=\"failed but we expected an error\",\n                    )\n                else:\n                    # Non-exception group error with unexpected type.\n                    return self._record_test_failed(\n                        wall_time_s=wall_time_s,\n                        sim_time_ns=sim_time_ns,\n                        result=exc,\n                        msg=\"errored with unexpected type\",\n                    )\n            elif test.expect_fail:\n                if isinstance(exc, _TestFailures):\n                    # We expected a failure and got one.\n                    return self._record_test_xfail(\n                        wall_time_s=wall_time_s,\n                        sim_time_ns=sim_time_ns,\n                        result=exc,\n                        msg=\"failed as expected\",\n                    )\n                else:\n                    # We expected a failure but got an unexpected exception type.\n                    return self._record_test_failed(\n                        wall_time_s=wall_time_s,\n                        sim_time_ns=sim_time_ns,\n                        result=exc,\n                        msg=\"errored but we expected a failure\",\n                    )\n            else:\n                # We are not expecting an error or failure, but got an exception instead.\n                return self._record_test_failed(\n                    wall_time_s=wall_time_s,\n                    sim_time_ns=sim_time_ns,\n                    result=exc,\n                    msg=None,\n                )\n        elif test.expect_error:\n            # We expected an error but the test passed.\n            return self._record_test_failed(\n                wall_time_s=wall_time_s,\n                sim_time_ns=sim_time_ns,\n                result=None,\n                msg=\"passed but we expected an error\",\n            )\n        elif test.expect_fail:\n            # We expected a failure but the test passed.\n            return self._record_test_failed(\n                wall_time_s=wall_time_s,\n                sim_time_ns=sim_time_ns,\n                result=None,\n                msg=\"passed but we expected a failure\",\n            )\n        else:\n            # We expected a pass and got one.\n            return self._record_test_passed(\n                wall_time_s=wall_time_s, sim_time_ns=sim_time_ns\n            )\n\n    def _get_lineno(self, test: Test) -> int:\n        try:\n            return test.func.__code__.co_firstlineno\n        except AttributeError:\n            try:\n                return inspect.getsourcelines(test.func)[1]\n            except OSError:\n                return 1\n\n    def _log_test_start(self) -> None:\n        \"\"\"Called by :meth:`_execute` to log that a test is starting.\"\"\"\n        hilight_start = \"\" if cocotb_logging.strip_ansi else self.COLOR_TEST\n        hilight_end = \"\" if cocotb_logging.strip_ansi else ANSI.DEFAULT\n        self.log.info(\n            \"%srunning%s %s (%d/%d)%s\",\n            hilight_start,\n            hilight_end,\n            self._test.fullname,\n            self.count,\n            self.total_tests,\n            _format_doc(self._test.doc),\n        )\n\n    def _record_test_excluded(self) -> None:\n        \"\"\"Called by :meth:`_execute` when a test is excluded by filters.\"\"\"\n\n        # write out xunit results\n        lineno = self._get_lineno(self._test)\n        self.xunit.add_testcase(\n            name=self._test.name,\n            classname=self._test.module,\n            file=inspect.getfile(self._test.func),\n            lineno=repr(lineno),\n            time=repr(0),\n            sim_time_ns=repr(0),\n            ratio_time=repr(0),\n        )\n        self.xunit.add_skipped()\n\n        # do not log anything, nor save details for the summary\n\n    def _record_test_skipped(\n        self,\n        wall_time_s: float,\n        sim_time_ns: float,\n        msg: str | None,\n    ) -> None:\n        \"\"\"Called by :meth:`_execute` when a test is skipped.\"\"\"\n\n        # log test results\n        hilight_start = \"\" if cocotb_logging.strip_ansi else self.COLOR_SKIPPED\n        hilight_end = \"\" if cocotb_logging.strip_ansi else ANSI.DEFAULT\n        if msg is not None:\n            msg = f\": {msg}\"\n        else:\n            msg = f\" ({self.count}/{self.total_tests}){_format_doc(self._test.doc)}\"\n        self.log.info(\n            \"%sskipping%s %s%s\",\n            hilight_start,\n            hilight_end,\n            self._test.fullname,\n            msg,\n        )\n\n        # write out xunit results\n        lineno = self._get_lineno(self._test)\n        self.xunit.add_testcase(\n            name=self._test.name,\n            classname=self._test.module,\n            file=inspect.getfile(self._test.func),\n            lineno=repr(lineno),\n            time=repr(0),\n            sim_time_ns=repr(0),\n            ratio_time=repr(0),\n        )\n        self.xunit.add_skipped()\n\n        # save details for summary\n        self._test_results.append(\n            _TestResults(\n                test_fullname=self._test.fullname,\n                outcome=_TestOutcome.SKIP,\n                sim_time_ns=sim_time_ns,\n                wall_time_s=wall_time_s,\n            )\n        )\n\n        # update running passed/failed/skipped counts\n        self.skipped += 1\n        self.count += 1\n\n    def _record_test_init_failed(self) -> None:\n        \"\"\"Called by :meth:`_execute` when a test initialization fails.\"\"\"\n\n        # log test results\n        hilight_start = \"\" if cocotb_logging.strip_ansi else self.COLOR_FAILED\n        hilight_end = \"\" if cocotb_logging.strip_ansi else ANSI.DEFAULT\n        self.log.exception(\n            \"%sFailed to initialize%s %s! (%d/%d)%s\",\n            hilight_start,\n            hilight_end,\n            self._test.fullname,\n            self.count,\n            self.total_tests,\n            _format_doc(self._test.doc),\n        )\n\n        # write out xunit results\n        lineno = self._get_lineno(self._test)\n        self.xunit.add_testcase(\n            name=self._test.name,\n            classname=self._test.module,\n            file=inspect.getfile(self._test.func),\n            lineno=repr(lineno),\n            time=repr(0),\n            sim_time_ns=repr(0),\n            ratio_time=repr(0),\n        )\n        self.xunit.add_failure(msg=\"Test initialization failed\")\n\n        # save details for summary\n        self._test_results.append(\n            _TestResults(\n                test_fullname=self._test.fullname,\n                outcome=_TestOutcome.FAIL,\n                sim_time_ns=0,\n                wall_time_s=0,\n            )\n        )\n\n        # update running passed/failed/skipped counts\n        self.failures += 1\n        self.count += 1\n\n    def _record_test_xfail(\n        self,\n        wall_time_s: float,\n        sim_time_ns: float,\n        result: BaseException | None,\n        msg: str | None,\n    ) -> None:\n        start_hilight = \"\" if cocotb_logging.strip_ansi else self.COLOR_PASSED\n        stop_hilight = \"\" if cocotb_logging.strip_ansi else ANSI.DEFAULT\n        if msg is None:\n            rest = \"\"\n        else:\n            rest = f\": {msg}\"\n        if result is None:\n            result_was = \"\"\n        else:\n            result_was = f\" (result was {type(result).__qualname__})\"\n        self.log.info(\n            \"%s %spassed%s%s%s\",\n            self._test.fullname,\n            start_hilight,\n            stop_hilight,\n            rest,\n            result_was,\n            exc_info=result,\n        )\n\n        # write out xunit results\n        ratio_time = safe_divide(sim_time_ns, wall_time_s)\n        lineno = self._get_lineno(self._test)\n        self.xunit.add_testcase(\n            name=self._test.name,\n            classname=self._test.module,\n            file=inspect.getfile(self._test.func),\n            lineno=repr(lineno),\n            time=repr(wall_time_s),\n            sim_time_ns=repr(sim_time_ns),\n            ratio_time=repr(ratio_time),\n        )\n\n        # update running passed/failed/skipped counts\n        self.passed += 1\n        self.count += 1\n\n        # save details for summary\n        self._test_results.append(\n            _TestResults(\n                test_fullname=self._test.fullname,\n                outcome=_TestOutcome.PASS,\n                sim_time_ns=sim_time_ns,\n                wall_time_s=wall_time_s,\n            )\n        )\n\n    def _record_test_passed(\n        self,\n        wall_time_s: float,\n        sim_time_ns: float,\n    ) -> None:\n        start_hilight = \"\" if cocotb_logging.strip_ansi else self.COLOR_PASSED\n        stop_hilight = \"\" if cocotb_logging.strip_ansi else ANSI.DEFAULT\n        self.log.info(\n            \"%s %spassed%s\",\n            self._test.fullname,\n            start_hilight,\n            stop_hilight,\n        )\n\n        # write out xunit results\n        ratio_time = safe_divide(sim_time_ns, wall_time_s)\n        lineno = self._get_lineno(self._test)\n        self.xunit.add_testcase(\n            name=self._test.name,\n            classname=self._test.module,\n            file=inspect.getfile(self._test.func),\n            lineno=repr(lineno),\n            time=repr(wall_time_s),\n            sim_time_ns=repr(sim_time_ns),\n            ratio_time=repr(ratio_time),\n        )\n\n        # update running passed/failed/skipped counts\n        self.passed += 1\n        self.count += 1\n\n        # save details for summary\n        self._test_results.append(\n            _TestResults(\n                test_fullname=self._test.fullname,\n                outcome=_TestOutcome.PASS,\n                sim_time_ns=sim_time_ns,\n                wall_time_s=wall_time_s,\n            )\n        )\n\n    def _record_test_failed(\n        self,\n        wall_time_s: float,\n        sim_time_ns: float,\n        result: BaseException | None,\n        msg: str | None,\n    ) -> None:\n        start_hilight = \"\" if cocotb_logging.strip_ansi else self.COLOR_FAILED\n        stop_hilight = \"\" if cocotb_logging.strip_ansi else ANSI.DEFAULT\n        if msg is None:\n            rest = \"\"\n        else:\n            rest = f\": {msg}\"\n        self.log.warning(\n            \"%s%s %sfailed%s%s\",\n            stop_hilight,\n            self._test.fullname,\n            start_hilight,\n            stop_hilight,\n            rest,\n            exc_info=result,\n        )\n\n        # write out xunit results\n        ratio_time = safe_divide(sim_time_ns, wall_time_s)\n        lineno = self._get_lineno(self._test)\n        self.xunit.add_testcase(\n            name=self._test.name,\n            classname=self._test.module,\n            file=inspect.getfile(self._test.func),\n            lineno=repr(lineno),\n            time=repr(wall_time_s),\n            sim_time_ns=repr(sim_time_ns),\n            ratio_time=repr(ratio_time),\n        )\n        self.xunit.add_failure(\n            error_type=type(result).__name__, error_msg=bin_xml_escape(result)\n        )\n\n        # update running passed/failed/skipped counts\n        self.failures += 1\n        self.count += 1\n\n        # save details for summary\n        self._test_results.append(\n            _TestResults(\n                test_fullname=self._test.fullname,\n                outcome=_TestOutcome.FAIL,\n                sim_time_ns=sim_time_ns,\n                wall_time_s=wall_time_s,\n            )\n        )\n        if (\n            self._regression_terminated is None\n            and self._max_failures > 0\n            and self.failures >= self._max_failures\n        ):\n            self._regression_terminated = RegressionTerminated(\n                f\"Regression stopped after {self.failures} failures \"\n                f\"(limit={self._max_failures})\"\n            )\n            self.log.warning(self._regression_terminated)\n\n    def _log_test_summary(self) -> None:\n        \"\"\"Called by :meth:`_tear_down` to log the test summary.\"\"\"\n        real_time = time.time() - self._regression_start_time\n        sim_time_ns = get_sim_time(\"ns\")\n        ratio_time = safe_divide(sim_time_ns, real_time)\n\n        if len(self._test_results) == 0:\n            return\n\n        TEST_FIELD = \"TEST\"\n        RESULT_FIELD = \"STATUS\"\n        SIM_FIELD = \"SIM TIME (ns)\"\n        REAL_FIELD = \"REAL TIME (s)\"\n        RATIO_FIELD = \"RATIO (ns/s)\"\n        TOTAL_NAME = f\"TESTS={self.total_tests} PASS={self.passed} FAIL={self.failures} SKIP={self.skipped}\"\n\n        TEST_FIELD_LEN = max(\n            len(TEST_FIELD),\n            len(TOTAL_NAME),\n            len(max([x.test_fullname for x in self._test_results], key=len)),\n        )\n        RESULT_FIELD_LEN = len(RESULT_FIELD)\n        SIM_FIELD_LEN = len(SIM_FIELD)\n        REAL_FIELD_LEN = len(REAL_FIELD)\n        RATIO_FIELD_LEN = len(RATIO_FIELD)\n\n        header_dict = {\n            \"a\": TEST_FIELD,\n            \"b\": RESULT_FIELD,\n            \"c\": SIM_FIELD,\n            \"d\": REAL_FIELD,\n            \"e\": RATIO_FIELD,\n            \"a_len\": TEST_FIELD_LEN,\n            \"b_len\": RESULT_FIELD_LEN,\n            \"c_len\": SIM_FIELD_LEN,\n            \"d_len\": REAL_FIELD_LEN,\n            \"e_len\": RATIO_FIELD_LEN,\n        }\n\n        LINE_LEN = (\n            3\n            + TEST_FIELD_LEN\n            + 2\n            + RESULT_FIELD_LEN\n            + 2\n            + SIM_FIELD_LEN\n            + 2\n            + REAL_FIELD_LEN\n            + 2\n            + RATIO_FIELD_LEN\n            + 3\n        )\n\n        LINE_SEP = \"*\" * LINE_LEN + \"\\n\"\n\n        summary = \"\"\n        summary += LINE_SEP\n        summary += \"** {a:<{a_len}}  {b:^{b_len}}  {c:>{c_len}}  {d:>{d_len}}  {e:>{e_len}} **\\n\".format(\n            **header_dict\n        )\n        summary += LINE_SEP\n\n        test_line = \"** {a:<{a_len}}  {start}{b:^{b_len}}{end}  {c:>{c_len}.2f}   {d:>{d_len}.2f}   {e:>{e_len}}  **\\n\"\n        hilite: str\n        lolite: str\n        for result in self._test_results:\n            if result.outcome == _TestOutcome.SKIP:\n                ratio = \"-.--\"\n                pass_fail_str = \"SKIP\"\n                hilite = self.COLOR_SKIPPED\n                lolite = ANSI.DEFAULT\n            elif result.outcome == _TestOutcome.PASS:\n                ratio = format(result.ratio, \"0.2f\")\n                pass_fail_str = \"PASS\"\n                hilite = self.COLOR_PASSED\n                lolite = ANSI.DEFAULT\n            elif result.outcome == _TestOutcome.FAIL:\n                ratio = format(result.ratio, \"0.2f\")\n                pass_fail_str = \"FAIL\"\n                hilite = self.COLOR_FAILED\n                lolite = ANSI.DEFAULT\n            elif result.outcome == _TestOutcome.XFAIL:\n                ratio = format(result.ratio, \"0.2f\")\n                pass_fail_str = \"XFAIL\"\n                hilite = self.COLOR_XFAILED\n                lolite = ANSI.DEFAULT\n\n            if cocotb_logging.strip_ansi:\n                hilite = \"\"\n                lolite = \"\"\n\n            test_dict = {\n                \"a\": result.test_fullname,\n                \"b\": pass_fail_str,\n                \"c\": result.sim_time_ns,\n                \"d\": result.wall_time_s,\n                \"e\": ratio,\n                \"a_len\": TEST_FIELD_LEN,\n                \"b_len\": RESULT_FIELD_LEN,\n                \"c_len\": SIM_FIELD_LEN - 1,\n                \"d_len\": REAL_FIELD_LEN - 1,\n                \"e_len\": RATIO_FIELD_LEN - 1,\n                \"start\": hilite,\n                \"end\": lolite,\n            }\n\n            summary += test_line.format(**test_dict)\n\n        summary += LINE_SEP\n\n        summary += test_line.format(\n            a=TOTAL_NAME,\n            b=\"\",\n            c=sim_time_ns,\n            d=real_time,\n            e=format(ratio_time, \"0.2f\"),\n            a_len=TEST_FIELD_LEN,\n            b_len=RESULT_FIELD_LEN,\n            c_len=SIM_FIELD_LEN - 1,\n            d_len=REAL_FIELD_LEN - 1,\n            e_len=RATIO_FIELD_LEN - 1,\n            start=\"\",\n            end=\"\",\n        )\n\n        summary += LINE_SEP\n\n        self.log.info(summary)\n\n    def _on_sim_end(self) -> None:\n        \"\"\"Called when the simulator shuts down.\"\"\"\n\n        # We are already shutting down, this is expected.\n        if self._tearing_down:\n            return\n\n        msg = (\n            \"cocotb expected it would shut down the simulation, but the simulation ended prematurely. \"\n            \"This could be due to an assertion failure or a call to an exit routine in the HDL, \"\n            \"or due to the simulator running out of events to process (is your clock running?).\"\n        )\n\n        # We assume if we get here, the simulation ended unexpectedly due to an assertion failure,\n        # or due to an end of events from the simulator.\n        self._regression_terminated = SimFailure(msg)\n        self._running_test.cancel(msg)\n        cocotb._event_loop._inst.run()\n\n    def list_tests(self) -> None:\n        \"\"\"List the tests that would be run, without running them.\"\"\"\n        self.log.info(\n            \"Listing tests that were discovered, in the order they would be run.\"\n        )\n        for test in self._test_queue:\n            print(test.fullname)\n        self.log.info(\"All tests listed. Exiting.\")\n\n\n_manager_inst: RegressionManager\n\"\"\"The global regression manager instance.\"\"\"\n\n\ndef _setup_regression_manager() -> None:\n    \"\"\"Setup the global regression manager instance.\"\"\"\n    global _manager_inst\n    _manager_inst = RegressionManager()\n\n    # discover tests\n    modules: list[str] = _env.as_list(\"COCOTB_TEST_MODULES\")\n    if not modules:\n        raise RuntimeError(\n            \"Environment variable COCOTB_TEST_MODULES, which defines the module(s) to execute, is not defined or empty.\"\n        )\n    _manager_inst.setup_pytest_assertion_rewriting()\n    _manager_inst.discover_tests(*modules)\n\n    # filter tests\n    testcases: list[str] = _env.as_list(\"COCOTB_TESTCASE\")\n    test_filter: str = _env.as_str(\"COCOTB_TEST_FILTER\")\n    if testcases and test_filter:\n        raise RuntimeError(\"Specify only one of COCOTB_TESTCASE or COCOTB_TEST_FILTER\")\n    elif testcases:\n        warnings.warn(\n            \"COCOTB_TESTCASE is deprecated in favor of COCOTB_TEST_FILTER\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        filters: list[str] = [f\"{testcase}$\" for testcase in testcases]\n        _manager_inst.add_filters(*filters)\n        _manager_inst.set_mode(RegressionMode.TESTCASE)\n    elif test_filter:\n        _manager_inst.add_filters(test_filter)\n        _manager_inst.set_mode(RegressionMode.TESTCASE)\n\n\ndef _run_regression() -> None:\n    \"\"\"Setup and run a regression.\"\"\"\n\n    # sys.path normally includes \"\" (the current directory), but does not appear to when Python is embedded.\n    # Add it back because users expect to be able to import files in their test directory.\n    sys.path.insert(0, \"\")\n\n    # From https://www.python.org/dev/peps/pep-0565/#recommended-filter-settings-for-test-runners\n    # If the user doesn't want to see these, they can always change the global\n    # warning settings in their test module.\n    if not sys.warnoptions:\n        warnings.simplefilter(\"default\")\n\n    _setup_regression_manager()\n\n    if _env.as_bool(\"COCOTB_LIST_TESTS\", False):\n        _manager_inst.list_tests()\n    else:\n        _manager_inst.start_regression()\n        shutdown.register(_manager_inst._on_sim_end)\n"
  },
  {
    "path": "src/cocotb/result.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport warnings\n\n\ndef __getattr__(name: str) -> object:\n    if name == \"TestSuccess\":\n        warnings.warn(\n            \"`raise TestSuccess` is deprecated. Use `cocotb.end_test` or `pytest.skip` instead.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        from cocotb._test_manager import TestSuccess  # noqa: PLC0415\n\n        return TestSuccess\n\n    elif name == \"SimFailure\":\n        warnings.warn(\n            \"SimFailure was moved to `cocotb.regression`.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        from cocotb.regression import SimFailure  # noqa: PLC0415\n\n        return SimFailure\n\n    elif name == \"SimTimeoutError\":\n        warnings.warn(\n            \"SimTimeoutError was moved from `cocotb.result` to `cocotb.triggers`.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        from cocotb.triggers import SimTimeoutError  # noqa: PLC0415\n\n        return SimTimeoutError\n\n    raise AttributeError(f\"module {__name__!r} has no attribute {name!r}\")\n"
  },
  {
    "path": "src/cocotb/share/def/.gitignore",
    "content": "# Generated import libraries on Windows\n*.a\n"
  },
  {
    "path": "src/cocotb/share/def/README.md",
    "content": "This directory contains module-definition files (`.def`).\nOn 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.\nThey are not needed on other platforms.\nMore details on `.def` files can be found at http://www.mingw.org/wiki/msvc_and_mingw_dlls\n"
  },
  {
    "path": "src/cocotb/share/def/aldec.def",
    "content": "LIBRARY \"aldecpli.dll\"\nEXPORTS\nvpi_chk_error\nvpi_compare_objects\nvpi_control\nvpi_flush\nvpi_fopen\nvpi_free_object\nvpi_get\nvpi_get_delays\nvpi_get_file\nvpi_get_str\nvpi_get_systf_info\nvpi_get_time\nvpi_get_userdata\nvpi_get_value\nvpi_get_vlog_info\nvpi_handle\nvpi_handle_by_index\nvpi_handle_by_name\nvpi_iterate\nvpi_mcd_close\nvpi_mcd_flush\nvpi_mcd_name\nvpi_mcd_open\nvpi_mcd_printf\nvpi_mcd_vprintf\nvpi_printf\nvpi_put_delays\nvpi_put_userdata\nvpi_put_value\nvpi_register_cb\nvpi_register_systf\nvpi_remove_cb\nvpi_scan\nvpi_sim_control\nvpi_sim_vcontrol\nvpi_vprintf\nvpip_count_drivers\nvpip_format_strength\nvpip_make_systf_system_defined\nvpip_mcd_rawwrite\nvpip_set_return_value\nvhpi_check_error\nvhpi_control\nvhpi_disable_cb\nvhpi_enable_cb\nvhpi_get\nvhpi_get_phys\nvhpi_get_str\nvhpi_get_time\nvhpi_get_value\nvhpi_handle\nvhpi_handle_by_index\nvhpi_handle_by_name\nvhpi_iterator\nvhpi_put_value\nvhpi_register_cb\nvhpi_release_handle\nvhpi_remove_cb\nvhpi_scan\n"
  },
  {
    "path": "src/cocotb/share/def/ghdl.def",
    "content": "LIBRARY \"libghdlvpi.dll\"\nEXPORTS\nvpi_compare_objects\nvpi_control\nvpi_flush\nvpi_fopen\nvpi_free_object\nvpi_get\nvpi_get_delays\nvpi_get_file\nvpi_get_str\nvpi_get_systf_info\nvpi_get_time\nvpi_get_userdata\nvpi_get_value\nvpi_get_vlog_info\nvpi_handle\nvpi_handle_by_index\nvpi_handle_by_name\nvpi_iterate\nvpi_mcd_close\nvpi_mcd_flush\nvpi_mcd_name\nvpi_mcd_printf\nvpi_mcd_vprintf\nvpi_printf\nvpi_put_delays\nvpi_put_userdata\nvpi_put_value\nvpi_register_cb\nvpi_register_systf\nvpi_remove_cb\nvpi_scan\nvpi_sim_control\nvpi_sim_vcontrol\nvpi_mcd_open\nvpi_vprintf\nvpip_count_drivers\nvpip_format_strength\nvpip_make_systf_system_defined\nvpip_mcd_rawwrite\nvpip_set_return_value\nvpi_chk_error\n"
  },
  {
    "path": "src/cocotb/share/def/icarus.def",
    "content": "LIBRARY \"vvp.exe\"\nEXPORTS\nvpi_compare_objects\nvpi_control\nvpi_flush\nvpi_fopen\nvpi_free_object\nvpi_get\nvpi_get_delays\nvpi_get_file\nvpi_get_str\nvpi_get_systf_info\nvpi_get_time\nvpi_get_userdata\nvpi_get_value\nvpi_get_vlog_info\nvpi_handle\nvpi_handle_by_index\nvpi_handle_by_name\nvpi_iterate\nvpi_mcd_close\nvpi_mcd_flush\nvpi_mcd_name\nvpi_mcd_printf\nvpi_mcd_vprintf\nvpi_printf\nvpi_put_delays\nvpi_put_userdata\nvpi_put_value\nvpi_register_cb\nvpi_register_systf\nvpi_remove_cb\nvpi_scan\nvpi_sim_control\nvpi_sim_vcontrol\nvpi_mcd_open\nvpi_vprintf\nvpip_count_drivers\nvpip_format_strength\nvpip_make_systf_system_defined\nvpip_mcd_rawwrite\nvpip_set_return_value\nvpi_chk_error\n"
  },
  {
    "path": "src/cocotb/share/def/modelsim.def",
    "content": "LIBRARY \"mtipli.dll\"\nEXPORTS\nvpi_chk_error\nvpi_compare_objects\nvpi_control\nvpi_flush\nvpi_fopen\nvpi_free_object\nvpi_get\nvpi_get_delays\nvpi_get_file\nvpi_get_str\nvpi_get_systf_info\nvpi_get_time\nvpi_get_userdata\nvpi_get_value\nvpi_get_vlog_info\nvpi_handle\nvpi_handle_by_index\nvpi_handle_by_name\nvpi_iterate\nvpi_mcd_close\nvpi_mcd_flush\nvpi_mcd_name\nvpi_mcd_open\nvpi_mcd_printf\nvpi_mcd_vprintf\nvpi_printf\nvpi_put_delays\nvpi_put_userdata\nvpi_put_value\nvpi_register_cb\nvpi_register_systf\nvpi_remove_cb\nvpi_scan\nvpi_sim_control\nvpi_sim_vcontrol\nvpi_vprintf\nvpip_count_drivers\nvpip_format_strength\nvpip_make_systf_system_defined\nvpip_mcd_rawwrite\nvpip_set_return_value\nacc_fetch_fullname\nacc_fetch_fulltype\nacc_fetch_name\nacc_fetch_type\nacc_fetch_type_str\nmti_AddLoadDoneCB\nmti_AddQuitCB\nmti_Break\nmti_CreateProcess\nmti_CreateProcessWithPriority\nmti_Delta\nmti_Desensitize\nmti_FindRegion\nmti_FindSignal\nmti_FindVar\nmti_FirstLowerRegion\nmti_FirstLowerRegion\nmti_FirstSignal\nmti_FirstVarByRegion\nmti_ForceSignal\nmti_GetArrayElementType\nmti_GetArraySignalValue\nmti_GetArrayVarValue\nmti_GetEnumValues\nmti_GetNumRecordElements\nmti_GetPrimaryName\nmti_GetProductVersion\nmti_GetRegionFullName\nmti_GetRegionName\nmti_GetRegionSourceName\nmti_GetResolutionLimit\nmti_GetSignalName\nmti_GetSignalNameIndirect\nmti_GetSignalSubelements\nmti_GetSignalType\nmti_GetSignalValue\nmti_GetSignalValueIndirect\nmti_GetTopRegion\nmti_GetTypeKind\nmti_GetVarKind\nmti_GetVarName\nmti_GetVarSubelements\nmti_GetVarType\nmti_GetVarValue\nmti_GetVarValueIndirect\nmti_NextRegion\nmti_NextSignal\nmti_NextVar\nmti_Now\nmti_NowUpper\nmti_Quit\nmti_ReleaseSignal\nmti_RemoveLoadDoneCB\nmti_RemoveQuitCB\nmti_ScheduleWakeup\nmti_ScheduleWakeup64\nmti_Sensitize\nmti_SetSignalValue\nmti_SetVarValue\nmti_TickDir\nmti_TickLeft\nmti_TickLength\nmti_TickRight\nmti_VsimFree\nmti_Interp\nmti_Cmd\nTcl_GetStringResult\nTcl_ResetResult\nTcl_GetObjResult\nTcl_ResetResult\nTcl_ListObjGetElements\nTcl_GetStringResult\nTclFreeObj\nTcl_ResetResult\nTcl_ResetResult\nTcl_GetString\nTclFreeObj\nvhpi_check_error\nvhpi_control\nvhpi_disable_cb\nvhpi_enable_cb\nvhpi_get\nvhpi_get_phys\nvhpi_get_str\nvhpi_get_time\nvhpi_get_value\nvhpi_handle\nvhpi_handle_by_index\nvhpi_handle_by_name\nvhpi_iterator\nvhpi_put_value\nvhpi_register_cb\nvhpi_release_handle\nvhpi_remove_cb\nvhpi_scan\n"
  },
  {
    "path": "src/cocotb/share/def/nvcvhpi.def",
    "content": "LIBRARY \"nvc.exe\"\nEXPORTS\nvhpi_handle\nvhpi_register_cb\nvhpi_iterator\nvhpi_get_value\nvhpi_get_str\nvhpi_scan\nvhpi_put_value\nvhpi_remove_cb\nvhpi_check_error\nvhpi_release_handle\nvhpi_get\nvhpi_handle_by_name\nvhpi_handle_by_index\nvhpi_get_phys\nvhpi_get_time\nvhpi_control\n"
  },
  {
    "path": "src/cocotb/share/include/exports.h",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#ifndef COCOTB_EXPORTS_H_\n#define COCOTB_EXPORTS_H_\n\n// Make cocotb work correctly when the default visibility is changed to hidden\n// Changing the default visibility to hidden has the advantage of significantly\n// reducing the code size and load times, as well as letting the optimizer\n// produce better code.\n#if _WIN32\n#define COCOTB_EXPORT __declspec(dllexport)\n#define COCOTB_IMPORT __declspec(dllimport)\n#else\n#define COCOTB_EXPORT __attribute__((visibility(\"default\")))\n#define COCOTB_IMPORT\n#endif\n\n#endif\n"
  },
  {
    "path": "src/cocotb/share/include/gpi.h",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#ifndef COCOTB_GPI_H_\n#define COCOTB_GPI_H_\n\n/** @file gpi.h\n\nGeneric Procedural Interface\n============================\n\nThis header file defines the GPI to interface with any simulator that supports\nVPI, VHPI, or FLI.\n\nImplementations need to implement the underlying functions in `gpi_priv.h`.\nThe functions are essentially a limited subset of VPI/VHPI/FLI.\n\nImplementation-specific notes\n-----------------------------\n\nBy amazing coincidence, VPI and VHPI are strikingly similar which is obviously\nreflected by this header file. Unfortunately, this means that proprietary,\nnon-standard, less featured language interfaces (for example Mentor FLI) may\nhave to resort to some hackery.\n\nBecause of the lack of ability to register a callback on event change using the\nFLI, we have to create a process with the signal on the sensitivity list to\nimitate a callback.\n*/\n\n#include <exports.h>\n#include <stdarg.h>\n#include <stdbool.h>\n#include <stdint.h>\n\n#ifdef GPI_EXPORTS\n#define GPI_EXPORT COCOTB_EXPORT\n#else\n#define GPI_EXPORT COCOTB_IMPORT\n#endif\n\n/*\n * Declare the handle types.\n *\n * We want these handles to be opaque pointers, since their layout is not\n * exposed to C. We do this by using incomplete types. The assumption being\n * made here is that `sizeof(some_cpp_class*) == sizeof(some_c_struct*)`, which\n * is true on all reasonable platforms.\n */\n#ifdef __cplusplus\n/* In C++, we use forward-declarations of the types in gpi_priv.h as our\n * incomplete types, as this avoids the need for any casting in GpiCommon.cpp.\n */\nclass GpiObjHdl;\nclass GpiCbHdl;\nclass GpiIterator;\ntypedef GpiObjHdl *gpi_sim_hdl;\ntypedef GpiCbHdl *gpi_cb_hdl;\ntypedef GpiIterator *gpi_iterator_hdl;\n#else\n/* In C, we declare some incomplete struct types that we never complete.\n * The names of these are irrelevant, but for simplicity they match the C++\n * names.\n */\nstruct GpiObjHdl;\nstruct GpiCbHdl;\nstruct GpiIterator;\n\n/** Handle to simulation object, such as a signal. */\ntypedef struct GpiObjHdl *gpi_sim_hdl;\n\n/** Handle to callback object. */\ntypedef struct GpiCbHdl *gpi_cb_hdl;\n\n/** Handle to iterator object.\n *\n * Used to iterate over child handles of a smulation object.\n */\ntypedef struct GpiIterator *gpi_iterator_hdl;\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** @defgroup SimIntf Simulator Control and Interrogation\n * These functions are for controlling and querying\n * simulator state and information.\n * @{\n */\n\n/** Check if there is a registered GPI implementation.\n *\n * Useful for checking if a simulator is running.\n *\n * @return `1` if there is a registered GPI implementation, `0` otherwise.\n */\nGPI_EXPORT bool gpi_has_registered_impl(void);\n\n/** Stop the simulation after control returns to the GPI. */\nGPI_EXPORT void gpi_finish(void);\n\n/** Get the simulation time as two 32-bit uints.\n *\n * The value is in default simulation time units,\n * which can be retrieved with @ref gpi_get_sim_precision.\n *\n * @param high  Location to return high bits of current simulation time.\n * @param low   Location to return low bits of current simulation time.\n */\nGPI_EXPORT void gpi_get_sim_time(uint32_t *high, uint32_t *low);\n\n/** Get the simulation time precision.\n *\n * @param precision  Location to return time precision.\n *                   The value is scientific notation in terms of seconds.\n *                   So a value of `-9` is nanosecond precision.\n */\nGPI_EXPORT void gpi_get_sim_precision(int32_t *precision);\n\n/** Get the running simulator product information.\n *\n * @return The simulator product string.\n */\nGPI_EXPORT const char *gpi_get_simulator_product(void);\n\n/** Get the running simulator version string.\n *\n * @return The simulator version string.\n */\nGPI_EXPORT const char *gpi_get_simulator_version(void);\n\n/** Return the arguments to the simulator executable call.\n *\n * @param argc  Pointer to store argument count.\n * @param argv  Pointer to store argument values.\n * @return      Zero on success, non-zero on failure.\n */\nGPI_EXPORT int gpi_get_simulator_args(int *argc, char const *const **argv);\n\n/** @} */  // End of group SimIntf\n\n/** @defgroup ObjQuery Simulation Object Query\n * These functions are for getting handles to simulation objects.\n * @{\n */\n\n/** Object discovery method when searching by name. */\ntypedef enum gpi_discovery_e {\n    GPI_AUTO = 0,\n    GPI_NATIVE = 1,\n} gpi_discovery;\n\n/** Get a handle to the root simulation object.\n *\n * @param name  Name of the root object, or `NULL`.\n * @return      Handle to simulation object or `NULL` if not found.\n */\nGPI_EXPORT gpi_sim_hdl gpi_get_root_handle(const char *name);\n\n/** Get a handle to a child simulation object by its name.\n *\n * @param parent            Parent object handle.\n * @param name              Name of the child object.\n *                          This should not be a path,\n *                          but only the name of a direct child object.\n * @param discovery_method  Object discovery method.\n * @return                  Handle to simulation object or `NULL` if not found.\n */\nGPI_EXPORT gpi_sim_hdl gpi_get_handle_by_name(gpi_sim_hdl parent,\n                                              const char *name,\n                                              gpi_discovery discovery_method);\n\n/** Get a handle to a child simulation object by its index.\n *\n * @param parent    Parent indexable object handle.\n * @param index     Index of the child object.\n * @return          Handle to simulation object or `NULL` if not found.\n */\nGPI_EXPORT gpi_sim_hdl gpi_get_handle_by_index(gpi_sim_hdl parent,\n                                               int32_t index);\n\n/** @} */  // End of group ObjQuery\n\n/** @defgroup ObjProps General Object Properties\n * These functions are for getting and setting properties of a simulation\n * object.\n * @{\n */\n\n/** GPI simulation object types. */\n// Note these are strikingly similar to the VPI types...\ntypedef enum gpi_objtype_e {\n    GPI_UNKNOWN = 0,\n    GPI_MEMORY = 1,\n    GPI_MODULE = 2,\n    // GPI_NET = 3,  // Deprecated\n    // GPI_PARAMETER = 4,  // Deprecated\n    // GPI_REGISTER = 5,  // Deprecated\n    GPI_ARRAY = 6,\n    GPI_ENUM = 7,\n    GPI_STRUCTURE = 8,\n    GPI_REAL = 9,\n    GPI_INTEGER = 10,\n    GPI_STRING = 11,\n    GPI_GENARRAY = 12,\n    GPI_PACKAGE = 13,\n    GPI_PACKED_STRUCTURE = 14,\n    GPI_LOGIC = 15,\n    GPI_LOGIC_ARRAY = 16,\n    GPI_PACKED_OBJECT = 17,\n} gpi_objtype;\n\n/** Direction of range constraint of an object. */\ntypedef enum gpi_range_dir_e {\n    GPI_RANGE_DOWN = -1,\n    GPI_RANGE_NO_DIR = 0,\n    GPI_RANGE_UP = 1,\n} gpi_range_dir;\n\n/** @return The @ref gpi_objtype \"type\" of the simulation object. */\nGPI_EXPORT gpi_objtype gpi_get_object_type(gpi_sim_hdl obj_hdl);\n\n/** @return Definition name of the simulation object. */\nGPI_EXPORT const char *gpi_get_definition_name(gpi_sim_hdl obj_hdl);\n\n/** @return Definition file of the simulation object. */\nGPI_EXPORT const char *gpi_get_definition_file(gpi_sim_hdl obj_hdl);\n\n/** @return The number of objects in the collection of the handle. */\nGPI_EXPORT int gpi_get_num_elems(gpi_sim_hdl gpi_sim_hdl);\n\n/** @return The left side of the range constraint. */\nGPI_EXPORT int gpi_get_range_left(gpi_sim_hdl gpi_sim_hdl);\n\n/** @return The right side of the range constraint. */\nGPI_EXPORT int gpi_get_range_right(gpi_sim_hdl gpi_sim_hdl);\n\n/** @return The direction of the range constraint:\n *         `+1` for ascending, `-1` for descending, `0` for undefined.\n */\nGPI_EXPORT gpi_range_dir gpi_get_range_dir(gpi_sim_hdl gpi_sim_hdl);\n\n/** Determine whether an object value is constant (parameters / generics etc).\n *\n * @return `1` if the object value is constant, `0` otherwise.\n */\nGPI_EXPORT int gpi_is_constant(gpi_sim_hdl obj_hdl);\n\n/** Determine whether an object is indexable.\n *\n * @return `1` if the object value is indexable, `0` otherwise.\n */\nGPI_EXPORT int gpi_is_indexable(gpi_sim_hdl obj_hdl);\n\n/** Determine whether integer object is signed.\n *\n * @return `1` if the integer object is signed, `0` if unsigned, `-1` if unknown\n * or not applicable.\n */\nGPI_EXPORT int gpi_is_signed(gpi_sim_hdl obj_hdl);\n\n/** @} */  // End of group ObjProps\n\n/** @defgroup SigProps Signal Object Properties\n * These functions are for getting and setting properties of a signal object.\n * @{\n */\n\n/** Action to use when setting object value. */\ntypedef enum gpi_set_action_e {\n    GPI_DEPOSIT = 0,\n    GPI_FORCE = 1,\n    GPI_RELEASE = 2,\n    GPI_NO_DELAY = 3,\n} gpi_set_action;\n\n// Getting properties\n\n/** Get signal object value as a binary string.\n * @param sig_hdl   Signal object handle.\n * @return          Object value.\n */\nGPI_EXPORT const char *gpi_get_signal_value_binstr(gpi_sim_hdl sig_hdl);\n\n/** Get signal object value as a byte array.\n * @param sig_hdl   Signal object handle.\n * @return          Object value. Null-terminated byte array.\n */\nGPI_EXPORT const char *gpi_get_signal_value_str(gpi_sim_hdl sig_hdl);\n\n/** Get signal object value as a real.\n * @param sig_hdl   Signal object handle.\n * @return          Object value.\n */\nGPI_EXPORT double gpi_get_signal_value_real(gpi_sim_hdl sig_hdl);\n\n/** Get signal object value as a long.\n * @param sig_hdl   Signal object handle.\n * @return          Object value.\n */\nGPI_EXPORT long gpi_get_signal_value_long(gpi_sim_hdl sig_hdl);\n\n/** Get signal object name.\n * @param sig_hdl   Signal object handle.\n * @return          Object name.\n */\nGPI_EXPORT const char *gpi_get_signal_name_str(gpi_sim_hdl sig_hdl);\n\n/** Get signal object type as a string.\n * @param sig_hdl   Signal object handle.\n * @return          Object type as a string.\n */\nGPI_EXPORT const char *gpi_get_signal_type_str(gpi_sim_hdl sig_hdl);\n\n// Setting properties\n\n/** Set signal object value with a real.\n * @param sig_hdl   Signal object handle.\n * @param value     Object value.\n * @param action    Action to use.\n */\nGPI_EXPORT void gpi_set_signal_value_real(gpi_sim_hdl sig_hdl, double value,\n                                          gpi_set_action action);\n\n/** Set signal object value with an int.\n * @param sig_hdl   Signal object handle.\n * @param value     Object value.\n * @param action    Action to use.\n */\nGPI_EXPORT void gpi_set_signal_value_int(gpi_sim_hdl sig_hdl, int32_t value,\n                                         gpi_set_action action);\n\n/** Set signal object value with a binary string.\n * @param sig_hdl   Signal object handle.\n * @param str       Object value. Null-terminated string of binary characters\n *                  in [`1`, `0`, `x`, `z`].\n * @param action    Action to use.\n */\nGPI_EXPORT void gpi_set_signal_value_binstr(gpi_sim_hdl sig_hdl,\n                                            const char *str,\n                                            gpi_set_action action);\n\n/** Set signal object value with a byte array.\n * @param sig_hdl   Signal object handle.\n * @param str       Object value. Null-terminated byte array.\n * @param action    Action to use.\n */\nGPI_EXPORT void gpi_set_signal_value_str(gpi_sim_hdl sig_hdl, const char *str,\n                                         gpi_set_action action);\n\n/** @} */  // End of group SigProps\n\n/** @defgroup HandleIteration Simulation Object Iteration\n * These functions are for iterating over simulation object handles\n * to discover child objects.\n * @{\n */\n\n/** Types of child objects to search for when iterating. */\ntypedef enum gpi_iterator_sel_e {\n    GPI_OBJECTS = 1,\n    GPI_DRIVERS = 2,\n    GPI_LOADS = 3,\n    GPI_PACKAGE_SCOPES = 4,\n} gpi_iterator_sel;\n\n/** Start iteration on a simulation object.\n *\n * Unlike `vpi_iterate()` the iterator handle may only be `NULL` if the `type`\n * is not supported. If no objects of the requested type are found, an empty\n * iterator is returned.\n * @param base  Simulation object to iterate over.\n * @param type  Iteration type.\n * @return      An iterator handle which can then be used with @ref gpi_next.\n */\nGPI_EXPORT gpi_iterator_hdl gpi_iterate(gpi_sim_hdl base,\n                                        gpi_iterator_sel type);\n\n/** Get next object in iteration.\n *\n * @param iterator  Iterator handle.\n * @return          Object handle, or `NULL` when there are no more objects.\n */\nGPI_EXPORT gpi_sim_hdl gpi_next(gpi_iterator_hdl iterator);\n\n/** @} */  // End of group HandleIteration\n\n/** @defgroup SimCallbacks Simulation Callbacks\n * These functions are for registering and controlling callbacks.\n * @{\n */\n\n/** Type of value change to match when registering for callback. */\ntypedef enum gpi_edge_e {\n    GPI_VALUE_CHANGE,\n    GPI_RISING,\n    GPI_FALLING,\n} gpi_edge;\n\n/** Register a timed callback.\n *\n * @param gpi_function  Callback function pointer.\n * @param gpi_cb_data   Pointer to user data to be passed to callback function.\n * @param time          Time delay in simulation time units.\n * @return              Handle to callback object.\n */\nGPI_EXPORT gpi_cb_hdl gpi_register_timed_callback(int (*gpi_function)(void *),\n                                                  void *gpi_cb_data,\n                                                  uint64_t time);\n\n/** Register a value change callback.\n *\n * @param gpi_function  Callback function pointer.\n * @param gpi_cb_data   Pointer to user data to be passed to callback function.\n * @param sig_hdl       Simulation object to monitor for value change.\n * @param edge          Type of value change to monitor for.\n * @return              Handle to callback object.\n */\nGPI_EXPORT gpi_cb_hdl gpi_register_value_change_callback(\n    int (*gpi_function)(void *), void *gpi_cb_data, gpi_sim_hdl sig_hdl,\n    gpi_edge edge);\n\n/** Register a readonly simulation phase callback.\n *\n * Callback will be called when simulation next enters the readonly phase.\n * @param gpi_function  Callback function pointer.\n * @param gpi_cb_data   Pointer to user data to be passed to callback function.\n * @return              Handle to callback object.\n */\nGPI_EXPORT gpi_cb_hdl\ngpi_register_readonly_callback(int (*gpi_function)(void *), void *gpi_cb_data);\n\n/** Register a next timestep simulation phase callback.\n *\n * Callback will be called when simulation next enters the next timestep.\n * @param gpi_function  Callback function pointer.\n * @param gpi_cb_data   Pointer to user data to be passed to callback function.\n * @return              Handle to callback object.\n */\nGPI_EXPORT gpi_cb_hdl\ngpi_register_nexttime_callback(int (*gpi_function)(void *), void *gpi_cb_data);\n\n/** Register a readwrite simulation phase callback.\n *\n * Callback will be called when simulation next enters the readwrite phase.\n * @param gpi_function  Callback function pointer.\n * @param gpi_cb_data   Pointer to user data to be passed to callback function.\n * @return              Handle to callback object.\n */\nGPI_EXPORT gpi_cb_hdl\ngpi_register_readwrite_callback(int (*gpi_function)(void *), void *gpi_cb_data);\n\n/** Register a callback to run at the start of simulation time.\n *\n * @param cb        Callback function pointer.\n * @param cb_data   Pointer to user data to be passed to callback function.\n * @return          Zero on success, non-zero on failure.\n */\nGPI_EXPORT int gpi_register_start_of_sim_time_callback(int (*cb)(void *),\n                                                       void *cb_data);\n\n/** Register a callback to run at the end of simulation time.\n *\n * @param cb        Callback function pointer.\n * @param cb_data   Pointer to user data to be passed to callback function.\n * @return          Zero on success, non-zero on failure.\n */\nGPI_EXPORT int gpi_register_end_of_sim_time_callback(void (*cb)(void *),\n                                                     void *cb_data);\n\n/** Type of a GPI finalization callback.\n *\n * @param cb_data   Pointer to user data to be passed to callback function.\n */\ntypedef void (*gpi_finalize_callback)(void *cb_data);\n\n/** Register a callback to run just before the GPI terminates.\n *\n * @param cb        Callback function pointer.\n * @param cb_data   Pointer to user data to be passed to callback function.\n * @return          Handle to callback object.\n */\nGPI_EXPORT int gpi_register_finalize_callback(gpi_finalize_callback cb,\n                                              void *cb_data);\n\n/** Remove callback.\n *\n * The callback will not fire after this function is called.\n * The handle is no longer valid if this function succeeds.\n *\n * @param cb_hdl    The handle to the callback to remove.\n * @return          `0` on successful removal, `1` otherwise.\n */\nGPI_EXPORT int gpi_remove_cb(gpi_cb_hdl cb_hdl);\n\n/** Retrieve user callback information from callback handle.\n *\n * This function cannot fail.\n *\n * @param cb_hdl    The handle to the callback.\n * @param cb_func   Where the user callback function should be placed.\n * @param cb_data   Where the user callback function data should be placed.\n */\nGPI_EXPORT void gpi_get_cb_info(gpi_cb_hdl cb_hdl, int (**cb_func)(void *),\n                                void **cb_data);\n\n/** @} */  // End of group SimCallbacks\n\n/** @defgroup Logging GPI Logging Dependency Injection\n * These functions are for registering logging implementations into the GPI for\n * its logging.\n * @{\n */\n\n/** Named logging level\n *\n *  The native logger only logs level names at these log level values.\n *  They were specifically chosen to align with the default level values in the\n *  Python logging module. Implementers of custom loggers should emit human\n *  readable level names for these value, but may support other values.\n */\nenum gpi_log_level {\n    GPI_NOTSET = 0,  ///< Lets the parent logger in the hierarchy decide the\n                     ///< effective log level. By default this behaves like\n                     ///< `INFO`.\n    GPI_TRACE = 5,   ///< Prints `TRACE` by default. Information about execution\n                     ///< of simulator callbacks and Python/simulator contexts.\n    GPI_DEBUG = 10,  ///< Prints `DEBUG` by default. Verbose information, useful\n                     ///< for debugging.\n    GPI_INFO = 20,   ///< Prints `INFO` by default. Information about major\n                     ///< events in the current program.\n    GPI_WARNING = 30,  ///< Prints `WARN` by default. Encountered a recoverable\n                       ///< bug, or information about surprising behavior.\n    GPI_ERROR = 40,    ///< Prints `ERROR` by default. An unrecoverable error.\n    GPI_CRITICAL = 50  ///< Prints `CRITICAL` by default. An unrecoverable\n                       ///< error, to be followed by immediate simulator\n                       ///< shutdown.\n};\n\n/** Type of a logger handler function.\n * @param userdata  Private implementation data registered with this function\n * @param name      Name of the logger\n * @param level     Level at which to log the message\n * @param pathname  Name of the file where the call site is located\n * @param funcname  Name of the function where the call site is located\n * @param lineno    Line number of the call site\n * @param msg       The message to log, uses C-sprintf-style format specifier\n * @param args      Additional arguments; formatted and inserted in message\n *                  according to format specifier in msg argument\n */\ntypedef void (*gpi_log_handler_ftype)(void *userdata, const char *name,\n                                      enum gpi_log_level level,\n                                      const char *pathname,\n                                      const char *funcname, long lineno,\n                                      const char *msg, va_list args);\n\n/** Retrieve the current log handler.\n * @param handler   Location to return current log handler function.\n * @param userdata  Location to return log handler userdata.\n */\nGPI_EXPORT void gpi_get_log_handler(gpi_log_handler_ftype *handler,\n                                    void **userdata);\n\n/** Set custom log handler\n * @param handler   Logger handler function.\n * @param userdata  Data passed to the above functions.\n */\nGPI_EXPORT void gpi_set_log_handler(gpi_log_handler_ftype handler,\n                                    void *userdata);\n\n/** Set minimum logging level of the native logger.\n *\n * If a logging request occurs where the logging level is lower than the level\n * set by this function, it is not logged. Only affects the native logger.\n * @param level     Logging level\n * @return          Previous logging level\n */\nGPI_EXPORT int gpi_native_logger_set_level(enum gpi_log_level level);\n\n/** @} */  // End of group Logging\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* COCOTB_GPI_H_ */\n"
  },
  {
    "path": "src/cocotb/share/include/vhpi_user_ext.h",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n/* extensions to vhpi_user.h */\n\n#ifndef VHPI_USER_EXT_H\n#define VHPI_USER_EXT_H\n\n#ifdef  __cplusplus\nextern \"C\" {\n#endif\n\n/* arguments for vhpiStop or vhpiFinish */\ntypedef enum\n{\n  vhpiDiagNone          = 0, /* prints nothing */\n  vhpiDiagTimeLoc       = 1, /* prints simulation time and location */\n  vhpiDiagTimeLocCPUMem = 2  /* prints simulation time, location and statistics about CPU and memory usage */\n} vhpiDiagT;\n\n#ifdef  __cplusplus\n}\n#endif\n\n#endif /* VHPI_USER_EXT_H */\n"
  },
  {
    "path": "src/cocotb/share/include/vpi_user_ext.h",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2019 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n/* extensions to vpi_user.h */\n\n#ifndef VPI_USER_EXT_H\n#define VPI_USER_EXT_H\n\n#ifdef  __cplusplus\nextern \"C\" {\n#endif\n\n/* used by Cadence Xcelium for Verilog-AMS */\n#define vpiInterconnectNet   533\n#define vpiInterconnectArray 534\n\n/* arguments for vpiStop or vpiFinish */\n#define vpiDiagNone               0  /* prints nothing */\n#define vpiDiagTimeLoc            1  /* prints simulation time and location */\n#define vpiDiagTimeLocCPUMem      2  /* prints simulation time, location and\n                                        statistics about CPU and memory usage */\n\n#ifdef  __cplusplus\n}\n#endif\n\n#endif /* VPI_USER_EXT_H */\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/GpiCbHdl.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <gpi.h>\n\n#include \"./gpi_priv.hpp\"\n\nconst char *GpiObjHdl::get_name_str() { return m_name.c_str(); }\n\nconst char *GpiObjHdl::get_fullname_str() { return m_fullname.c_str(); }\n\nconst std::string &GpiObjHdl::get_fullname() { return m_fullname; }\n\nconst char *GpiObjHdl::get_type_str() {\n#define CASE_OPTION(_X) \\\n    case _X:            \\\n        ret = #_X;      \\\n        break\n\n    const char *ret;\n\n    switch (m_type) {\n        CASE_OPTION(GPI_UNKNOWN);\n        CASE_OPTION(GPI_MEMORY);\n        CASE_OPTION(GPI_MODULE);\n        CASE_OPTION(GPI_ARRAY);\n        CASE_OPTION(GPI_ENUM);\n        CASE_OPTION(GPI_STRUCTURE);\n        CASE_OPTION(GPI_REAL);\n        CASE_OPTION(GPI_INTEGER);\n        CASE_OPTION(GPI_STRING);\n        CASE_OPTION(GPI_GENARRAY);\n        CASE_OPTION(GPI_PACKAGE);\n        CASE_OPTION(GPI_LOGIC);\n        CASE_OPTION(GPI_LOGIC_ARRAY);\n        CASE_OPTION(GPI_PACKED_OBJECT);\n        default:\n            ret = \"unknown\";\n    }\n\n    return ret;\n}\n\nconst std::string &GpiObjHdl::get_name() { return m_name; }\n\n/* Genertic base clss implementations */\nbool GpiHdl::is_this_impl(GpiImplInterface *impl) {\n    return impl == this->m_impl;\n}\n\nint GpiObjHdl::initialise(const std::string &name, const std::string &fq_name) {\n    m_name = name;\n    m_fullname = fq_name;\n    return 0;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/GpiCommon.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <gpi.h>\n#include <sys/types.h>\n\n#include <algorithm>\n#include <map>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"./gpi_priv.hpp\"\n#include \"./logging.hpp\"\n\nusing namespace std;\n\nstatic vector<GpiImplInterface *> registered_impls;\nstatic vector<std::pair<int (*)(void *), void *>> start_of_sim_time_cbs;\nstatic vector<std::pair<void (*)(void *), void *>> end_of_sim_time_cbs;\nstatic vector<std::pair<void (*)(void *), void *>> finalize_cbs;\n\nclass GpiHandleStore {\n  public:\n    GpiObjHdl *check_and_store(GpiObjHdl *hdl) {\n        std::map<std::string, GpiObjHdl *>::iterator it;\n\n        const std::string &name = hdl->get_fullname();\n\n        LOG_DEBUG(\"Checking %s exists\", name.c_str());\n\n        it = handle_map.find(name);\n        if (it == handle_map.end()) {\n            handle_map[name] = hdl;\n            return hdl;\n        } else {\n            LOG_DEBUG(\"Found duplicate %s\", name.c_str());\n\n            delete hdl;\n            return it->second;\n        }\n    }\n\n    uint64_t handle_count() { return handle_map.size(); }\n\n    void clear() {\n        std::map<std::string, GpiObjHdl *>::iterator it;\n\n        // Delete the object handles before clearing the map\n        for (it = handle_map.begin(); it != handle_map.end(); it++) {\n            delete (it->second);\n        }\n        handle_map.clear();\n    }\n\n  private:\n    std::map<std::string, GpiObjHdl *> handle_map;\n};\n\nstatic GpiHandleStore unique_handles;\n\n#define CHECK_AND_STORE(_x) unique_handles.check_and_store(_x)\n#define CLEAR_STORE() unique_handles.clear()\n\nstatic bool gpi_finalizing = false;\n\nstatic size_t gpi_print_registered_impl() {\n    vector<GpiImplInterface *>::iterator iter;\n    for (iter = registered_impls.begin(); iter != registered_impls.end();\n         iter++) {\n        LOG_INFO(\"GPI: %s support registered\", (*iter)->get_name_c());\n    }\n    return registered_impls.size();\n}\n\nint gpi_register_impl(GpiImplInterface *func_tbl) {\n    vector<GpiImplInterface *>::iterator iter;\n    for (iter = registered_impls.begin(); iter != registered_impls.end();\n         iter++) {\n        if ((*iter)->get_name_s() == func_tbl->get_name_s()) {\n            LOG_WARN(\"GPI: %s support already registered, check GPI_EXTRA\",\n                     func_tbl->get_name_c());\n            return -1;\n        }\n    }\n    registered_impls.push_back(func_tbl);\n    return 0;\n}\n\nbool gpi_has_registered_impl() { return registered_impls.size() > 0; }\n\nvoid gpi_start_of_sim_time() {\n    for (auto &cb_info : start_of_sim_time_cbs) {\n        // start_of_sime_time should never fail, this should be moved to\n        // gpi_load_users, as should the (argc,argv)\n        LOG_TRACE(\"[ GPI Start Sim ] => User Start callback\");\n        int error = cb_info.first(cb_info.second);\n        LOG_TRACE(\"User Start callback => [ GPI Start Sim ]\");\n        if (error) {\n            gpi_end_of_sim_time();\n        }\n    }\n}\n\nvoid gpi_end_of_sim_time() {\n    for (auto &cb_info : end_of_sim_time_cbs) {\n        LOG_TRACE(\"[ GPI End Sim ] => User End callback\");\n        cb_info.first(cb_info.second);\n        LOG_TRACE(\"User End callback => [ GPI End Sim ]\");\n    }\n    // always request simulation termination at end_of_sim_time\n    gpi_finish();\n}\n\nvoid gpi_finish() {\n    if (!gpi_finalizing) {\n        registered_impls[0]->sim_end();\n        gpi_finalizing = true;\n    }\n}\n\nvoid gpi_finalize(void) {\n    CLEAR_STORE();\n    for (auto it = finalize_cbs.rbegin(); it != finalize_cbs.rend(); it++) {\n        LOG_TRACE(\"[ GPI Finalize ] => User Finalize callback\");\n        it->first(it->second);\n        LOG_TRACE(\"User Finalize callback => [ GPI Finalize ]\");\n    }\n}\n\nvoid gpi_check_cleanup(void) {\n    if (gpi_finalizing) {\n        gpi_finalize();\n    }\n}\n\nbool gpi_is_finalizing(void) { return gpi_finalizing; }\n\nstatic void gpi_load_libs(std::vector<std::string> to_load) {\n    std::vector<std::string>::iterator iter;\n\n    for (iter = to_load.begin(); iter != to_load.end(); iter++) {\n        std::string arg = *iter;\n\n        auto const idx = arg.rfind(\n            ':');  // find from right since path could contain colons (Windows)\n        if (idx == std::string::npos) {\n            // no colon in the string\n            printf(\"cocotb: Error parsing GPI_EXTRA %s\\n\", arg.c_str());\n            exit(1);\n        }\n\n        std::string const lib_name = arg.substr(0, idx);\n        std::string const func_name = arg.substr(idx + 1, std::string::npos);\n\n        void *lib_handle = utils_dyn_open(lib_name.c_str());\n        if (!lib_handle) {\n            printf(\"cocotb: Error loading shared library %s\\n\",\n                   lib_name.c_str());\n            exit(1);\n        }\n\n        void *entry_point = utils_dyn_sym(lib_handle, func_name.c_str());\n        if (!entry_point) {\n            char const *fmt =\n                \"cocotb: Unable to find entry point %s for shared library \"\n                \"%s\\n%s\";\n            char const *msg =\n                \"        Perhaps you meant to use `,` instead of `:` to \"\n                \"separate library names, as this changed in cocotb 1.4?\\n\";\n            printf(fmt, func_name.c_str(), lib_name.c_str(), msg);\n            exit(1);\n        }\n\n        layer_entry_func new_lib_entry = (layer_entry_func)entry_point;\n        LOG_TRACE(\"[ GPI Init ] => Impl Init (%s)\", arg.c_str());\n        new_lib_entry();\n        LOG_TRACE(\"Impl Init => [ GPI Init ]\");\n    }\n}\n\nstatic int gpi_load_users() {\n    auto users = getenv(\"GPI_USERS\");\n    if (!users) {\n        LOG_ERROR(\"No GPI_USERS specified, exiting...\");\n        return -1;\n    }\n    // I would have loved to use istringstream and getline, but it causes a\n    // compilation issue when compiling with newer GCCs against C++11.\n    std::string users_str = users;\n    std::string::size_type start_idx = 0;\n    bool done = false;\n    while (!done) {\n        auto next_delim = users_str.find(';', start_idx);\n        if (next_delim == std::string::npos) {\n            done = true;\n            next_delim = users_str.length();\n        }\n        auto user = users_str.substr(start_idx, next_delim - start_idx);\n        start_idx = next_delim + 1;\n\n        auto split_idx = user.rfind(',');\n\n        std::string lib_name;\n        std::string func_name;\n        if (split_idx == std::string::npos) {\n            lib_name = std::move(user);\n        } else {\n            lib_name = user.substr(0, split_idx);\n            func_name = user.substr(split_idx + 1, std::string::npos);\n        }\n\n        void *lib_handle = utils_dyn_open(lib_name.c_str());\n        if (!lib_handle) {\n            LOG_ERROR(\"Error loading library '%s'\", lib_name.c_str());\n            gpi_finish();\n            return -1;\n        }\n\n        if (split_idx != std::string::npos) {\n            void *func_handle = utils_dyn_sym(lib_handle, func_name.c_str());\n            if (!func_handle) {\n                LOG_ERROR(\n                    \"Error getting entry func '%s' from loaded library '%s'\",\n                    func_name.c_str(), lib_name.c_str());\n                gpi_finish();\n                return -1;\n            }\n\n            LOG_INFO(\"Running entry func '%s' from loaded library '%s'\",\n                     func_name.c_str(), lib_name.c_str());\n\n            auto entry_func = (void (*)(void))func_handle;\n            LOG_TRACE(\"[ GPI Init ] => User Init (%s:%s)\", lib_name.c_str(),\n                      func_name.c_str());\n            entry_func();\n            LOG_TRACE(\"User Init => [ GPI Init ]\");\n        } else {\n            LOG_INFO(\"Loaded entry library: '%s'\", lib_name.c_str());\n        }\n    }\n\n    return 0;\n}\n\nvoid gpi_entry_point() {\n    LOG_TRACE(\"=> [ GPI Init ]\");\n\n    /* Lets look at what other libs we were asked to load too */\n    char *lib_env = getenv(\"GPI_EXTRA\");\n\n    if (lib_env) {\n        std::string lib_list = lib_env;\n        std::string const delim = \",\";\n        std::vector<std::string> to_load;\n\n        size_t e_pos = 0;\n        while (std::string::npos != (e_pos = lib_list.find(delim))) {\n            std::string lib = lib_list.substr(0, e_pos);\n            lib_list.erase(0, e_pos + delim.length());\n\n            to_load.push_back(lib);\n        }\n        if (lib_list.length()) {\n            to_load.push_back(lib_list);\n        }\n\n        gpi_load_libs(to_load);\n    }\n\n    // Load users\n    if (gpi_load_users()) {\n        return;\n    }\n\n    gpi_print_registered_impl();\n\n    LOG_TRACE(\"[ GPI Init ] =>\");\n}\n\nGPI_EXPORT void gpi_init_logging_and_debug() {\n    char *debug_env = getenv(\"GPI_DEBUG\");\n    if (debug_env) {\n        std::string gpi_debug = debug_env;\n        // If it's explicitly set to 0, don't enable\n        if (gpi_debug != \"0\") {\n            gpi_debug_enabled = 1;\n        }\n    }\n\n    const char *log_level = getenv(\"GPI_LOG_LEVEL\");\n    if (log_level) {\n        static const std::map<std::string, enum gpi_log_level>\n            log_level_str_table = {\n                {\"CRITICAL\", GPI_CRITICAL}, {\"ERROR\", GPI_ERROR},\n                {\"WARNING\", GPI_WARNING},   {\"INFO\", GPI_INFO},\n                {\"DEBUG\", GPI_DEBUG},       {\"TRACE\", GPI_TRACE}};\n        auto it = log_level_str_table.find(log_level);\n        if (it != log_level_str_table.end()) {\n            gpi_native_logger_set_level(it->second);\n        } else {\n            // LCOV_EXCL_START\n            LOG_ERROR(\"Invalid log level: %s\", log_level);\n            // LCOV_EXCL_STOP\n        }\n    }\n}\n\nvoid gpi_get_sim_time(uint32_t *high, uint32_t *low) {\n    registered_impls[0]->get_sim_time(high, low);\n}\n\nvoid gpi_get_sim_precision(int32_t *precision) {\n    /* We clamp to sensible values here, 1e-15 min and 1e3 max */\n    int32_t val;\n    registered_impls[0]->get_sim_precision(&val);\n    if (val > 2) val = 2;\n\n    if (val < -15) val = -15;\n\n    *precision = val;\n}\n\nconst char *gpi_get_simulator_product() {\n    return registered_impls[0]->get_simulator_product();\n}\n\nconst char *gpi_get_simulator_version() {\n    return registered_impls[0]->get_simulator_version();\n}\n\ngpi_sim_hdl gpi_get_root_handle(const char *name) {\n    /* May need to look over all the implementations that are registered\n       to find this handle */\n    vector<GpiImplInterface *>::iterator iter;\n\n    GpiObjHdl *hdl = NULL;\n\n    LOG_DEBUG(\"Looking for root handle '%s' over %d implementations\", name,\n              registered_impls.size());\n\n    for (iter = registered_impls.begin(); iter != registered_impls.end();\n         iter++) {\n        if ((hdl = (*iter)->get_root_handle(name))) {\n            LOG_DEBUG(\"Got a Root handle (%s) back from %s\",\n                      hdl->get_name_str(), (*iter)->get_name_c());\n            break;\n        }\n    }\n\n    if (hdl)\n        return CHECK_AND_STORE(hdl);\n    else {\n        LOG_ERROR(\"No root handle found\");\n        return hdl;\n    }\n}\n\nstatic GpiObjHdl *gpi_get_child_by_name(GpiObjHdl *parent,\n                                        const std::string &name,\n                                        GpiImplInterface *skip_impl) {\n    LOG_DEBUG(\"Searching for %s\", name.c_str());\n\n    // check parent impl *first* if it's not skipped\n    if (!skip_impl || (skip_impl != parent->m_impl)) {\n        auto hdl = parent->m_impl->get_child_by_name(name, parent);\n        if (hdl) {\n            return CHECK_AND_STORE(hdl);\n        }\n    }\n\n    // iterate over all registered impls to see if we can get the signal\n    for (auto iter = registered_impls.begin(); iter != registered_impls.end();\n         iter++) {\n        // check if impl is skipped\n        if (skip_impl && (skip_impl == (*iter))) {\n            LOG_DEBUG(\"Skipping %s implementation\", (*iter)->get_name_c());\n            continue;\n        }\n\n        // already checked parent implementation\n        if ((*iter) == parent->m_impl) {\n            LOG_DEBUG(\"Already checked %s implementation\",\n                      (*iter)->get_name_c());\n            continue;\n        }\n\n        LOG_DEBUG(\"Checking if %s is native through implementation %s\",\n                  name.c_str(), (*iter)->get_name_c());\n\n        /* If the current interface is not the same as the one that we\n           are going to query then append the name we are looking for to\n           the parent, such as <parent>.name. This is so that its entity can\n           be seen discovered even if the parents implementation is not the same\n           as the one that we are querying through */\n\n        auto hdl = (*iter)->get_child_by_name(name, parent);\n        if (hdl) {\n            LOG_DEBUG(\"Found %s via %s\", name.c_str(), (*iter)->get_name_c());\n            return CHECK_AND_STORE(hdl);\n        }\n    }\n\n    return NULL;\n}\n\nstatic GpiObjHdl *gpi_get_child_from_handle(GpiObjHdl *parent, void *raw_hdl,\n                                            GpiImplInterface *skip_impl) {\n    vector<GpiImplInterface *>::iterator iter;\n\n    GpiObjHdl *hdl = NULL;\n\n    for (iter = registered_impls.begin(); iter != registered_impls.end();\n         iter++) {\n        if (skip_impl && (skip_impl == (*iter))) {\n            LOG_DEBUG(\"Skipping %s implementation\", (*iter)->get_name_c());\n            continue;\n        }\n\n        if ((hdl = (*iter)->get_child_from_handle(raw_hdl, parent))) {\n            LOG_DEBUG(\"Found %s via %s\", hdl->get_name_str(),\n                      (*iter)->get_name_c());\n            break;\n        }\n    }\n\n    if (hdl)\n        return CHECK_AND_STORE(hdl);\n    else {\n        LOG_WARN(\n            \"Failed to convert a raw handle to valid object via any registered \"\n            \"implementation\");\n        return hdl;\n    }\n}\n\ngpi_sim_hdl gpi_get_handle_by_name(gpi_sim_hdl base, const char *name,\n                                   gpi_discovery discovery_method = GPI_AUTO) {\n    std::string s_name = name;\n    GpiObjHdl *hdl = NULL;\n    if (discovery_method == GPI_AUTO) {\n        hdl = gpi_get_child_by_name(base, s_name, NULL);\n        if (!hdl) {\n            LOG_DEBUG(\n                \"Failed to find a handle named %s via any registered \"\n                \"implementation\",\n                name);\n        }\n    } else if (discovery_method == GPI_NATIVE) {\n        /* Explicitly does not try to cross language boundaries.\n         * This can be useful when interfacing with\n         * simulators that misbehave during (optional) signal discovery.\n         */\n        hdl = base->m_impl->get_child_by_name(name, base);\n        if (!hdl) {\n            LOG_DEBUG(\n                \"Failed to find a handle named %s via native implementation\",\n                name);\n        }\n    }\n    return hdl;\n}\n\ngpi_sim_hdl gpi_get_handle_by_index(gpi_sim_hdl base, int32_t index) {\n    GpiObjHdl *hdl = NULL;\n    GpiImplInterface *intf = base->m_impl;\n\n    /* Shouldn't need to iterate over interfaces because indexing into a handle\n     * shouldn't cross the interface boundaries.\n     *\n     * NOTE: IUS's VPI interface returned valid VHDL handles, but then couldn't\n     *       use the handle properly.\n     */\n    LOG_DEBUG(\"Checking if index %d native through implementation %s \", index,\n              intf->get_name_c());\n    hdl = intf->get_child_by_index(index, base);\n\n    if (hdl)\n        return CHECK_AND_STORE(hdl);\n    else {\n        LOG_WARN(\n            \"Failed to find a handle at index %d via any registered \"\n            \"implementation\",\n            index);\n        return hdl;\n    }\n}\n\ngpi_iterator_hdl gpi_iterate(gpi_sim_hdl obj_hdl, gpi_iterator_sel type) {\n    if (type == GPI_PACKAGE_SCOPES) {\n        if (obj_hdl != NULL) {\n            LOG_ERROR(\"Cannot iterate over package from non-NULL handles\");\n            return NULL;\n        }\n\n        vector<GpiImplInterface *>::iterator implIter;\n\n        LOG_DEBUG(\"Looking for packages over %d implementations\",\n                  registered_impls.size());\n\n        for (implIter = registered_impls.begin();\n             implIter != registered_impls.end(); implIter++) {\n            GpiIterator *iter =\n                (*implIter)->iterate_handle(NULL, GPI_PACKAGE_SCOPES);\n            if (iter != NULL) return iter;\n        }\n        return NULL;\n    }\n\n    GpiIterator *iter = obj_hdl->m_impl->iterate_handle(obj_hdl, type);\n    if (!iter) {\n        return NULL;\n    }\n    return iter;\n}\n\ngpi_sim_hdl gpi_next(gpi_iterator_hdl iter) {\n    std::string name;\n    GpiObjHdl *parent = iter->get_parent();\n\n    while (true) {\n        GpiObjHdl *next = NULL;\n        void *raw_hdl = NULL;\n        GpiIterator::Status ret = iter->next_handle(name, &next, &raw_hdl);\n\n        switch (ret) {\n            case GpiIterator::NATIVE:\n                LOG_DEBUG(\"Create a native handle\");\n                return CHECK_AND_STORE(next);\n            case GpiIterator::NATIVE_NO_NAME:\n                LOG_DEBUG(\"Unable to fully setup handle, skipping\");\n                continue;\n            case GpiIterator::NOT_NATIVE:\n                LOG_DEBUG(\n                    \"Found a name but unable to create via native \"\n                    \"implementation, trying others\");\n                next = gpi_get_child_by_name(parent, name, iter->m_impl);\n                if (next) {\n                    return next;\n                }\n                LOG_WARN(\n                    \"Unable to create %s via any registered implementation\",\n                    name.c_str());\n                continue;\n            case GpiIterator::NOT_NATIVE_NO_NAME:\n                LOG_DEBUG(\n                    \"Found an object but not accessible via %s, trying others\",\n                    iter->m_impl->get_name_c());\n                next = gpi_get_child_from_handle(parent, raw_hdl, iter->m_impl);\n                if (next) {\n                    return next;\n                }\n                continue;\n            case GpiIterator::END:\n                LOG_DEBUG(\"Reached end of iterator\");\n                delete iter;\n                return NULL;\n        }\n    }\n}\n\nconst char *gpi_get_definition_name(gpi_sim_hdl obj_hdl) {\n    return obj_hdl->get_definition_name();\n}\n\nconst char *gpi_get_definition_file(gpi_sim_hdl obj_hdl) {\n    return obj_hdl->get_definition_file();\n}\n\nstatic std::string g_binstr;\n\nconst char *gpi_get_signal_value_binstr(gpi_sim_hdl sig_hdl) {\n    GpiSignalObjHdl *obj_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n    g_binstr = obj_hdl->get_signal_value_binstr();\n    std::transform(g_binstr.begin(), g_binstr.end(), g_binstr.begin(),\n                   ::toupper);\n    return g_binstr.c_str();\n}\n\nconst char *gpi_get_signal_value_str(gpi_sim_hdl sig_hdl) {\n    GpiSignalObjHdl *obj_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n    return obj_hdl->get_signal_value_str();\n}\n\ndouble gpi_get_signal_value_real(gpi_sim_hdl sig_hdl) {\n    GpiSignalObjHdl *obj_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n    return obj_hdl->get_signal_value_real();\n}\n\nlong gpi_get_signal_value_long(gpi_sim_hdl sig_hdl) {\n    GpiSignalObjHdl *obj_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n    return obj_hdl->get_signal_value_long();\n}\n\nconst char *gpi_get_signal_name_str(gpi_sim_hdl sig_hdl) {\n    GpiSignalObjHdl *obj_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n    return obj_hdl->get_name_str();\n}\n\nconst char *gpi_get_signal_type_str(gpi_sim_hdl sig_hdl) {\n    return sig_hdl->get_type_str();\n}\n\ngpi_objtype gpi_get_object_type(gpi_sim_hdl obj_hdl) {\n    return obj_hdl->get_type();\n}\n\nint gpi_is_constant(gpi_sim_hdl obj_hdl) {\n    if (obj_hdl->get_const()) return 1;\n    return 0;\n}\n\nint gpi_is_indexable(gpi_sim_hdl obj_hdl) {\n    if (obj_hdl->get_indexable()) return 1;\n    return 0;\n}\n\nint gpi_is_signed(gpi_sim_hdl obj_hdl) { return obj_hdl->get_signed(); }\n\nvoid gpi_set_signal_value_int(gpi_sim_hdl sig_hdl, int32_t value,\n                              gpi_set_action action) {\n    GpiSignalObjHdl *obj_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n\n    obj_hdl->set_signal_value(value, action);\n}\n\nvoid gpi_set_signal_value_binstr(gpi_sim_hdl sig_hdl, const char *binstr,\n                                 gpi_set_action action) {\n    std::string value = binstr;\n    GpiSignalObjHdl *obj_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n    obj_hdl->set_signal_value_binstr(value, action);\n}\n\nvoid gpi_set_signal_value_str(gpi_sim_hdl sig_hdl, const char *str,\n                              gpi_set_action action) {\n    std::string value = str;\n    GpiSignalObjHdl *obj_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n    obj_hdl->set_signal_value_str(value, action);\n}\n\nvoid gpi_set_signal_value_real(gpi_sim_hdl sig_hdl, double value,\n                               gpi_set_action action) {\n    GpiSignalObjHdl *obj_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n    obj_hdl->set_signal_value(value, action);\n}\n\nint gpi_get_num_elems(gpi_sim_hdl obj_hdl) { return obj_hdl->get_num_elems(); }\n\nint gpi_get_range_left(gpi_sim_hdl obj_hdl) {\n    return obj_hdl->get_range_left();\n}\n\nint gpi_get_range_right(gpi_sim_hdl obj_hdl) {\n    return obj_hdl->get_range_right();\n}\n\ngpi_range_dir gpi_get_range_dir(gpi_sim_hdl obj_hdl) {\n    return obj_hdl->get_range_dir();\n}\n\ngpi_cb_hdl gpi_register_value_change_callback(int (*gpi_function)(void *),\n                                              void *gpi_cb_data,\n                                              gpi_sim_hdl sig_hdl,\n                                              gpi_edge edge) {\n    GpiSignalObjHdl *signal_hdl = static_cast<GpiSignalObjHdl *>(sig_hdl);\n\n    /* Do something based on int & GPI_RISING | GPI_FALLING */\n    GpiCbHdl *cb_hdl = signal_hdl->register_value_change_callback(\n        edge, gpi_function, gpi_cb_data);\n    if (!cb_hdl) {\n        LOG_ERROR(\"Failed to register a value change callback\");\n        return NULL;\n    } else {\n        return cb_hdl;\n    }\n}\n\ngpi_cb_hdl gpi_register_timed_callback(int (*gpi_function)(void *),\n                                       void *gpi_cb_data, uint64_t time) {\n    // It should not matter which implementation we use for this so just pick\n    // the first one\n    GpiCbHdl *cb_hdl = registered_impls[0]->register_timed_callback(\n        time, gpi_function, gpi_cb_data);\n    if (!cb_hdl) {\n        LOG_ERROR(\"Failed to register a timed callback\");\n        return NULL;\n    } else {\n        return cb_hdl;\n    }\n}\n\ngpi_cb_hdl gpi_register_readonly_callback(int (*gpi_function)(void *),\n                                          void *gpi_cb_data) {\n    // It should not matter which implementation we use for this so just pick\n    // the first one\n    GpiCbHdl *cb_hdl = registered_impls[0]->register_readonly_callback(\n        gpi_function, gpi_cb_data);\n    if (!cb_hdl) {\n        LOG_ERROR(\"Failed to register a readonly callback\");\n        return NULL;\n    } else {\n        return cb_hdl;\n    }\n}\n\ngpi_cb_hdl gpi_register_nexttime_callback(int (*gpi_function)(void *),\n                                          void *gpi_cb_data) {\n    // It should not matter which implementation we use for this so just pick\n    // the first one\n    GpiCbHdl *cb_hdl = registered_impls[0]->register_nexttime_callback(\n        gpi_function, gpi_cb_data);\n    if (!cb_hdl) {\n        LOG_ERROR(\"Failed to register a nexttime callback\");\n        return NULL;\n    } else {\n        return cb_hdl;\n    }\n}\n\ngpi_cb_hdl gpi_register_readwrite_callback(int (*gpi_function)(void *),\n                                           void *gpi_cb_data) {\n    // It should not matter which implementation we use for this so just pick\n    // the first one\n    GpiCbHdl *cb_hdl = registered_impls[0]->register_readwrite_callback(\n        gpi_function, gpi_cb_data);\n    if (!cb_hdl) {\n        LOG_ERROR(\"Failed to register a readwrite callback\");\n        return NULL;\n    } else {\n        return cb_hdl;\n    }\n}\n\nint gpi_remove_cb(gpi_cb_hdl cb_hdl) { return cb_hdl->remove(); }\n\nvoid gpi_get_cb_info(gpi_cb_hdl cb_hdl, int (**cb_func)(void *),\n                     void **cb_data) {\n    cb_hdl->get_cb_info(cb_func, cb_data);\n}\n\nconst char *GpiImplInterface::get_name_c() { return m_name.c_str(); }\n\nconst string &GpiImplInterface::get_name_s() { return m_name; }\n\nint gpi_register_start_of_sim_time_callback(int (*cb)(void *), void *cb_data) {\n    start_of_sim_time_cbs.push_back(std::make_pair(cb, cb_data));\n    return 0;\n}\n\nint gpi_register_end_of_sim_time_callback(void (*cb)(void *), void *cb_data) {\n    end_of_sim_time_cbs.push_back(std::make_pair(cb, cb_data));\n    return 0;\n}\n\nint gpi_register_finalize_callback(void (*cb)(void *), void *cb_data) {\n    finalize_cbs.push_back(std::make_pair(cb, cb_data));\n    return 0;\n}\n\nint gpi_get_simulator_args(int *argc, char const *const **argv) {\n    registered_impls[0]->get_simulator_args(argc, argv);\n    return 0;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/dynload.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <stdlib.h>\n\n#include \"./logging.hpp\"\n\n#ifdef _WIN32\n#include <windows.h>\n#else\n#include <dlfcn.h>\n#endif\n\nvoid *utils_dyn_open(const char *lib_name) {\n    void *ret = NULL;\n#ifdef _WIN32\n    SetErrorMode(0);\n    ret = static_cast<void *>(LoadLibrary(lib_name));\n    if (!ret) {\n        const char *log_fmt = \"Unable to open lib '%s'%s%s\";\n        LPSTR msg_ptr;\n        if (FormatMessageA(\n                FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,\n                NULL, GetLastError(),\n                MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), (LPSTR)&msg_ptr,\n                255, NULL)) {\n            LOG_ERROR(log_fmt, lib_name, \": \", msg_ptr);\n            LocalFree(msg_ptr);\n        } else {\n            LOG_ERROR(log_fmt, lib_name, \"\", \"\");\n        }\n    }\n#else\n    /* Clear status */\n    dlerror();\n\n    ret = dlopen(lib_name, RTLD_LAZY | RTLD_GLOBAL);\n    if (!ret) {\n        LOG_ERROR(\"Unable to open lib '%s': %s\", lib_name, dlerror());\n    }\n#endif\n    return ret;\n}\n\nvoid *utils_dyn_sym(void *handle, const char *sym_name) {\n    void *entry_point;\n#ifdef _WIN32\n    entry_point = reinterpret_cast<void *>(\n        GetProcAddress(static_cast<HMODULE>(handle), sym_name));\n    if (!entry_point) {\n        const char *log_fmt = \"Unable to find symbol '%s'%s%s\";\n        LPSTR msg_ptr;\n        if (FormatMessageA(\n                FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,\n                NULL, GetLastError(),\n                MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), (LPSTR)&msg_ptr,\n                255, NULL)) {\n            LOG_ERROR(log_fmt, sym_name, \": \", msg_ptr);\n            LocalFree(msg_ptr);\n        } else {\n            LOG_ERROR(log_fmt, sym_name, \"\", \"\");\n        }\n    }\n#else\n    entry_point = dlsym(handle, sym_name);\n    if (!entry_point) {\n        LOG_ERROR(\"Unable to find symbol '%s': %s\", sym_name, dlerror());\n    }\n#endif\n    return entry_point;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/fli/FliCbHdl.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2015/16 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <cstring>\n\n#include \"../logging.hpp\"\n#include \"./FliImpl.hpp\"\n#include \"_vendor/fli/mti.h\"\n\n// Main re-entry point for callbacks from simulator\nvoid handle_fli_callback(void *data) {\n    SIM_TO_GPI(FLI, data, \"callback\");\n\n    // TODO Add why?\n    fflush(stderr);\n\n    FliCbHdl *cb_hdl = (FliCbHdl *)data;\n\n    int error = (!cb_hdl);\n    // LCOV_EXCL_START\n    if (error) {\n        LOG_CRITICAL(\"FLI: Callback data corrupted: ABORTING\");\n    }\n    // LCOV_EXCL_STOP\n\n    if (!error) {\n        GPI_TO_USER_CB(FLI);\n        error = cb_hdl->run();\n        USER_CB_TO_GPI(FLI);\n    }\n\n    if (error) {\n        gpi_end_of_sim_time();\n    }\n\n    GPI_TO_SIM(FLI, data);\n}\n\nint FliTimedCbHdl::arm() {\n    // These are reused, so we need to reset m_removed.\n    m_removed = false;\n#if defined(__LP64__) || defined(_WIN64)\n    mti_ScheduleWakeup64(m_proc_hdl, static_cast<mtiTime64T>(m_time));\n#else\n    mtiTime64T m_time_union_ps;\n    MTI_TIME64_ASGN(m_time_union_ps, (mtiInt32T)((m_time) >> 32),\n                    (mtiUInt32T)(m_time));\n    mti_ScheduleWakeup64(m_proc_hdl, m_time_union_ps);\n#endif\n    LOG_TRACE(\"FLI: Scheduled timed callback %p for time %lu\", this, m_time);\n    return 0;\n}\n\nint FliTimedCbHdl::run() {\n    int res = 0;\n    if (!m_removed) {\n        // Prevent the callback from calling up if it's been removed.\n        res = m_cb_func(m_cb_data);\n    }\n    // Don't delete, but release back to the appropriate cache to be reused.\n    release();\n    return res;\n}\n\nint FliTimedCbHdl::remove() {\n    // mti_ScheduleWakeup callbacks can't be cancelled, so we mark the callback\n    // as removed and let it fire. When it fires, this flag prevents it from\n    // calling up and then releases the callback back to the appropriate cache\n    // to be reused.\n    m_removed = true;\n    return 0;\n}\n\nint FliSignalCbHdl::arm() {\n    mti_Sensitize(m_proc_hdl, m_signal->get_handle<mtiSignalIdT>(), MTI_EVENT);\n    LOG_TRACE(\"FLI: Scheduled signal callback %p for signal %p\", this,\n              m_signal);\n    return 0;\n}\n\nint FliSignalCbHdl::run() {\n    bool pass = false;\n    switch (m_edge) {\n        case GPI_RISING: {\n            pass = !strcmp(m_signal->get_signal_value_binstr(), \"1\");\n            break;\n        }\n        case GPI_FALLING: {\n            pass = !strcmp(m_signal->get_signal_value_binstr(), \"0\");\n            break;\n        }\n        case GPI_VALUE_CHANGE: {\n            pass = true;\n            break;\n        }\n    }\n\n    int res = 0;\n    if (pass) {\n        res = m_cb_func(m_cb_data);\n\n        // Don't delete, but desensitize the process from the signal change and\n        // release back to the appropriate cache to be reused.\n        mti_Desensitize(m_proc_hdl);\n        release();\n    }  // else don't remove and let it fire again.\n\n    return res;\n}\n\nint FliSignalCbHdl::remove() {\n    // Don't delete, but desensitize the process from the signal change and\n    // release back to the appropriate cache to be reused.\n    mti_Desensitize(m_proc_hdl);\n    release();\n    return 0;\n}\n\nint FliSimPhaseCbHdl::arm() {\n    mti_ScheduleWakeup(m_proc_hdl, 0);\n    m_removed = false;\n    LOG_TRACE(\"FLI: Scheduled simulation phase callback %p\", this);\n    return 0;\n}\n\nint FliSimPhaseCbHdl::run() {\n    int res = 0;\n    if (!m_removed) {\n        // Prevent the callback from calling up if it's been removed.\n        res = m_cb_func(m_cb_data);\n    }\n    // Don't delete, but release back to the appropriate cache to be reused.\n    release();\n    return res;\n}\n\nint FliSimPhaseCbHdl::remove() {\n    // mti_ScheduleWakeup callbacks can't be cancelled, so we mark the callback\n    // as removed and let it fire. When it fires, this flag prevents it from\n    // calling up and then releases the callback back to the appropriate cache\n    // to be reused.\n    m_removed = true;\n    return 0;\n}\n\nvoid FliSignalCbHdl::release() {\n    dynamic_cast<FliImpl *>(m_impl)->m_value_change_cache.release(this);\n}\n\nvoid FliTimedCbHdl::release() {\n    dynamic_cast<FliImpl *>(m_impl)->m_timer_cache.release(this);\n}\n\nvoid FliReadOnlyCbHdl::release() {\n    dynamic_cast<FliImpl *>(m_impl)->m_read_only_cache.release(this);\n}\n\nvoid FliReadWriteCbHdl::release() {\n    dynamic_cast<FliImpl *>(m_impl)->m_read_write_cache.release(this);\n}\n\nvoid FliNextPhaseCbHdl::release() {\n    dynamic_cast<FliImpl *>(m_impl)->m_next_phase_cache.release(this);\n}\n\nint FliStartupCbHdl::arm() {\n    mti_AddLoadDoneCB(handle_fli_callback, (void *)this);\n    LOG_TRACE(\"FLI: Scheduled startup callback %p\", this);\n    return 0;\n}\n\nint FliStartupCbHdl::run() {\n    int res = m_cb_func(m_cb_data);\n    delete this;\n    return res;\n}\n\nint FliStartupCbHdl::remove() {\n    mti_RemoveLoadDoneCB(handle_fli_callback, (void *)this);\n    delete this;\n    return 0;\n}\n\nint FliShutdownCbHdl::arm() {\n    mti_AddQuitCB(handle_fli_callback, (void *)this);\n    LOG_TRACE(\"FLI: Scheduled shutdown callback %p\", this);\n    return 0;\n}\n\nint FliShutdownCbHdl::run() {\n    int res = m_cb_func(m_cb_data);\n    delete this;\n    return res;\n}\n\nint FliShutdownCbHdl::remove() {\n    mti_RemoveQuitCB(handle_fli_callback, (void *)this);\n    delete this;\n    return 0;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/fli/FliImpl.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2014, 2018 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include \"./FliImpl.hpp\"\n\n#include <cstddef>\n#include <cstring>\n#include <stdexcept>\n#include <string>\n#include <vector>\n\n#include \"../logging.hpp\"\n#include \"_vendor/fli/acc_user.h\"\n#include \"_vendor/fli/acc_vhdl.h\"\n#include \"_vendor/fli/mti.h\"\n#include \"_vendor/tcl/tcl.h\"\n\nvoid FliImpl::sim_end() {\n    m_sim_finish_cb->remove();\n    if (mti_NowUpper() == 0 && mti_Now() == 0 && mti_Delta() == 0) {\n        mti_Quit();\n    } else {\n        mti_Break();\n    }\n}\n\nbool FliImpl::isValueConst(int kind) {\n    return (kind == accGeneric || kind == accVHDLConstant);\n}\n\nbool FliImpl::isValueLogic(mtiTypeIdT type) {\n    mtiInt32T numEnums = mti_TickLength(type);\n    if (numEnums == 2) {\n        char **enum_values = mti_GetEnumValues(type);\n        std::string str0 = enum_values[0];\n        std::string str1 = enum_values[1];\n\n        if (str0.compare(\"'0'\") == 0 && str1.compare(\"'1'\") == 0) {\n            return true;\n        }\n    } else if (numEnums == 9) {\n        const char enums[9][4] = {\"'U'\", \"'X'\", \"'0'\", \"'1'\", \"'Z'\",\n                                  \"'W'\", \"'L'\", \"'H'\", \"'-'\"};\n        char **enum_values = mti_GetEnumValues(type);\n\n        for (int i = 0; i < 9; i++) {\n            std::string str = enum_values[i];\n            if (str.compare(enums[i]) != 0) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    return false;\n}\n\nbool FliImpl::isValueChar(mtiTypeIdT type) {\n    const int NUM_ENUMS_IN_CHAR_TYPE = 256;\n    return (mti_TickLength(type) == NUM_ENUMS_IN_CHAR_TYPE);\n}\n\nbool FliImpl::isValueBoolean(mtiTypeIdT type) {\n    if (mti_TickLength(type) == 2) {\n        char **enum_values = mti_GetEnumValues(type);\n        std::string strFalse = enum_values[0];\n        std::string strTrue = enum_values[1];\n\n        if (strFalse.compare(\"FALSE\") == 0 && strTrue.compare(\"TRUE\") == 0) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool FliImpl::isTypeValue(int type) {\n    return (type == accAlias || type == accVHDLConstant || type == accGeneric ||\n            type == accVariable || type == accSignal);\n}\n\nbool FliImpl::isTypeSignal(int type, int full_type) {\n    return (type == accSignal || full_type == accAliasSignal);\n}\n\nGpiObjHdl *FliImpl::create_gpi_obj_from_handle(void *hdl,\n                                               const std::string &name,\n                                               const std::string &fq_name,\n                                               int accType, int accFullType) {\n    GpiObjHdl *new_obj = NULL;\n\n    LOG_DEBUG(\n        \"Attempting to create GPI object from handle (Type=%d, FullType=%d).\",\n        accType, accFullType);\n    if (!VS_TYPE_IS_VHDL(accFullType)) {\n        LOG_DEBUG(\"Handle is not a VHDL type.\");\n        return NULL;\n    }\n\n    if (!isTypeValue(accType)) {\n        /* Need a Pseudo-region to handle generate loops in a consistent manner\n         * across interfaces and across the different methods of accessing data.\n         */\n        std::string rgn_name =\n            mti_GetRegionName(static_cast<mtiRegionIdT>(hdl));\n        if (name != rgn_name) {\n            LOG_DEBUG(\"Found pseudo-region %s -> %p\", fq_name.c_str(), hdl);\n            new_obj =\n                new FliObjHdl(this, hdl, GPI_GENARRAY, accType, accFullType);\n        } else {\n            LOG_DEBUG(\"Found region %s -> %p\", fq_name.c_str(), hdl);\n            new_obj =\n                new FliObjHdl(this, hdl, GPI_MODULE, accType, accFullType);\n        }\n    } else {\n        bool is_var;\n        bool is_const;\n        mtiTypeIdT valType;\n        mtiTypeKindT typeKind;\n\n        if (isTypeSignal(accType, accFullType)) {\n            LOG_DEBUG(\"Found a signal %s -> %p\", fq_name.c_str(), hdl);\n            is_var = false;\n            is_const = false;\n            valType = mti_GetSignalType(static_cast<mtiSignalIdT>(hdl));\n        } else {\n            LOG_DEBUG(\"Found a variable %s -> %p\", fq_name.c_str(), hdl);\n            is_var = true;\n            is_const = isValueConst(accFullType);\n            valType = mti_GetVarType(static_cast<mtiVariableIdT>(hdl));\n        }\n\n        typeKind = mti_GetTypeKind(valType);\n\n        switch (typeKind) {\n            case MTI_TYPE_ENUM:\n                if (isValueLogic(valType)) {\n                    new_obj = new FliLogicObjHdl(this, hdl, GPI_LOGIC, is_const,\n                                                 accType, accFullType, is_var,\n                                                 valType, typeKind);\n                } else if (isValueBoolean(valType) || isValueChar(valType)) {\n                    new_obj = new FliIntObjHdl(this, hdl, GPI_INTEGER, is_const,\n                                               accType, accFullType, is_var,\n                                               valType, typeKind);\n                } else {\n                    new_obj = new FliEnumObjHdl(this, hdl, GPI_ENUM, is_const,\n                                                accType, accFullType, is_var,\n                                                valType, typeKind);\n                }\n                break;\n            case MTI_TYPE_SCALAR:\n            case MTI_TYPE_PHYSICAL:\n                new_obj =\n                    new FliIntObjHdl(this, hdl, GPI_INTEGER, is_const, accType,\n                                     accFullType, is_var, valType, typeKind);\n                break;\n            case MTI_TYPE_REAL:\n                new_obj =\n                    new FliRealObjHdl(this, hdl, GPI_REAL, is_const, accType,\n                                      accFullType, is_var, valType, typeKind);\n                break;\n            case MTI_TYPE_ARRAY: {\n                mtiTypeIdT elemType = mti_GetArrayElementType(valType);\n                mtiTypeKindT elemTypeKind = mti_GetTypeKind(elemType);\n\n                switch (elemTypeKind) {\n                    case MTI_TYPE_ENUM:\n                        if (isValueLogic(elemType)) {\n                            new_obj = new FliLogicObjHdl(\n                                this, hdl, GPI_LOGIC_ARRAY, is_const, accType,\n                                accFullType, is_var, valType,\n                                typeKind);  // std_logic_vector\n                        } else if (isValueChar(elemType)) {\n                            new_obj = new FliStringObjHdl(\n                                this, hdl, GPI_STRING, is_const, accType,\n                                accFullType, is_var, valType, typeKind);\n                        } else {\n                            new_obj = new FliValueObjHdl(\n                                this, hdl, GPI_ARRAY, false, accType,\n                                accFullType, is_var, valType,\n                                typeKind);  // array of enums\n                        }\n                        break;\n                    default:\n                        new_obj = new FliValueObjHdl(\n                            this, hdl, GPI_ARRAY, false, accType, accFullType,\n                            is_var, valType,\n                            typeKind);  // array of (array, Integer, Real,\n                                        // Record, etc.)\n                }\n            } break;\n            case MTI_TYPE_RECORD:\n                new_obj =\n                    new FliValueObjHdl(this, hdl, GPI_STRUCTURE, false, accType,\n                                       accFullType, is_var, valType, typeKind);\n                break;\n            default:\n                LOG_ERROR(\"Unable to handle object type for %s (%d)\",\n                          name.c_str(), typeKind);\n                return NULL;\n        }\n    }\n\n    if (NULL == new_obj) {\n        LOG_DEBUG(\"Didn't find anything named %s\", fq_name.c_str());\n        return NULL;\n    }\n\n    if (new_obj->initialise(name, fq_name) < 0) {\n        LOG_ERROR(\"Failed to initialize the handle %s\", name.c_str());\n        delete new_obj;\n        return NULL;\n    }\n\n    return new_obj;\n}\n\nGpiObjHdl *FliImpl::get_child_from_handle(void *raw_hdl, GpiObjHdl *) {\n    LOG_DEBUG(\"Trying to convert a raw handle to an FLI Handle.\");\n\n    const char *c_name = acc_fetch_name(raw_hdl);\n    const char *c_fullname = acc_fetch_fullname(raw_hdl);\n\n    if (!c_name) {\n        LOG_DEBUG(\"Unable to query the name of the raw handle.\");\n        return NULL;\n    }\n\n    std::string name = c_name;\n    std::string fq_name = c_fullname;\n\n    PLI_INT32 accType = acc_fetch_type(raw_hdl);\n    PLI_INT32 accFullType = acc_fetch_fulltype(raw_hdl);\n\n    return create_gpi_obj_from_handle(raw_hdl, name, fq_name, accType,\n                                      accFullType);\n}\n\n/**\n * @name    Get Child By Name\n * @brief   Attempt to get child handle by name with FLI and create\n *          a handle if it exists\n */\nGpiObjHdl *FliImpl::get_child_by_name(const std::string &name,\n                                      GpiObjHdl *parent) {\n    bool search_rgn = false;\n    bool search_sig = false;\n    bool search_var = false;\n\n    std::string fq_name = parent->get_fullname();\n    gpi_objtype obj_type = parent->get_type();\n\n    if (fq_name == \"/\") {\n        fq_name += name;\n        search_rgn = true;\n        search_sig = true;\n        search_var = true;\n    } else if (obj_type == GPI_MODULE) {\n        fq_name += \"/\" + name;\n        search_rgn = true;\n        search_sig = true;\n        search_var = true;\n    } else if (obj_type == GPI_STRUCTURE) {\n        FliValueObjHdl *fli_obj = reinterpret_cast<FliValueObjHdl *>(parent);\n\n        fq_name += \".\" + name;\n        search_rgn = false;\n        search_var = fli_obj->is_variable();\n        search_sig = !search_var;\n    } else {\n        LOG_ERROR(\n            \"FLI: Parent of type %d must be of type GPI_MODULE or \"\n            \"GPI_STRUCTURE to have a child.\",\n            obj_type);\n        return NULL;\n    }\n\n    LOG_DEBUG(\"Looking for child %s from %s\", name.c_str(),\n              parent->get_name_str());\n\n    std::vector<char> writable(fq_name.begin(), fq_name.end());\n    writable.push_back('\\0');\n\n    HANDLE hdl = NULL;\n    PLI_INT32 accType;\n    PLI_INT32 accFullType;\n\n    if (search_rgn && (hdl = mti_FindRegion(&writable[0])) != NULL) {\n        accType = acc_fetch_type(hdl);\n        accFullType = acc_fetch_fulltype(hdl);\n        LOG_DEBUG(\"Found region %s -> %p\", fq_name.c_str(), hdl);\n        LOG_DEBUG(\"        Type: %d\", accType);\n        LOG_DEBUG(\"   Full Type: %d\", accFullType);\n    } else if (search_sig && (hdl = mti_FindSignal(&writable[0])) != NULL) {\n        accType = acc_fetch_type(hdl);\n        accFullType = acc_fetch_fulltype(hdl);\n        LOG_DEBUG(\"Found a signal %s -> %p\", fq_name.c_str(), hdl);\n        LOG_DEBUG(\"        Type: %d\", accType);\n        LOG_DEBUG(\"   Full Type: %d\", accFullType);\n    } else if (search_var && (hdl = mti_FindVar(&writable[0])) != NULL) {\n        accFullType = accType =\n            mti_GetVarKind(static_cast<mtiVariableIdT>(hdl));\n        LOG_DEBUG(\"Found a variable %s -> %p\", fq_name.c_str(), hdl);\n        LOG_DEBUG(\"        Type: %d\", accType);\n        LOG_DEBUG(\"   Full Type: %d\", accFullType);\n    } else if (search_rgn) {\n        mtiRegionIdT rgn;\n\n        // Looking for generates should only occur if the parent is from this\n        // implementation\n        if (!parent->is_this_impl(this)) {\n            return NULL;\n        }\n\n        /* If not found, check to see if the name of a generate loop and create\n         * a pseudo-region */\n        for (rgn = mti_FirstLowerRegion(parent->get_handle<mtiRegionIdT>());\n             rgn != NULL; rgn = mti_NextRegion(rgn)) {\n            if (acc_fetch_fulltype(rgn) == accForGenerate) {\n                std::string rgn_name =\n                    mti_GetRegionName(static_cast<mtiRegionIdT>(rgn));\n                if (compare_generate_labels(rgn_name, name)) {\n                    FliObj *fli_obj = dynamic_cast<FliObj *>(parent);\n                    return create_gpi_obj_from_handle(\n                        parent->get_handle<HANDLE>(), name, fq_name,\n                        fli_obj->get_acc_type(), fli_obj->get_acc_full_type());\n                }\n            }\n        }\n    }\n\n    if (NULL == hdl) {\n        LOG_DEBUG(\"Didn't find anything named %s\", &writable[0]);\n        return NULL;\n    }\n\n    /* Generate Loops have inconsistent behavior across fli.  A \"name\"\n     * without an index, i.e. dut.loop vs dut.loop(0), will attempt to map\n     * to index 0, if index 0 exists.  If it doesn't then it won't find\n     * anything.\n     *\n     * If this unique case is hit, we need to create the Pseudo-region, with the\n     * handle being equivalent to the parent handle.\n     */\n    if (accFullType == accForGenerate) {\n        FliObj *fli_obj = dynamic_cast<FliObj *>(parent);\n        return create_gpi_obj_from_handle(parent->get_handle<HANDLE>(), name,\n                                          fq_name, fli_obj->get_acc_type(),\n                                          fli_obj->get_acc_full_type());\n    }\n\n    return create_gpi_obj_from_handle(hdl, name, fq_name, accType, accFullType);\n}\n\n/**\n * @name    Get Child By Index\n * @brief   Attempt to get child handle by index with FLI and create\n *          a handle if it exists\n */\nGpiObjHdl *FliImpl::get_child_by_index(int32_t index, GpiObjHdl *parent) {\n    gpi_objtype obj_type = parent->get_type();\n\n    HANDLE hdl;\n    PLI_INT32 accType;\n    PLI_INT32 accFullType;\n    char buff[14];\n\n    if (obj_type == GPI_GENARRAY) {\n        LOG_DEBUG(\"Looking for index %d from %s\", index,\n                  parent->get_name_str());\n\n        snprintf(buff, 14, \"(%d)\", index);\n\n        std::string idx = buff;\n        std::string name = parent->get_name() + idx;\n        std::string fq_name = parent->get_fullname() + idx;\n\n        std::vector<char> writable(fq_name.begin(), fq_name.end());\n        writable.push_back('\\0');\n\n        if ((hdl = mti_FindRegion(&writable[0])) != NULL) {\n            accType = acc_fetch_type(hdl);\n            accFullType = acc_fetch_fulltype(hdl);\n            LOG_DEBUG(\"Found region %s -> %p\", fq_name.c_str(), hdl);\n            LOG_DEBUG(\"        Type: %d\", accType);\n            LOG_DEBUG(\"   Full Type: %d\", accFullType);\n        } else {\n            LOG_DEBUG(\"Didn't find anything named %s\", &writable[0]);\n            return NULL;\n        }\n\n        return create_gpi_obj_from_handle(hdl, name, fq_name, accType,\n                                          accFullType);\n    } else if (obj_type == GPI_LOGIC || obj_type == GPI_LOGIC_ARRAY ||\n               obj_type == GPI_ARRAY || obj_type == GPI_STRING) {\n        FliValueObjHdl *fli_obj = reinterpret_cast<FliValueObjHdl *>(parent);\n\n        LOG_DEBUG(\"Looking for index %u from %s\", index,\n                  parent->get_name_str());\n\n        if ((hdl = fli_obj->get_sub_hdl(index)) == NULL) {\n            LOG_DEBUG(\"Didn't find the index %d\", index);\n            return NULL;\n        }\n\n        snprintf(buff, 14, \"(%d)\", index);\n\n        std::string idx = buff;\n        std::string name = parent->get_name() + idx;\n        std::string fq_name = parent->get_fullname() + idx;\n\n        if (!(fli_obj->is_variable())) {\n            accType = acc_fetch_type(hdl);\n            accFullType = acc_fetch_fulltype(hdl);\n            LOG_DEBUG(\"Found a signal %s -> %p\", fq_name.c_str(), hdl);\n            LOG_DEBUG(\"        Type: %d\", accType);\n            LOG_DEBUG(\"   Full Type: %d\", accFullType);\n        } else {\n            accFullType = accType =\n                mti_GetVarKind(static_cast<mtiVariableIdT>(hdl));\n            LOG_DEBUG(\"Found a variable %s -> %p\", fq_name.c_str(), hdl);\n            LOG_DEBUG(\"        Type: %d\", accType);\n            LOG_DEBUG(\"   Full Type: %d\", accFullType);\n        }\n        return create_gpi_obj_from_handle(hdl, name, fq_name, accType,\n                                          accFullType);\n    } else {\n        LOG_ERROR(\n            \"FLI: Parent of type %d must be of type GPI_GENARRAY, \"\n            \"GPI_LOGIC, GPI_ARRAY, or GPI_STRING to have an index.\",\n            obj_type);\n        return NULL;\n    }\n}\n\n/**\n * @name    Get current simulation time\n * @brief   Get current simulation time\n *\n * NB units depend on the simulation configuration\n */\nvoid FliImpl::get_sim_time(uint32_t *high, uint32_t *low) {\n    *high = static_cast<uint32_t>(\n        mti_NowUpper());  // these functions return a int32_t for some reason\n    *low = static_cast<uint32_t>(mti_Now());\n}\n\nvoid FliImpl::get_sim_precision(int32_t *precision) {\n    *precision = mti_GetResolutionLimit();\n}\n\nconst char *FliImpl::get_simulator_product() {\n    if (m_product.empty() && m_version.empty()) {\n        const std::string info =\n            mti_GetProductVersion();  // Returned pointer must not be freed,\n                                      // does not fail\n        const std::string search = \" Version \";\n        const std::size_t found = info.find(search);\n\n        if (found != std::string::npos) {\n            m_product = info.substr(0, found);\n            m_version = info.substr(found + search.length());\n        } else {\n            m_product = info;\n            m_version = \"UNKNOWN\";\n        }\n    }\n    return m_product.c_str();\n}\n\nconst char *FliImpl::get_simulator_version() {\n    get_simulator_product();\n    return m_version.c_str();\n}\n\nint FliImpl::get_simulator_args(int *argc, const char *const **argv) {\n    if (m_argv == nullptr) {\n        /*\n        There is no function available on the FLI to obtain argc+argv directly\n        from the simulator. To work around this we use the TCL interpreter that\n        ships with Questa, some TCL commands, and the TCL variable `argv` to\n        obtain the simulator argc+argv.\n        */\n\n        // obtain a reference to TCL interpreter\n        Tcl_Interp *interp = reinterpret_cast<Tcl_Interp *>(mti_Interp());\n\n        // get argv TCL variable\n        auto err = mti_Cmd(\"return -level 0 $argv\") != TCL_OK;\n        // LCOV_EXCL_START\n        if (err) {\n            const char *errmsg = Tcl_GetStringResult(interp);\n            LOG_WARN(\"Failed to get reference to argv: %s\", errmsg);\n            Tcl_ResetResult(interp);\n            return -1;\n        }\n        // LCOV_EXCL_STOP\n        Tcl_Obj *result = Tcl_GetObjResult(interp);\n        Tcl_IncrRefCount(result);\n        Tcl_ResetResult(interp);\n\n        // split TCL list into length and element array\n        Tcl_Obj **tcl_argv;\n        err = Tcl_ListObjGetElements(interp, result, &m_argc, &tcl_argv) !=\n              TCL_OK;\n        // LCOV_EXCL_START\n        if (err) {\n            const char *errmsg = Tcl_GetStringResult(interp);\n            LOG_WARN(\"Failed to get argv elements: %s\", errmsg);\n            Tcl_DecrRefCount(result);\n            Tcl_ResetResult(interp);\n            return -1;\n        }\n        // LCOV_EXCL_STOP\n        Tcl_ResetResult(interp);\n\n        // get each argv arg and copy into internal storage\n        for (int i = 0; i < m_argc; i++) {\n            const char *arg = Tcl_GetString(tcl_argv[i]);\n            m_argv_storage.push_back(arg);\n        }\n        Tcl_DecrRefCount(result);\n\n        // store argv pointers\n        m_argv = new const char *[m_argc];\n        for (int i = 0; i < m_argc; i++) {\n            m_argv[i] = m_argv_storage[static_cast<size_t>(i)].c_str();\n        }\n    }\n    *argc = m_argc;\n    *argv = m_argv;\n    return 0;\n}\n\n/**\n * @name    Find the root handle\n * @brief   Find the root handle using an optional name\n *\n * Get a handle to the root simulator object.  This is usually the toplevel.\n *\n * If no name is provided, we return the first root instance.\n *\n * If name is provided, we check the name against the available objects until\n * we find a match.  If no match is found we return NULL\n */\nGpiObjHdl *FliImpl::get_root_handle(const char *name) {\n    mtiRegionIdT root;\n    char *rgn_name;\n    char *rgn_fullname;\n    std::string root_name;\n    std::string root_fullname;\n    PLI_INT32 accType;\n    PLI_INT32 accFullType;\n\n    for (root = mti_GetTopRegion(); root != NULL; root = mti_NextRegion(root)) {\n        LOG_DEBUG(\"Iterating over: %s\", mti_GetRegionName(root));\n        if (name == NULL || !strcmp(name, mti_GetRegionName(root))) break;\n    }\n\n    if (!root) {\n        goto error;\n    }\n\n    rgn_name = mti_GetRegionName(root);\n    rgn_fullname = mti_GetRegionFullName(root);\n\n    root_name = rgn_name;\n    root_fullname = rgn_fullname;\n    mti_VsimFree(rgn_fullname);\n\n    LOG_DEBUG(\"Found toplevel: %s, creating handle....\", root_name.c_str());\n\n    accType = acc_fetch_type(root);\n    accFullType = acc_fetch_fulltype(root);\n\n    return create_gpi_obj_from_handle(root, root_name, root_fullname, accType,\n                                      accFullType);\n\nerror:\n\n    LOG_ERROR(\"FLI: Couldn't find root handle %s\", name);\n\n    for (root = mti_GetTopRegion(); root != NULL; root = mti_NextRegion(root)) {\n        if (name == NULL) break;\n\n        LOG_ERROR(\"FLI: Toplevel instances: %s != %s...\", name,\n                  mti_GetRegionName(root));\n    }\n    return NULL;\n}\n\nGpiCbHdl *FliImpl::register_timed_callback(uint64_t time,\n                                           int (*cb_func)(void *),\n                                           void *cb_data) {\n    // get timer from cache\n    auto cb_hdl = m_timer_cache.acquire();\n    cb_hdl->set_time(time);\n    int err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        m_timer_cache.release(cb_hdl);\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiCbHdl *FliImpl::register_readonly_callback(int (*cb_func)(void *),\n                                              void *cb_data) {\n    auto cb_hdl = m_read_only_cache.acquire();\n    int err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        m_read_only_cache.release(cb_hdl);\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiCbHdl *FliImpl::register_readwrite_callback(int (*cb_func)(void *),\n                                               void *cb_data) {\n    auto cb_hdl = m_read_write_cache.acquire();\n    int err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        m_read_write_cache.release(cb_hdl);\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiCbHdl *FliImpl::register_nexttime_callback(int (*cb_func)(void *),\n                                              void *cb_data) {\n    auto cb_hdl = m_next_phase_cache.acquire();\n    int err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        m_next_phase_cache.release(cb_hdl);\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiIterator *FliImpl::iterate_handle(GpiObjHdl *obj_hdl,\n                                     gpi_iterator_sel type) {\n    GpiIterator *new_iter = NULL;\n\n    switch (type) {\n        case GPI_OBJECTS:\n            new_iter = new FliIterator(this, obj_hdl);\n            break;\n        case GPI_DRIVERS:\n            LOG_WARN(\"FLI: Drivers iterator not implemented yet\");\n            break;\n        case GPI_LOADS:\n            LOG_WARN(\"FLI: Loads iterator not implemented yet\");\n            break;\n        default:\n            LOG_WARN(\"FLI: Other iterator types not implemented yet\");\n            break;\n    }\n\n    return new_iter;\n}\n\nbool FliImpl::compare_generate_labels(const std::string &a,\n                                      const std::string &b) {\n    /* Compare two generate labels for equality ignoring any suffixed index. */\n    std::size_t a_idx = a.rfind(\"(\");\n    std::size_t b_idx = b.rfind(\"(\");\n    return a.substr(0, a_idx) == b.substr(0, b_idx);\n}\n\ndecltype(FliIterator::iterate_over) FliIterator::iterate_over = [] {\n    std::initializer_list<FliIterator::OneToMany> region_options = {\n        FliIterator::OTM_CONSTANTS,\n        FliIterator::OTM_SIGNALS,\n        FliIterator::OTM_REGIONS,\n    };\n    std::initializer_list<FliIterator::OneToMany> signal_options = {\n        FliIterator::OTM_SIGNAL_SUB_ELEMENTS,\n    };\n    std::initializer_list<FliIterator::OneToMany> variable_options = {\n        FliIterator::OTM_VARIABLE_SUB_ELEMENTS,\n    };\n\n    return decltype(FliIterator::iterate_over){\n        {accArchitecture, region_options},\n        {accEntityVitalLevel0, region_options},\n        {accArchVitalLevel0, region_options},\n        {accArchVitalLevel1, region_options},\n        {accBlock, region_options},\n        {accCompInst, region_options},\n        {accDirectInst, region_options},\n        {accinlinedBlock, region_options},\n        {accinlinedinnerBlock, region_options},\n        {accGenerate, region_options},\n        {accIfGenerate, region_options},\n#ifdef accElsifGenerate\n        {accElsifGenerate, region_options},\n#endif\n#ifdef accElseGenerate\n        {accElseGenerate, region_options},\n#endif\n#ifdef accCaseGenerate\n        {accCaseGenerate, region_options},\n#endif\n#ifdef accCaseOTHERSGenerate\n        {accCaseOTHERSGenerate, region_options},\n#endif\n        {accForGenerate, region_options},\n        {accConfiguration, region_options},\n\n        {accSignal, signal_options},\n        {accSignalBit, signal_options},\n        {accSignalSubComposite, signal_options},\n        {accAliasSignal, signal_options},\n\n        {accVariable, variable_options},\n        {accGeneric, variable_options},\n        {accGenericConstant, variable_options},\n        {accAliasConstant, variable_options},\n        {accAliasGeneric, variable_options},\n        {accAliasVariable, variable_options},\n        {accVHDLConstant, variable_options},\n    };\n}();\n\nFliIterator::FliIterator(GpiImplInterface *impl, GpiObjHdl *hdl)\n    : GpiIterator(impl, hdl),\n      m_vars(),\n      m_sigs(),\n      m_regs(),\n      m_currentHandles(NULL) {\n    FliObj *fli_obj = dynamic_cast<FliObj *>(m_parent);\n    int type = fli_obj->get_acc_full_type();\n\n    LOG_DEBUG(\"fli_iterator::Create iterator for %s of type %d:%s\",\n              m_parent->get_fullname().c_str(), type, acc_fetch_type_str(type));\n\n    try {\n        selected = &iterate_over.at(type);\n    } catch (std::out_of_range const &) {\n        LOG_WARN(\"FLI: Implementation does not know how to iterate over %s(%d)\",\n                 acc_fetch_type_str(type), type);\n        selected = nullptr;\n        return;\n    }\n\n    /* Find the first mapping type that yields a valid iterator */\n    for (one2many = selected->begin(); one2many != selected->end();\n         one2many++) {\n        /* GPI_GENARRAY are pseudo-regions and all that should be searched for\n         * are the sub-regions */\n        if (m_parent->get_type() == GPI_GENARRAY &&\n            *one2many != FliIterator::OTM_REGIONS) {\n            LOG_DEBUG(\"fli_iterator OneToMany=%d skipped for GPI_GENARRAY type\",\n                      *one2many);\n            continue;\n        }\n\n        populate_handle_list(*one2many);\n\n        switch (*one2many) {\n            case FliIterator::OTM_CONSTANTS:\n            case FliIterator::OTM_VARIABLE_SUB_ELEMENTS:\n                m_currentHandles = &m_vars;\n                m_iterator = m_vars.begin();\n                break;\n            case FliIterator::OTM_SIGNALS:\n            case FliIterator::OTM_SIGNAL_SUB_ELEMENTS:\n                m_currentHandles = &m_sigs;\n                m_iterator = m_sigs.begin();\n                break;\n            case FliIterator::OTM_REGIONS:\n                m_currentHandles = &m_regs;\n                m_iterator = m_regs.begin();\n                break;\n            default:\n                LOG_WARN(\"Unhandled OneToMany Type (%d)\", *one2many);\n        }\n\n        if (m_iterator != m_currentHandles->end()) break;\n\n        LOG_DEBUG(\"fli_iterator OneToMany=%d returned NULL\", *one2many);\n    }\n\n    if (m_iterator == m_currentHandles->end()) {\n        LOG_DEBUG(\n            \"fli_iterator return NULL for all relationships on %s (%d) kind:%s\",\n            m_parent->get_name_str(), type, acc_fetch_type_str(type));\n        selected = NULL;\n        return;\n    }\n\n    LOG_DEBUG(\"Created iterator working from scope %d\", *one2many);\n}\n\nGpiIterator::Status FliIterator::next_handle(std::string &name, GpiObjHdl **hdl,\n                                             void **raw_hdl) {\n    HANDLE obj;\n    GpiObjHdl *new_obj;\n\n    if (!selected) return GpiIterator::END;\n\n    gpi_objtype obj_type = m_parent->get_type();\n    std::string parent_name = m_parent->get_name();\n\n    /* We want the next object in the current mapping.\n     * If the end of mapping is reached then we want to\n     * try next one until a new object is found\n     */\n    do {\n        obj = NULL;\n\n        if (m_iterator != m_currentHandles->end()) {\n            obj = *m_iterator++;\n\n            /* For GPI_GENARRAY, only allow the generate statements through that\n             * match the name of the generate block.\n             */\n            if (obj_type == GPI_GENARRAY) {\n                if (acc_fetch_fulltype(obj) == accForGenerate) {\n                    std::string rgn_name =\n                        mti_GetRegionName(static_cast<mtiRegionIdT>(obj));\n                    if (!FliImpl::compare_generate_labels(rgn_name,\n                                                          parent_name)) {\n                        obj = NULL;\n                        continue;\n                    }\n                } else {\n                    obj = NULL;\n                    continue;\n                }\n            }\n\n            break;\n        } else {\n            LOG_DEBUG(\n                \"No more valid handles in the current OneToMany=%d iterator\",\n                *one2many);\n        }\n\n        if (++one2many >= selected->end()) {\n            obj = NULL;\n            break;\n        }\n\n        /* GPI_GENARRAY are pseudo-regions and all that should be searched for\n         * are the sub-regions */\n        if (obj_type == GPI_GENARRAY && *one2many != FliIterator::OTM_REGIONS) {\n            LOG_DEBUG(\"fli_iterator OneToMany=%d skipped for GPI_GENARRAY type\",\n                      *one2many);\n            continue;\n        }\n\n        populate_handle_list(*one2many);\n\n        switch (*one2many) {\n            case FliIterator::OTM_CONSTANTS:\n            case FliIterator::OTM_VARIABLE_SUB_ELEMENTS:\n                m_currentHandles = &m_vars;\n                m_iterator = m_vars.begin();\n                break;\n            case FliIterator::OTM_SIGNALS:\n            case FliIterator::OTM_SIGNAL_SUB_ELEMENTS:\n                m_currentHandles = &m_sigs;\n                m_iterator = m_sigs.begin();\n                break;\n            case FliIterator::OTM_REGIONS:\n                m_currentHandles = &m_regs;\n                m_iterator = m_regs.begin();\n                break;\n            default:\n                LOG_WARN(\"Unhandled OneToMany Type (%d)\", *one2many);\n        }\n    } while (!obj);\n\n    if (NULL == obj) {\n        LOG_DEBUG(\"No more children, all relationships tested\");\n        return GpiIterator::END;\n    }\n\n    char *c_name;\n    PLI_INT32 accType;\n    PLI_INT32 accFullType;\n    switch (*one2many) {\n        case FliIterator::OTM_CONSTANTS:\n        case FliIterator::OTM_VARIABLE_SUB_ELEMENTS:\n            c_name = mti_GetVarName(static_cast<mtiVariableIdT>(obj));\n            accFullType = accType =\n                mti_GetVarKind(static_cast<mtiVariableIdT>(obj));\n            break;\n        case FliIterator::OTM_SIGNALS:\n            c_name = mti_GetSignalName(static_cast<mtiSignalIdT>(obj));\n            accType = acc_fetch_type(obj);\n            accFullType = acc_fetch_fulltype(obj);\n            break;\n        case FliIterator::OTM_SIGNAL_SUB_ELEMENTS:\n            c_name = mti_GetSignalNameIndirect(static_cast<mtiSignalIdT>(obj),\n                                               NULL, 0);\n            accType = acc_fetch_type(obj);\n            accFullType = acc_fetch_fulltype(obj);\n            break;\n        case FliIterator::OTM_REGIONS:\n            c_name = mti_GetRegionName(static_cast<mtiRegionIdT>(obj));\n            accType = acc_fetch_type(obj);\n            accFullType = acc_fetch_fulltype(obj);\n            break;\n        default:\n            c_name = NULL;\n            accType = 0;\n            accFullType = 0;\n            LOG_WARN(\"Unhandled OneToMany Type (%d)\", *one2many);\n    }\n\n    if (!c_name) {\n        if (!VS_TYPE_IS_VHDL(accFullType)) {\n            *raw_hdl = (void *)obj;\n            return GpiIterator::NOT_NATIVE_NO_NAME;\n        }\n\n        return GpiIterator::NATIVE_NO_NAME;\n    }\n\n    /*\n     * If the parent is not a generate loop, then watch for generate handles and\n     * create the pseudo-region.\n     *\n     * NOTE: Taking advantage of the \"caching\" to only create one pseudo-region\n     * object. Otherwise a list would be required and checked while iterating\n     */\n    if (*one2many == FliIterator::OTM_REGIONS && obj_type != GPI_GENARRAY &&\n        accFullType == accForGenerate) {\n        std::string idx_str = c_name;\n        std::size_t found = idx_str.find_last_of(\"(\");\n\n        if (found != std::string::npos && found != 0) {\n            FliObj *fli_obj = dynamic_cast<FliObj *>(m_parent);\n\n            name = idx_str.substr(0, found);\n            obj = m_parent->get_handle<HANDLE>();\n            accType = fli_obj->get_acc_type();\n            accFullType = fli_obj->get_acc_full_type();\n        } else {\n            LOG_WARN(\"Unhandled Generate Loop Format - %s\", name.c_str());\n            name = c_name;\n        }\n    } else {\n        name = c_name;\n    }\n\n    if (*one2many == FliIterator::OTM_SIGNAL_SUB_ELEMENTS) {\n        mti_VsimFree(c_name);\n    }\n\n    std::string fq_name = m_parent->get_fullname();\n    if (fq_name == \"/\") {\n        fq_name += name;\n    } else if (*one2many == FliIterator::OTM_SIGNAL_SUB_ELEMENTS ||\n               *one2many == FliIterator::OTM_VARIABLE_SUB_ELEMENTS ||\n               obj_type == GPI_GENARRAY) {\n        std::size_t found;\n\n        if (obj_type == GPI_STRUCTURE) {\n            found = name.find_last_of(\".\");\n        } else {\n            found = name.find_last_of(\"(\");\n        }\n\n        if (found != std::string::npos) {\n            fq_name += name.substr(found);\n            if (obj_type != GPI_GENARRAY) {\n                name = name.substr(found + 1);\n            }\n        } else {\n            LOG_WARN(\"Unhandled Sub-Element Format - %s\", name.c_str());\n            fq_name += \"/\" + name;\n        }\n    } else {\n        fq_name += \"/\" + name;\n    }\n\n    FliImpl *fli_impl = reinterpret_cast<FliImpl *>(m_impl);\n    new_obj = fli_impl->create_gpi_obj_from_handle(obj, name, fq_name, accType,\n                                                   accFullType);\n    if (new_obj) {\n        *hdl = new_obj;\n        return GpiIterator::NATIVE;\n    } else {\n        return GpiIterator::NOT_NATIVE;\n    }\n}\n\nvoid FliIterator::populate_handle_list(FliIterator::OneToMany childType) {\n    switch (childType) {\n        case FliIterator::OTM_CONSTANTS: {\n            mtiRegionIdT parent = m_parent->get_handle<mtiRegionIdT>();\n            mtiVariableIdT id;\n\n            for (id = mti_FirstVarByRegion(parent); id; id = mti_NextVar()) {\n                if (id) {\n                    m_vars.push_back(id);\n                }\n            }\n        } break;\n        case FliIterator::OTM_SIGNALS: {\n            mtiRegionIdT parent = m_parent->get_handle<mtiRegionIdT>();\n            mtiSignalIdT id;\n\n            for (id = mti_FirstSignal(parent); id; id = mti_NextSignal()) {\n                if (id) {\n                    m_sigs.push_back(id);\n                }\n            }\n        } break;\n        case FliIterator::OTM_REGIONS: {\n            mtiRegionIdT parent = m_parent->get_handle<mtiRegionIdT>();\n            mtiRegionIdT id;\n\n            for (id = mti_FirstLowerRegion(parent); id;\n                 id = mti_NextRegion(id)) {\n                if (id) {\n                    m_regs.push_back(id);\n                }\n            }\n        } break;\n        case FliIterator::OTM_SIGNAL_SUB_ELEMENTS:\n            if (m_parent->get_type() == GPI_STRUCTURE) {\n                mtiSignalIdT parent = m_parent->get_handle<mtiSignalIdT>();\n\n                mtiTypeIdT type = mti_GetSignalType(parent);\n                mtiSignalIdT *ids = mti_GetSignalSubelements(parent, NULL);\n\n                LOG_DEBUG(\"GPI_STRUCTURE: %d fields\", mti_TickLength(type));\n                for (int i = 0; i < mti_TickLength(type); i++) {\n                    m_sigs.push_back(ids[i]);\n                }\n                mti_VsimFree(ids);\n            } else if (m_parent->get_indexable()) {\n                FliValueObjHdl *fli_obj =\n                    reinterpret_cast<FliValueObjHdl *>(m_parent);\n\n                int left = m_parent->get_range_left();\n                int right = m_parent->get_range_right();\n\n                if (left > right) {\n                    for (int i = left; i >= right; i--) {\n                        m_sigs.push_back(\n                            static_cast<mtiSignalIdT>(fli_obj->get_sub_hdl(i)));\n                    }\n                } else {\n                    for (int i = left; i <= right; i++) {\n                        m_sigs.push_back(\n                            static_cast<mtiSignalIdT>(fli_obj->get_sub_hdl(i)));\n                    }\n                }\n            }\n            break;\n        case FliIterator::OTM_VARIABLE_SUB_ELEMENTS:\n            if (m_parent->get_type() == GPI_STRUCTURE) {\n                mtiVariableIdT parent = m_parent->get_handle<mtiVariableIdT>();\n\n                mtiTypeIdT type = mti_GetVarType(parent);\n                mtiVariableIdT *ids = mti_GetVarSubelements(parent, NULL);\n\n                LOG_DEBUG(\"GPI_STRUCTURE: %d fields\", mti_TickLength(type));\n                for (int i = 0; i < mti_TickLength(type); i++) {\n                    m_vars.push_back(ids[i]);\n                }\n\n                mti_VsimFree(ids);\n            } else if (m_parent->get_indexable()) {\n                FliValueObjHdl *fli_obj =\n                    reinterpret_cast<FliValueObjHdl *>(m_parent);\n\n                int left = m_parent->get_range_left();\n                int right = m_parent->get_range_right();\n\n                if (left > right) {\n                    for (int i = left; i >= right; i--) {\n                        m_vars.push_back(static_cast<mtiVariableIdT>(\n                            fli_obj->get_sub_hdl(i)));\n                    }\n                } else {\n                    for (int i = left; i <= right; i++) {\n                        m_vars.push_back(static_cast<mtiVariableIdT>(\n                            fli_obj->get_sub_hdl(i)));\n                    }\n                }\n            }\n            break;\n        default:\n            LOG_WARN(\"Unhandled OneToMany Type (%d)\", childType);\n    }\n}\n\nstatic int startup_callback(void *) {\n    LOG_TRACE(\"GPI => [ GPI (FLI startup) ]\");\n    gpi_start_of_sim_time();\n    LOG_TRACE(\"[ GPI (FLI startup) ] => GPI\");\n    return 0;\n}\n\nstatic int shutdown_callback(void *) {\n    LOG_TRACE(\"GPI => [ GPI (FLI shutdown) ]\");\n    gpi_end_of_sim_time();\n    LOG_TRACE(\"[ GPI (FLI shutdown) ] => GPI\");\n    return 0;\n}\n\nvoid FliImpl::main() noexcept {\n    auto startup_cb = new FliStartupCbHdl(this);\n    auto err = startup_cb->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        LOG_CRITICAL(\n            \"FLI: Unable to register startup callback! Simulation will end.\");\n        delete startup_cb;\n        exit(1);\n    }\n    // LCOV_EXCL_STOP\n    startup_cb->set_cb_info(startup_callback, nullptr);\n\n    auto shutdown_cb = new FliShutdownCbHdl(this);\n    err = shutdown_cb->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        LOG_CRITICAL(\n            \"FLI: Unable to register shutdown callback! Simulation will end.\");\n        startup_cb->remove();\n        delete shutdown_cb;\n        exit(1);\n    }\n    // LCOV_EXCL_STOP\n    shutdown_cb->set_cb_info(shutdown_callback, nullptr);\n    m_sim_finish_cb = shutdown_cb;\n\n    gpi_register_impl(this);\n    gpi_entry_point();\n}\n\n// This is run by GPI when requested for mixed-language simulations\nstatic void register_impl() {\n    LOG_TRACE(\"GPI Init => [ FLI (register_impl) ]\");\n    auto fli_table = new FliImpl(\"FLI\");\n    gpi_register_impl(fli_table);\n    LOG_TRACE(\"[ FLI (register_impl) ] => GPI Init\");\n}\n\nextern \"C\" {\n// This is run by the simulator at startup when this is the main GPI entrypoint\nCOCOTBFLI_EXPORT void cocotb_init() {\n    gpi_init_logging_and_debug();\n    LOG_TRACE(\"Sim => [ FLI (cocotb_init) ]\");\n    auto fli_table = new FliImpl(\"FLI\");\n    fli_table->main();\n    LOG_TRACE(\"[ FLI (cocotb_init) ] => Sim\");\n}\n}\n\nGPI_ENTRY_POINT(cocotbfli, register_impl);\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/fli/FliImpl.hpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2014 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#ifndef COCOTB_FLI_IMPL_H_\n#define COCOTB_FLI_IMPL_H_\n\n#include <exports.h>\n#include <gpi.h>\n\n#include <map>\n#include <vector>\n\n#include \"../gpi_priv.hpp\"\n#include \"_vendor/fli/mti.h\"\n\n#ifdef COCOTBFLI_EXPORTS\n#define COCOTBFLI_EXPORT COCOTB_EXPORT\n#else\n#define COCOTBFLI_EXPORT COCOTB_IMPORT\n#endif\n\nclass FliImpl;\nclass FliSignalObjHdl;\n\nclass FliCbHdl : public GpiCbHdl {\n  public:\n    using GpiCbHdl::GpiCbHdl;\n};\n\n// In FLI some callbacks require us to register a process\n// We use a subclass to track the process state related to the callback\nclass FliProcessCbHdl : public FliCbHdl {\n  public:\n    FliProcessCbHdl(GpiImplInterface *impl) : FliCbHdl(impl) {}\n\n    void set_mti_proc(mtiProcessIdT mti_proc) noexcept {\n        m_proc_hdl = mti_proc;\n    }\n\n    virtual void release() = 0;\n\n  protected:\n    mtiProcessIdT m_proc_hdl;\n};\n\n/** Maintains a cache of FliProcessCbHdl objects which can be reused.\n *\n * MTI Processes cannot be destroyed. So we never delete FliProcessCbHdl objects\n * and their MTI Processes and instead reuse them to prevent runaway leaks.\n *\n * We use the queue with LIFO behavior so recently used objects are reused first\n * leveraging cache locality.\n */\ntemplate <typename FliProcessCbHdlType, int priority>\nclass FliProcessCbHdlCache {\n  public:\n    FliProcessCbHdlCache(FliImpl *impl) : m_impl(impl) {}\n\n    FliProcessCbHdlType *acquire() {\n        void handle_fli_callback(void *);\n\n        if (!free_list.empty()) {\n            FliProcessCbHdlType *cb_hdl = free_list.back();\n            free_list.pop_back();\n            return cb_hdl;\n        } else {\n            auto cb_hdl = new FliProcessCbHdlType(m_impl);\n            auto mti_proc = mti_CreateProcessWithPriority(\n                nullptr, handle_fli_callback, cb_hdl,\n                (mtiProcessPriorityT)priority);\n            cb_hdl->set_mti_proc(mti_proc);\n            return cb_hdl;\n        }\n    }\n    void release(FliProcessCbHdlType *cb_hdl) { free_list.push_back(cb_hdl); }\n\n  private:\n    FliImpl *m_impl;\n    std::vector<FliProcessCbHdlType *> free_list;\n};\n\nclass FliSignalCbHdl : public FliProcessCbHdl {\n  public:\n    using FliProcessCbHdl::FliProcessCbHdl;\n\n    /** Set the signal and edge used by arm()\n     *\n     * MUST BE CALLED BEFORE arm()!\n     */\n    void set_signal_and_edge(FliSignalObjHdl *signal, gpi_edge edge) noexcept {\n        m_signal = signal;\n        m_edge = edge;\n    };\n    int arm() override;\n    int run() override;\n    int remove() override;\n    void release() override;\n\n  private:\n    FliSignalObjHdl *m_signal;\n    gpi_edge m_edge;\n};\n\nclass FliSimPhaseCbHdl : public FliProcessCbHdl {\n  public:\n    using FliProcessCbHdl::FliProcessCbHdl;\n    int arm() override;\n    int run() override;\n    int remove() override;\n\n  private:\n    bool m_removed;\n};\n\nclass FliReadWriteCbHdl : public FliSimPhaseCbHdl {\n  public:\n    using FliSimPhaseCbHdl::FliSimPhaseCbHdl;\n    void release() override;\n};\n\nclass FliNextPhaseCbHdl : public FliSimPhaseCbHdl {\n  public:\n    using FliSimPhaseCbHdl::FliSimPhaseCbHdl;\n    void release() override;\n};\n\nclass FliReadOnlyCbHdl : public FliSimPhaseCbHdl {\n  public:\n    using FliSimPhaseCbHdl::FliSimPhaseCbHdl;\n    void release() override;\n};\n\nclass FliStartupCbHdl : public FliCbHdl {\n  public:\n    FliStartupCbHdl(GpiImplInterface *impl) : FliCbHdl(impl) {}\n\n    int arm() override;\n    int run() override;\n    int remove() override;\n};\n\nclass FliShutdownCbHdl : public FliCbHdl {\n  public:\n    FliShutdownCbHdl(GpiImplInterface *impl) : FliCbHdl(impl) {}\n\n    int arm() override;\n    int run() override;\n    int remove() override;\n};\n\nclass FliTimedCbHdl : public FliProcessCbHdl {\n  public:\n    using FliProcessCbHdl::FliProcessCbHdl;\n\n    /** Set the time used by arm()\n     *\n     * MUST BE CALLED BEFORE arm()!\n     */\n    void set_time(uint64_t time) noexcept { m_time = time; }\n    int arm() override;\n    int run() override;\n    int remove() override;\n    void release() override;\n\n  private:\n    uint64_t m_time;\n    bool m_removed;\n};\n\n// Object Handles\nclass FliObj {\n  public:\n    FliObj(int acc_type, int acc_full_type)\n        : m_acc_type(acc_type), m_acc_full_type(acc_full_type) {}\n\n    virtual ~FliObj() = default;\n\n    int get_acc_type() { return m_acc_type; }\n    int get_acc_full_type() { return m_acc_full_type; }\n\n  protected:\n    int m_acc_type;\n    int m_acc_full_type;\n};\n\nclass FliObjHdl : public GpiObjHdl, public FliObj {\n  public:\n    FliObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype,\n              int acc_type, int acc_full_type, bool is_const = false)\n        : GpiObjHdl(impl, hdl, objtype, is_const),\n          FliObj(acc_type, acc_full_type) {}\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n};\n\nclass FliSignalObjHdl : public GpiSignalObjHdl, public FliObj {\n  public:\n    FliSignalObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype,\n                    bool is_const, int acc_type, int acc_full_type, bool is_var)\n        : GpiSignalObjHdl(impl, hdl, objtype, is_const),\n          FliObj(acc_type, acc_full_type),\n          m_is_var(is_var) {}\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n    GpiCbHdl *register_value_change_callback(gpi_edge edge,\n                                             int (*function)(void *),\n                                             void *cb_data) override;\n\n    bool is_variable() { return m_is_var; }\n\n  protected:\n    bool m_is_var;\n};\n\nclass FliValueObjHdl : public FliSignalObjHdl {\n  public:\n    FliValueObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype,\n                   bool is_const, int acc_type, int acc_full_type, bool is_var,\n                   mtiTypeIdT valType, mtiTypeKindT typeKind)\n        : FliSignalObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type,\n                          is_var),\n          m_fli_type(typeKind),\n          m_val_type(valType) {}\n\n    ~FliValueObjHdl() override {\n        if (m_val_buff != NULL) delete[] m_val_buff;\n        if (m_sub_hdls != NULL) mti_VsimFree(m_sub_hdls);\n    }\n\n    const char *get_signal_value_binstr() override;\n    const char *get_signal_value_str() override;\n    double get_signal_value_real() override;\n    long get_signal_value_long() override;\n\n    int set_signal_value(int32_t value, gpi_set_action action) override;\n    int set_signal_value(double value, gpi_set_action action) override;\n    int set_signal_value_str(std::string &value,\n                             gpi_set_action action) override;\n    int set_signal_value_binstr(std::string &value,\n                                gpi_set_action action) override;\n\n    void *get_sub_hdl(int index);\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n\n    mtiTypeKindT get_fli_typekind() { return m_fli_type; }\n    mtiTypeIdT get_fli_typeid() { return m_val_type; }\n\n  protected:\n    mtiTypeKindT m_fli_type;\n    mtiTypeIdT m_val_type;\n    char *m_val_buff = nullptr;\n    void **m_sub_hdls = nullptr;\n};\n\nclass FliEnumObjHdl : public FliValueObjHdl {\n  public:\n    FliEnumObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype,\n                  bool is_const, int acc_type, int acc_full_type, bool is_var,\n                  mtiTypeIdT valType, mtiTypeKindT typeKind)\n        : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type,\n                         is_var, valType, typeKind) {}\n\n    const char *get_signal_value_str() override;\n    long get_signal_value_long() override;\n\n    using FliValueObjHdl::set_signal_value;\n    int set_signal_value(int32_t value, gpi_set_action action) override;\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n\n  private:\n    char **m_value_enum = nullptr;  // Do Not Free\n    mtiInt32T m_num_enum = 0;\n};\n\nclass FliLogicObjHdl : public FliValueObjHdl {\n  public:\n    FliLogicObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype,\n                   bool is_const, int acc_type, int acc_full_type, bool is_var,\n                   mtiTypeIdT valType, mtiTypeKindT typeKind)\n        : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type,\n                         is_var, valType, typeKind) {}\n\n    ~FliLogicObjHdl() override {\n        if (m_mti_buff != NULL) delete[] m_mti_buff;\n    }\n\n    const char *get_signal_value_binstr() override;\n\n    using FliValueObjHdl::set_signal_value;\n    int set_signal_value(int32_t value, gpi_set_action action) override;\n    int set_signal_value_binstr(std::string &value,\n                                gpi_set_action action) override;\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n\n  private:\n    char *m_mti_buff = nullptr;\n    char **m_value_enum = nullptr;  // Do Not Free\n    mtiInt32T m_num_enum = 0;\n    std::map<char, mtiInt32T> m_enum_map;\n};\n\nclass FliIntObjHdl : public FliValueObjHdl {\n  public:\n    FliIntObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype,\n                 bool is_const, int acc_type, int acc_full_type, bool is_var,\n                 mtiTypeIdT valType, mtiTypeKindT typeKind)\n        : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type,\n                         is_var, valType, typeKind) {}\n\n    const char *get_signal_value_binstr() override;\n    long get_signal_value_long() override;\n    int get_signed() override {\n        // We don't know if the object is a Verilog object or VHDL object, but\n        // we assume that FLI is for VHDL accesses primarily and VHDL ints are\n        // always signed.\n        return 1;\n    }\n\n    using FliValueObjHdl::set_signal_value;\n    int set_signal_value(int32_t value, gpi_set_action action) override;\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n};\n\nclass FliRealObjHdl : public FliValueObjHdl {\n  public:\n    FliRealObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype,\n                  bool is_const, int acc_type, int acc_full_type, bool is_var,\n                  mtiTypeIdT valType, mtiTypeKindT typeKind)\n        : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type,\n                         is_var, valType, typeKind) {}\n\n    ~FliRealObjHdl() override {\n        if (m_mti_buff != NULL) delete m_mti_buff;\n    }\n\n    double get_signal_value_real() override;\n\n    using FliValueObjHdl::set_signal_value;\n    int set_signal_value(double value, gpi_set_action action) override;\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n\n  private:\n    double *m_mti_buff = nullptr;\n};\n\nclass FliStringObjHdl : public FliValueObjHdl {\n  public:\n    FliStringObjHdl(GpiImplInterface *impl, void *hdl, gpi_objtype objtype,\n                    bool is_const, int acc_type, int acc_full_type, bool is_var,\n                    mtiTypeIdT valType, mtiTypeKindT typeKind)\n        : FliValueObjHdl(impl, hdl, objtype, is_const, acc_type, acc_full_type,\n                         is_var, valType, typeKind) {}\n\n    ~FliStringObjHdl() override {\n        if (m_mti_buff != NULL) delete[] m_mti_buff;\n    }\n\n    const char *get_signal_value_str() override;\n\n    using FliValueObjHdl::set_signal_value;\n    int set_signal_value_str(std::string &value,\n                             gpi_set_action action) override;\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n\n  private:\n    char *m_mti_buff = nullptr;\n};\n\nclass FliIterator : public GpiIterator {\n  public:\n    enum OneToMany {\n        OTM_CONSTANTS,  // include Generics\n        OTM_SIGNALS,\n        OTM_REGIONS,\n        OTM_SIGNAL_SUB_ELEMENTS,\n        OTM_VARIABLE_SUB_ELEMENTS\n    };\n\n    FliIterator(GpiImplInterface *impl, GpiObjHdl *hdl);\n\n    Status next_handle(std::string &name, GpiObjHdl **hdl,\n                       void **raw_hdl) override;\n\n  private:\n    void populate_handle_list(OneToMany childType);\n\n  private:\n    static std::map<int, std::vector<OneToMany>>\n        iterate_over;                 /* Possible mappings */\n    std::vector<OneToMany> *selected; /* Mapping currently in use */\n    std::vector<OneToMany>::iterator one2many;\n\n    std::vector<void *> m_vars;\n    std::vector<void *> m_sigs;\n    std::vector<void *> m_regs;\n    std::vector<void *> *m_currentHandles;\n    std::vector<void *>::iterator m_iterator;\n};\n\nclass FliImpl : public GpiImplInterface {\n  public:\n    FliImpl(const std::string &name)\n        : GpiImplInterface(name),\n          m_timer_cache(this),\n          m_value_change_cache(this),\n          m_read_write_cache(this),\n          m_read_only_cache(this),\n          m_next_phase_cache(this) {}\n\n    /* Sim related */\n    void sim_end() override;\n    void get_sim_time(uint32_t *high, uint32_t *low) override;\n    void get_sim_precision(int32_t *precision) override;\n    const char *get_simulator_product() override;\n    const char *get_simulator_version() override;\n    int get_simulator_args(int *argc, const char *const **argv) override;\n\n    /* Hierarchy related */\n    GpiObjHdl *get_child_by_name(const std::string &name,\n                                 GpiObjHdl *parent) override;\n    GpiObjHdl *get_child_by_index(int32_t index, GpiObjHdl *parent) override;\n    GpiObjHdl *get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) override;\n    GpiObjHdl *get_root_handle(const char *name) override;\n    GpiIterator *iterate_handle(GpiObjHdl *obj_hdl,\n                                gpi_iterator_sel type) override;\n\n    /* Callback related, these may (will) return the same handle*/\n    GpiCbHdl *register_timed_callback(uint64_t time, int (*function)(void *),\n                                      void *cb_data) override;\n    GpiCbHdl *register_readonly_callback(int (*function)(void *),\n                                         void *cb_data) override;\n    GpiCbHdl *register_nexttime_callback(int (*function)(void *),\n                                         void *cb_data) override;\n    GpiCbHdl *register_readwrite_callback(int (*function)(void *),\n                                          void *cb_data) override;\n\n    /* Method to provide strings from operation types */\n    GpiObjHdl *create_gpi_obj_from_handle(void *hdl, const std::string &name,\n                                          const std::string &fq_name,\n                                          int accType, int accFullType);\n\n    static bool compare_generate_labels(const std::string &a,\n                                        const std::string &b);\n\n    void main() noexcept;\n\n  private:\n    bool isValueConst(int kind);\n    bool isValueLogic(mtiTypeIdT type);\n    bool isValueChar(mtiTypeIdT type);\n    bool isValueBoolean(mtiTypeIdT type);\n    bool isTypeValue(int type);\n    bool isTypeSignal(int type, int full_type);\n\n  private:\n    // We store the shutdown callback handle here so sim_end() can remove() it\n    // if it's called.\n    FliShutdownCbHdl *m_sim_finish_cb;\n\n    // Cache simulator info\n    std::string m_product;\n    std::string m_version;\n    int m_argc = 0;\n    std::vector<std::string> m_argv_storage;\n    char const **m_argv = nullptr;\n\n    // Caches for each type of callback handle. This must be associated with the\n    // FliImpl rather than be static member of the callback handle type because\n    // each callback handle is associated with an FliImpl.\n    // TODO remove the FliImpl association from the callback handle types then\n    // move these to static fields in the callback handle types.\n    FliProcessCbHdlCache<FliTimedCbHdl, MTI_PROC_IMMEDIATE> m_timer_cache;\n    FliProcessCbHdlCache<FliSignalCbHdl, MTI_PROC_NORMAL> m_value_change_cache;\n    FliProcessCbHdlCache<FliReadWriteCbHdl, MTI_PROC_SYNCH> m_read_write_cache;\n    FliProcessCbHdlCache<FliReadOnlyCbHdl, MTI_PROC_POSTPONED>\n        m_read_only_cache;\n    FliProcessCbHdlCache<FliNextPhaseCbHdl, MTI_PROC_IMMEDIATE>\n        m_next_phase_cache;\n    friend FliSignalObjHdl;\n    friend FliTimedCbHdl;\n    friend FliSignalCbHdl;\n    friend FliReadWriteCbHdl;\n    friend FliReadOnlyCbHdl;\n    friend FliNextPhaseCbHdl;\n};\n\n#endif /*COCOTB_FLI_IMPL_H_ */\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/fli/FliObjHdl.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2015/16 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <gpi.h>\n\n#include <bitset>\n#include <cmath>\n#include <cstring>\n#include <string>\n\n#include \"../logging.hpp\"\n#include \"./FliImpl.hpp\"\n#include \"_vendor/fli/acc_vhdl.h\"\n\nusing std::abs;\nusing std::to_string;\n\nGpiCbHdl *FliSignalObjHdl::register_value_change_callback(\n    gpi_edge edge, int (*cb_func)(void *), void *cb_data) {\n    if (m_is_var) {\n        return NULL;\n    }\n    // TODO The dynamic cast here is a good reason to not declare members in\n    // base classes.\n    auto &cache = dynamic_cast<FliImpl *>(m_impl)->m_value_change_cache;\n    auto cb = cache.acquire();\n    cb->set_signal_and_edge(this, edge);\n    auto err = cb->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        cache.release(cb);\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb->set_cb_info(cb_func, cb_data);\n    return cb;\n}\n\nint FliObjHdl::initialise(const std::string &name, const std::string &fq_name) {\n    bool is_signal =\n        (get_acc_type() == accSignal || get_acc_full_type() == accAliasSignal);\n    mtiTypeIdT typeId;\n    char *str;\n\n    switch (get_type()) {\n        case GPI_STRUCTURE:\n            if (is_signal) {\n                typeId = mti_GetSignalType(get_handle<mtiSignalIdT>());\n            } else {\n                typeId = mti_GetVarType(get_handle<mtiVariableIdT>());\n            }\n\n            m_num_elems = mti_GetNumRecordElements(typeId);\n            break;\n        case GPI_GENARRAY:\n            m_indexable = true;\n            // fall through\n        case GPI_MODULE:\n            m_num_elems = 1;\n            break;\n        default:\n            LOG_ERROR(\"Invalid object type for FliObjHdl. (%s (%s))\",\n                      name.c_str(), get_type_str());\n            return -1;\n    }\n\n    str = mti_GetPrimaryName(get_handle<mtiRegionIdT>());\n    if (str != NULL) m_definition_name = str;\n\n    str = mti_GetRegionSourceName(get_handle<mtiRegionIdT>());\n    if (str != NULL) m_definition_file = str;\n\n    return GpiObjHdl::initialise(name, fq_name);\n}\n\nint FliSignalObjHdl::initialise(const std::string &name,\n                                const std::string &fq_name) {\n    return GpiObjHdl::initialise(name, fq_name);\n}\n\nint FliValueObjHdl::initialise(const std::string &name,\n                               const std::string &fq_name) {\n    if (get_type() == GPI_ARRAY) {\n        m_range_left = mti_TickLeft(m_val_type);\n        m_range_right = mti_TickRight(m_val_type);\n        m_range_dir = static_cast<gpi_range_dir>(mti_TickDir(m_val_type));\n        m_num_elems = mti_TickLength(m_val_type);\n        m_indexable = true;\n    }\n\n    return FliSignalObjHdl::initialise(name, fq_name);\n}\n\nconst char *FliValueObjHdl::get_signal_value_binstr() {\n    LOG_ERROR(\n        \"Getting signal/variable value as binstr not supported for %s of type \"\n        \"%d\",\n        m_fullname.c_str(), m_type);\n    return NULL;\n}\n\nconst char *FliValueObjHdl::get_signal_value_str() {\n    LOG_ERROR(\n        \"Getting signal/variable value as str not supported for %s of type %d\",\n        m_fullname.c_str(), m_type);\n    return NULL;\n}\n\ndouble FliValueObjHdl::get_signal_value_real() {\n    LOG_ERROR(\n        \"Getting signal/variable value as double not supported for %s of type \"\n        \"%d\",\n        m_fullname.c_str(), m_type);\n    return -1;\n}\n\nlong FliValueObjHdl::get_signal_value_long() {\n    LOG_ERROR(\n        \"Getting signal/variable value as long not supported for %s of type %d\",\n        m_fullname.c_str(), m_type);\n    return -1;\n}\n\nint FliValueObjHdl::set_signal_value(int32_t, gpi_set_action) {\n    LOG_ERROR(\n        \"Setting signal/variable value via int32_t not supported for %s of \"\n        \"type %d\",\n        m_fullname.c_str(), m_type);\n    return -1;\n}\n\nint FliValueObjHdl::set_signal_value_binstr(std::string &, gpi_set_action) {\n    LOG_ERROR(\n        \"Setting signal/variable value via string not supported for %s of type \"\n        \"%d\",\n        m_fullname.c_str(), m_type);\n    return -1;\n}\n\nint FliValueObjHdl::set_signal_value_str(std::string &, gpi_set_action) {\n    LOG_ERROR(\n        \"Setting signal/variable value via string not supported for %s of type \"\n        \"%d\",\n        m_fullname.c_str(), m_type);\n    return -1;\n}\n\nint FliValueObjHdl::set_signal_value(double, gpi_set_action) {\n    LOG_ERROR(\n        \"Setting signal/variable value via double not supported for %s of type \"\n        \"%d\",\n        m_fullname.c_str(), m_type);\n    return -1;\n}\n\nvoid *FliValueObjHdl::get_sub_hdl(int index) {\n    if (!m_indexable) return NULL;\n\n    if (m_sub_hdls == NULL) {\n        if (m_is_var) {\n            m_sub_hdls = (void **)mti_GetVarSubelements(\n                get_handle<mtiVariableIdT>(), NULL);\n        } else {\n            m_sub_hdls = (void **)mti_GetSignalSubelements(\n                get_handle<mtiSignalIdT>(), NULL);\n        }\n    }\n\n    int idx;\n\n    if (m_range_left > m_range_right) {\n        idx = m_range_left - index;\n    } else {\n        idx = index - m_range_left;\n    }\n\n    if (idx < 0 || idx >= m_num_elems)\n        return NULL;\n    else\n        return m_sub_hdls[idx];\n}\n\nint FliEnumObjHdl::initialise(const std::string &name,\n                              const std::string &fq_name) {\n    m_num_elems = 1;\n    m_value_enum = mti_GetEnumValues(m_val_type);\n    m_num_enum = mti_TickLength(m_val_type);\n\n    return FliValueObjHdl::initialise(name, fq_name);\n}\n\nconst char *FliEnumObjHdl::get_signal_value_str() {\n    if (m_is_var) {\n        return m_value_enum[mti_GetVarValue(get_handle<mtiVariableIdT>())];\n    } else {\n        return m_value_enum[mti_GetSignalValue(get_handle<mtiSignalIdT>())];\n    }\n}\n\nlong FliEnumObjHdl::get_signal_value_long() {\n    if (m_is_var) {\n        return (long)mti_GetVarValue(get_handle<mtiVariableIdT>());\n    } else {\n        return (long)mti_GetSignalValue(get_handle<mtiSignalIdT>());\n    }\n}\n\nint FliEnumObjHdl::set_signal_value(const int32_t value,\n                                    const gpi_set_action action) {\n    if (value > m_num_enum || value < 0) {\n        LOG_ERROR(\n            \"Attempted to set an enum with range [0,%d] with invalid value %d!\",\n            m_num_enum, value);\n        return -1;\n    }\n\n    if (m_is_var) {\n        switch (action) {\n            case GPI_DEPOSIT:\n            case GPI_NO_DELAY:\n                mti_SetVarValue(get_handle<mtiVariableIdT>(),\n                                static_cast<mtiLongT>(value));\n                return 0;\n            case GPI_FORCE:\n                LOG_ERROR(\"Forcing VHDL variables is not supported by the FLI\");\n                return -1;\n            case GPI_RELEASE:\n                LOG_ERROR(\n                    \"Releasing VHDL variables is not supported by the FLI\");\n                return -1;\n            default:\n                LOG_ERROR(\"Unknown set value action (%d)\", action);\n                return -1;\n        }\n    } else {\n        switch (action) {\n            case GPI_DEPOSIT:\n            case GPI_NO_DELAY:\n                mti_SetSignalValue(get_handle<mtiSignalIdT>(),\n                                   static_cast<mtiLongT>(value));\n                return 0;\n            case GPI_FORCE: {\n                std::string value_str = \"10#\";\n                value_str.append(to_string(abs(value)));\n                return !mti_ForceSignal(get_handle<mtiSignalIdT>(),\n                                        const_cast<char *>(value_str.c_str()),\n                                        0, MTI_FORCE_FREEZE, -1, -1);\n            }\n            case GPI_RELEASE:\n                return !mti_ReleaseSignal(get_handle<mtiSignalIdT>());\n            default:\n                LOG_ERROR(\"Unknown set value action (%d)\", action);\n                return -1;\n        }\n    }\n}\n\nint FliLogicObjHdl::initialise(const std::string &name,\n                               const std::string &fq_name) {\n    switch (m_fli_type) {\n        case MTI_TYPE_ENUM:\n            m_num_elems = 1;\n            m_value_enum = mti_GetEnumValues(m_val_type);\n            m_num_enum = mti_TickLength(m_val_type);\n            break;\n        case MTI_TYPE_ARRAY: {\n            mtiTypeIdT elemType = mti_GetArrayElementType(m_val_type);\n\n            m_range_left = mti_TickLeft(m_val_type);\n            m_range_right = mti_TickRight(m_val_type);\n            m_range_dir = static_cast<gpi_range_dir>(mti_TickDir(m_val_type));\n            m_num_elems = mti_TickLength(m_val_type);\n            m_indexable = true;\n\n            m_value_enum = mti_GetEnumValues(elemType);\n            m_num_enum = mti_TickLength(elemType);\n\n            m_mti_buff = new char[m_num_elems + 1];\n        } break;\n        default:\n            LOG_ERROR(\"Object type is not 'logic' for %s (%d)\", name.c_str(),\n                      m_fli_type);\n            return -1;\n    }\n\n    for (mtiInt32T i = 0; i < m_num_enum; i++) {\n        m_enum_map[m_value_enum[i][1]] =\n            i;  // enum is of the format 'U' or '0', etc.\n    }\n\n    m_val_buff = new char[m_num_elems + 1];\n    m_val_buff[m_num_elems] = '\\0';\n\n    return FliValueObjHdl::initialise(name, fq_name);\n}\n\nconst char *FliLogicObjHdl::get_signal_value_binstr() {\n    switch (m_fli_type) {\n        case MTI_TYPE_ENUM:\n            if (m_is_var) {\n                m_val_buff[0] =\n                    m_value_enum[mti_GetVarValue(get_handle<mtiVariableIdT>())]\n                                [1];\n            } else {\n                m_val_buff[0] =\n                    m_value_enum[mti_GetSignalValue(get_handle<mtiSignalIdT>())]\n                                [1];\n            }\n            break;\n        case MTI_TYPE_ARRAY: {\n            if (m_is_var) {\n                mti_GetArrayVarValue(get_handle<mtiVariableIdT>(), m_mti_buff);\n            } else {\n                mti_GetArraySignalValue(get_handle<mtiSignalIdT>(), m_mti_buff);\n            }\n\n            for (int i = 0; i < m_num_elems; i++) {\n                m_val_buff[i] = m_value_enum[(int)m_mti_buff[i]][1];\n            }\n        } break;\n        default:\n            LOG_ERROR(\"Object type is not 'logic' for %s (%d)\", m_name.c_str(),\n                      m_fli_type);\n            return NULL;\n    }\n\n    LOG_DEBUG(\"Retrieved \\\"%s\\\" for value object %s\", m_val_buff,\n              m_name.c_str());\n\n    return m_val_buff;\n}\n\nint FliLogicObjHdl::set_signal_value(const int32_t value,\n                                     const gpi_set_action action) {\n    if (m_fli_type == MTI_TYPE_ENUM) {\n        mtiInt32T enumVal = value ? m_enum_map['1'] : m_enum_map['0'];\n\n        if (m_is_var) {\n            switch (action) {\n                case GPI_DEPOSIT:\n                case GPI_NO_DELAY:\n                    mti_SetVarValue(get_handle<mtiVariableIdT>(), enumVal);\n                    return 0;\n                case GPI_FORCE:\n                    LOG_ERROR(\n                        \"Forcing VHDL variables is not supported by the FLI\");\n                    return -1;\n                case GPI_RELEASE:\n                    LOG_ERROR(\n                        \"Releasing VHDL variables is not supported by the FLI\");\n                    return -1;\n                default:\n                    LOG_ERROR(\"Unknown set value action (%d)\", action);\n                    return -1;\n            }\n        } else {\n            switch (action) {\n                case GPI_DEPOSIT:\n                case GPI_NO_DELAY:\n                    mti_SetSignalValue(get_handle<mtiSignalIdT>(), enumVal);\n                    return 0;\n                case GPI_FORCE: {\n                    char const *value_str = (value ? \"2#1\" : \"2#0\");\n                    return !mti_ForceSignal(get_handle<mtiSignalIdT>(),\n                                            const_cast<char *>(value_str), 0,\n                                            MTI_FORCE_FREEZE, -1, -1);\n                }\n                case GPI_RELEASE:\n                    return !mti_ReleaseSignal(get_handle<mtiSignalIdT>());\n                default:\n                    LOG_ERROR(\"Unknown set value action (%d)\", action);\n                    return -1;\n            }\n        }\n    } else {\n        for (int i = 0, idx = m_num_elems - 1; i < m_num_elems; i++, idx--) {\n            mtiInt32T enumVal =\n                value & (1 << i) ? m_enum_map['1'] : m_enum_map['0'];\n\n            m_mti_buff[idx] = (char)enumVal;\n        }\n\n        if (m_is_var) {\n            switch (action) {\n                case GPI_DEPOSIT:\n                case GPI_NO_DELAY:\n                    mti_SetVarValue(get_handle<mtiVariableIdT>(),\n                                    (mtiLongT)m_mti_buff);\n                    return 0;\n                case GPI_FORCE:\n                    LOG_ERROR(\n                        \"Forcing VHDL variables is not supported by the FLI\");\n                    return -1;\n                case GPI_RELEASE:\n                    LOG_ERROR(\n                        \"Releasing VHDL variables is not supported by the FLI\");\n                    return -1;\n                default:\n                    LOG_ERROR(\"Unknown set value action (%d)\", action);\n                    return -1;\n            }\n        } else {\n            switch (action) {\n                case GPI_DEPOSIT:\n                case GPI_NO_DELAY:\n                    mti_SetSignalValue(get_handle<mtiSignalIdT>(),\n                                       (mtiLongT)m_mti_buff);\n                    return 0;\n                case GPI_FORCE: {\n                    std::string value_str = \"2#\";\n                    for (int idx = m_num_elems - 1; idx >= 0; idx--) {\n                        value_str.append((value & (1 << idx)) ? \"1\" : \"0\");\n                    }\n                    return !mti_ForceSignal(\n                        get_handle<mtiSignalIdT>(),\n                        const_cast<char *>(value_str.c_str()), 0,\n                        MTI_FORCE_FREEZE, -1, -1);\n                }\n                case GPI_RELEASE:\n                    return !mti_ReleaseSignal(get_handle<mtiSignalIdT>());\n                default:\n                    LOG_ERROR(\"Unknown set value action (%d)\", action);\n                    return -1;\n            }\n        }\n    }\n}\n\nint FliLogicObjHdl::set_signal_value_binstr(std::string &value,\n                                            const gpi_set_action action) {\n    if (m_fli_type == MTI_TYPE_ENUM) {\n        if (value.length() != 1) {\n            LOG_ERROR(\n                \"FLI: Unable to set logic vector due to the string having \"\n                \"incorrect length. Length of %d needs to be 1\",\n                value.length());\n            return -1;\n        }\n        mtiInt32T enumVal = m_enum_map[value.c_str()[0]];\n\n        if (m_is_var) {\n            switch (action) {\n                case GPI_DEPOSIT:\n                case GPI_NO_DELAY:\n                    mti_SetVarValue(get_handle<mtiVariableIdT>(), enumVal);\n                    return 0;\n                case GPI_FORCE:\n                    LOG_ERROR(\n                        \"Forcing VHDL variables is not supported by the FLI\");\n                    return -1;\n                case GPI_RELEASE:\n                    LOG_ERROR(\n                        \"Releasing VHDL variables is not supported by the FLI\");\n                    return -1;\n                default:\n                    LOG_ERROR(\"Unknown set value action (%d)\", action);\n                    return -1;\n            }\n        } else {\n            switch (action) {\n                case GPI_DEPOSIT:\n                case GPI_NO_DELAY:\n                    mti_SetSignalValue(get_handle<mtiSignalIdT>(), enumVal);\n                    return 0;\n                case GPI_FORCE: {\n                    std::string value_str = \"2#\";\n                    value_str.append(value);\n                    return !mti_ForceSignal(\n                        get_handle<mtiSignalIdT>(),\n                        const_cast<char *>(value_str.c_str()), 0,\n                        MTI_FORCE_FREEZE, -1, -1);\n                }\n                case GPI_RELEASE:\n                    return !mti_ReleaseSignal(get_handle<mtiSignalIdT>());\n                default:\n                    LOG_ERROR(\"Unknown set value action (%d)\", action);\n                    return -1;\n            }\n        }\n    } else {\n        if ((int)value.length() != m_num_elems) {\n            LOG_ERROR(\n                \"FLI: Unable to set logic vector due to the string having \"\n                \"incorrect length.  Length of %d needs to be %d\",\n                value.length(), m_num_elems);\n            return -1;\n        }\n\n        int i = 0;\n\n        for (auto valIter = value.begin();\n             (valIter != value.end()) && (i < m_num_elems); valIter++, i++) {\n            auto enumVal = m_enum_map[*valIter];\n            m_mti_buff[i] = (char)enumVal;\n        }\n\n        if (m_is_var) {\n            switch (action) {\n                case GPI_DEPOSIT:\n                case GPI_NO_DELAY:\n                    mti_SetVarValue(get_handle<mtiVariableIdT>(),\n                                    (mtiLongT)m_mti_buff);\n                    return 0;\n                case GPI_FORCE:\n                    LOG_ERROR(\n                        \"Forcing VHDL variables is not supported by the FLI\");\n                    return -1;\n                case GPI_RELEASE:\n                    LOG_ERROR(\n                        \"Releasing VHDL variables is not supported by the FLI\");\n                    return -1;\n                default:\n                    LOG_ERROR(\"Unknown set value action (%d)\", action);\n                    return -1;\n            }\n        } else {\n            switch (action) {\n                case GPI_DEPOSIT:\n                case GPI_NO_DELAY:\n                    mti_SetSignalValue(get_handle<mtiSignalIdT>(),\n                                       (mtiLongT)m_mti_buff);\n                    return 0;\n                case GPI_FORCE: {\n                    std::string value_str = \"2#\";\n                    value_str.append(value);\n                    return !mti_ForceSignal(\n                        get_handle<mtiSignalIdT>(),\n                        const_cast<char *>(value_str.c_str()), 0,\n                        MTI_FORCE_FREEZE, -1, -1);\n                }\n                case GPI_RELEASE:\n                    return !mti_ReleaseSignal(get_handle<mtiSignalIdT>());\n                default:\n                    LOG_ERROR(\"Unknown set value action (%d)\", action);\n                    return -1;\n            }\n        }\n    }\n}\n\nint FliIntObjHdl::initialise(const std::string &name,\n                             const std::string &fq_name) {\n    // We are assuming integers are always 32-bits\n    // TODO handle VHDL-2019 64-bit integers at some point.\n    m_num_elems = 32;\n    m_val_buff = new char[33];\n    m_val_buff[m_num_elems] = '\\0';\n\n    return FliValueObjHdl::initialise(name, fq_name);\n}\n\nconst char *FliIntObjHdl::get_signal_value_binstr() {\n    mtiInt32T val;\n\n    if (m_is_var) {\n        val = mti_GetVarValue(get_handle<mtiVariableIdT>());\n    } else {\n        val = mti_GetSignalValue(get_handle<mtiSignalIdT>());\n    }\n\n    unsigned long tmp = static_cast<unsigned long>(\n        val);  // only way to keep next line from warning\n    std::bitset<32> value{tmp};\n    std::string bin_str = value.to_string<char, std::string::traits_type,\n                                          std::string::allocator_type>();\n    snprintf(m_val_buff, 33, \"%s\", bin_str.c_str());\n\n    return m_val_buff;\n}\n\nlong FliIntObjHdl::get_signal_value_long() {\n    mtiInt32T value;\n\n    if (m_is_var) {\n        value = mti_GetVarValue(get_handle<mtiVariableIdT>());\n    } else {\n        value = mti_GetSignalValue(get_handle<mtiSignalIdT>());\n    }\n\n    return (long)value;\n}\n\nint FliIntObjHdl::set_signal_value(const int32_t value,\n                                   const gpi_set_action action) {\n    if (m_is_var) {\n        switch (action) {\n            case GPI_DEPOSIT:\n            case GPI_NO_DELAY:\n                mti_SetVarValue(get_handle<mtiVariableIdT>(),\n                                static_cast<mtiLongT>(value));\n                return 0;\n            case GPI_FORCE:\n                LOG_ERROR(\"Forcing VHDL variables is not supported by the FLI\");\n                return -1;\n            case GPI_RELEASE:\n                LOG_ERROR(\n                    \"Releasing VHDL variables is not supported by the FLI\");\n                return -1;\n            default:\n                LOG_ERROR(\"Unknown set value action (%d)\", action);\n                return -1;\n        }\n    } else {\n        switch (action) {\n            case GPI_DEPOSIT:\n            case GPI_NO_DELAY:\n                mti_SetSignalValue(get_handle<mtiSignalIdT>(),\n                                   static_cast<mtiLongT>(value));\n                return 0;\n            case GPI_FORCE: {\n                std::string value_str;\n                if (value < 0) {\n                    value_str.append(\"-\");\n                }\n                value_str.append(\"10#\");\n                value_str.append(to_string(abs(value)));\n                return !mti_ForceSignal(get_handle<mtiSignalIdT>(),\n                                        const_cast<char *>(value_str.c_str()),\n                                        0, MTI_FORCE_FREEZE, -1, -1);\n            }\n            case GPI_RELEASE:\n                return !mti_ReleaseSignal(get_handle<mtiSignalIdT>());\n            default:\n                LOG_ERROR(\"Unknown set value action (%d)\", action);\n                return -1;\n        }\n    }\n}\n\nint FliRealObjHdl::initialise(const std::string &name,\n                              const std::string &fq_name) {\n    m_num_elems = 1;\n\n    m_mti_buff = new double;\n\n    return FliValueObjHdl::initialise(name, fq_name);\n}\n\ndouble FliRealObjHdl::get_signal_value_real() {\n    if (m_is_var) {\n        mti_GetVarValueIndirect(get_handle<mtiVariableIdT>(), m_mti_buff);\n    } else {\n        mti_GetSignalValueIndirect(get_handle<mtiSignalIdT>(), m_mti_buff);\n    }\n\n    LOG_DEBUG(\"Retrieved \\\"%f\\\" for value object %s\", m_mti_buff[0],\n              m_name.c_str());\n\n    return m_mti_buff[0];\n}\n\nint FliRealObjHdl::set_signal_value(const double value,\n                                    const gpi_set_action action) {\n    m_mti_buff[0] = value;\n\n    if (m_is_var) {\n        switch (action) {\n            case GPI_DEPOSIT:\n            case GPI_NO_DELAY:\n                mti_SetVarValue(get_handle<mtiVariableIdT>(),\n                                (mtiLongT)m_mti_buff);\n                return 0;\n            case GPI_FORCE:\n                LOG_ERROR(\"Forcing VHDL variables is not supported by the FLI\");\n                return -1;\n            case GPI_RELEASE:\n                LOG_ERROR(\n                    \"Releasing VHDL variables is not supported by the FLI\");\n                return -1;\n            default:\n                LOG_ERROR(\"Unknown set value action (%d)\", action);\n                return -1;\n        }\n    } else {\n        switch (action) {\n            case GPI_DEPOSIT:\n            case GPI_NO_DELAY:\n                mti_SetSignalValue(get_handle<mtiSignalIdT>(),\n                                   (mtiLongT)m_mti_buff);\n                return 0;\n            case GPI_FORCE: {\n                LOG_ERROR(\"Cannot force a real signal with the FLI\");\n                return -1;\n            }\n            case GPI_RELEASE:\n                mti_ReleaseSignal(get_handle<mtiSignalIdT>());\n                return 0;\n            default:\n                LOG_ERROR(\"Unknown set value action (%d)\", action);\n                return -1;\n        }\n    }\n}\n\nint FliStringObjHdl::initialise(const std::string &name,\n                                const std::string &fq_name) {\n    m_range_left = mti_TickLeft(m_val_type);\n    m_range_right = mti_TickRight(m_val_type);\n    m_range_dir = static_cast<gpi_range_dir>(mti_TickDir(m_val_type));\n    m_num_elems = mti_TickLength(m_val_type);\n    m_indexable = true;\n\n    m_mti_buff = new char[m_num_elems];\n\n    m_val_buff = new char[m_num_elems + 1];\n    m_val_buff[m_num_elems] = '\\0';\n\n    return FliValueObjHdl::initialise(name, fq_name);\n}\n\nconst char *FliStringObjHdl::get_signal_value_str() {\n    if (m_is_var) {\n        mti_GetArrayVarValue(get_handle<mtiVariableIdT>(), m_mti_buff);\n    } else {\n        mti_GetArraySignalValue(get_handle<mtiSignalIdT>(), m_mti_buff);\n    }\n\n    strncpy(m_val_buff, m_mti_buff, static_cast<size_t>(m_num_elems));\n\n    LOG_DEBUG(\"Retrieved \\\"%s\\\" for value object %s\", m_val_buff,\n              m_name.c_str());\n\n    return m_val_buff;\n}\n\nint FliStringObjHdl::set_signal_value_str(std::string &value,\n                                          const gpi_set_action action) {\n    strncpy(m_mti_buff, value.c_str(), static_cast<size_t>(m_num_elems));\n\n    if (m_is_var) {\n        switch (action) {\n            case GPI_DEPOSIT:\n            case GPI_NO_DELAY:\n                mti_SetVarValue(get_handle<mtiVariableIdT>(),\n                                (mtiLongT)m_mti_buff);\n                return 0;\n            case GPI_FORCE:\n                LOG_ERROR(\"Forcing VHDL variables is not supported by the FLI\");\n                return -1;\n            case GPI_RELEASE:\n                LOG_ERROR(\n                    \"Releasing VHDL variables is not supported by the FLI\");\n                return -1;\n            default:\n                LOG_ERROR(\"Unknown set value action (%d)\", action);\n                return -1;\n        }\n    } else {\n        switch (action) {\n            case GPI_DEPOSIT:\n            case GPI_NO_DELAY:\n                mti_SetSignalValue(get_handle<mtiSignalIdT>(),\n                                   (mtiLongT)m_mti_buff);\n                return 0;\n            case GPI_FORCE: {\n                return !mti_ForceSignal(get_handle<mtiSignalIdT>(),\n                                        const_cast<char *>(value.c_str()), 0,\n                                        MTI_FORCE_FREEZE, -1, -1);\n            }\n            case GPI_RELEASE:\n                return !mti_ReleaseSignal(get_handle<mtiSignalIdT>());\n            default:\n                LOG_ERROR(\"Unknown set value action (%d)\", action);\n                return -1;\n        }\n    }\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/gpi_priv.hpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#ifndef COCOTB_GPI_PRIV_H_\n#define COCOTB_GPI_PRIV_H_\n\n#include <exports.h>\n#include <gpi.h>\n\n#include <string>\n\n#include \"../utils.hpp\"  // xstr\n\n#ifdef GPI_EXPORTS\n#define GPI_EXPORT COCOTB_EXPORT\n#else\n#define GPI_EXPORT COCOTB_IMPORT\n#endif\n\nclass GpiCbHdl;\nclass GpiImplInterface;\nclass GpiIterator;\nclass GpiCbHdl;\n\n/* Base GPI class others are derived from */\nclass GPI_EXPORT GpiHdl {\n  public:\n    GpiHdl(GpiImplInterface *impl, void *hdl = NULL)\n        : m_impl(impl), m_obj_hdl(hdl) {}\n    virtual ~GpiHdl() = default;\n\n    template <typename T>\n    T get_handle() const {\n        return static_cast<T>(m_obj_hdl);\n    }\n\n  private:\n    GpiHdl() {}  // Disable default constructor\n\n  public:\n    GpiImplInterface *m_impl;                   // VPI/VHPI/FLI routines\n    bool is_this_impl(GpiImplInterface *impl);  // Is the passed interface the\n                                                // one this object uses?\n\n  protected:\n    void *m_obj_hdl;\n};\n\n/* GPI object handle, maps to a simulation object */\n// An object is any item in the hierarchy\n// Provides methods for iterating through children or finding by name\n// Initial object is returned by call to GpiImplInterface::get_root_handle()\n// Subsequent operations to get children go through this handle.\n// GpiObjHdl::get_handle_by_name/get_handle_by_index are really factories\n// that construct an object derived from GpiSignalObjHdl or GpiObjHdl\nclass GPI_EXPORT GpiObjHdl : public GpiHdl {\n  public:\n    GpiObjHdl(GpiImplInterface *impl, void *hdl = nullptr,\n              gpi_objtype objtype = GPI_UNKNOWN, bool is_const = false)\n        : GpiHdl(impl, hdl), m_type(objtype), m_const(is_const) {}\n\n    virtual ~GpiObjHdl() = default;\n\n    // TODO why do these even exist? Just return the string by ref and call\n    // c_str.\n    virtual const char *get_name_str();\n    virtual const char *get_fullname_str();\n    virtual const char *get_type_str();\n    gpi_objtype get_type() { return m_type; };\n    bool get_const() { return m_const; };\n    int get_num_elems() { return m_num_elems; }\n    int get_range_left() { return m_range_left; }\n    int get_range_right() { return m_range_right; }\n    gpi_range_dir get_range_dir() { return m_range_dir; }\n    int get_indexable() { return m_indexable; }\n    virtual int get_signed() { return -1; }\n\n    const std::string &get_name();\n    const std::string &get_fullname();\n\n    virtual const char *get_definition_name() {\n        return m_definition_name.c_str();\n    };\n    virtual const char *get_definition_file() {\n        return m_definition_file.c_str();\n    };\n\n    bool is_native_impl(GpiImplInterface *impl);\n    virtual int initialise(const std::string &name,\n                           const std::string &full_name);\n\n  protected:\n    int m_num_elems = 0;\n    bool m_indexable = false;\n    int m_range_left = -1;\n    int m_range_right = -1;\n    gpi_range_dir m_range_dir = GPI_RANGE_NO_DIR;\n    std::string m_name = \"unknown\";\n    std::string m_fullname = \"unknown\";\n\n    std::string m_definition_name;\n    std::string m_definition_file;\n\n    gpi_objtype m_type;\n    bool m_const;\n};\n\n/* GPI Signal object handle, maps to a simulation object */\n//\n// Identical to an object but adds additional methods for getting/setting the\n// value of the signal (which doesn't apply to non signal items in the hierarchy\nclass GPI_EXPORT GpiSignalObjHdl : public GpiObjHdl {\n  public:\n    using GpiObjHdl::GpiObjHdl;\n\n    virtual ~GpiSignalObjHdl() = default;\n    // Provide public access to the implementation (composition vs inheritance)\n    virtual const char *get_signal_value_binstr() = 0;\n    virtual const char *get_signal_value_str() = 0;\n    virtual double get_signal_value_real() = 0;\n    virtual long get_signal_value_long() = 0;\n\n    int m_length = 0;\n\n    virtual int set_signal_value(const int32_t value,\n                                 gpi_set_action action) = 0;\n    virtual int set_signal_value(const double value, gpi_set_action action) = 0;\n    virtual int set_signal_value_str(std::string &value,\n                                     gpi_set_action action) = 0;\n    virtual int set_signal_value_binstr(std::string &value,\n                                        gpi_set_action action) = 0;\n    // virtual GpiCbHdl monitor_value(bool rising_edge) = 0; this was for the\n    // triggers\n    // but the explicit ones are probably better\n\n    virtual GpiCbHdl *register_value_change_callback(\n        gpi_edge edge, int (*gpi_function)(void *), void *gpi_cb_data) = 0;\n};\n\n/* GPI Callback handle */\n// To set a callback it needs the signal to do this on,\n// vpiHandle/vhpiHandleT for instance. The\nclass GPI_EXPORT GpiCbHdl : public GpiHdl {\n  public:\n    GpiCbHdl() = delete;\n    GpiCbHdl(GpiImplInterface *impl) : GpiHdl(impl) {}\n\n    // TODO Some of these routines don't need to be declared here. Only remove()\n    // and get_cb_info() need to. In fact, declaring these here means we can't\n    // do things like pass arguments to arm().\n\n    /** Set user callback info\n     *\n     * Not on init to prevent having to pass around the arguments everywhere.\n     * Secondary initialization routine. ONLY CALL ONCE!\n     */\n    void set_cb_info(int (*cb_func)(void *), void *cb_data) noexcept {\n        this->m_cb_func = cb_func;\n        this->m_cb_data = cb_data;\n    }\n\n    /** Get the current user callback function and data. */\n    void get_cb_info(int (**cb_func)(void *), void **cb_data) noexcept {\n        if (cb_func) {\n            *cb_func = m_cb_func;\n        }\n        if (cb_data) {\n            *cb_data = m_cb_data;\n        }\n    }\n\n    /** Arm the callback after construction.\n     *\n     * Calling virtual functions from constructors does not work as expected.\n     * Secondary initialization routine. ONLY CALL ONCE!\n     */\n    virtual int arm() = 0;\n\n    /** Remove the callback before it fires.\n     *\n     * This function should delete the object.\n     */\n    virtual int remove() = 0;\n\n    /** Run the callback.\n     *\n     * This function should delete the object if it can't fire again.\n     */\n    virtual int run() = 0;\n\n  protected:\n    int (*m_cb_func)(void *);  // GPI function to callback\n    void *m_cb_data;           // GPI data supplied to \"m_cb_func\"\n};\n\nclass GPI_EXPORT GpiIterator : public GpiHdl {\n  public:\n    enum Status {\n        NATIVE,          // Fully resolved object was created\n        NATIVE_NO_NAME,  // Native object was found but unable to fully create\n        NOT_NATIVE,      // Non-native object was found but we did get a name\n        NOT_NATIVE_NO_NAME,  // Non-native object was found without a name\n        END\n    };\n\n    GpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl)\n        : GpiHdl(impl), m_parent(hdl) {}\n    virtual ~GpiIterator() = default;\n\n    virtual Status next_handle(std::string &name, GpiObjHdl **hdl, void **) {\n        name = \"\";\n        *hdl = NULL;\n        return GpiIterator::END;\n    }\n\n    GpiObjHdl *get_parent() { return m_parent; }\n\n  protected:\n    GpiObjHdl *m_parent;\n};\n\nclass GPI_EXPORT GpiImplInterface {\n  public:\n    GpiImplInterface(const std::string &name) : m_name(name) {}\n    const char *get_name_c();\n    const std::string &get_name_s();\n    virtual ~GpiImplInterface() = default;\n\n    /* Sim related */\n    virtual void sim_end() = 0;\n    virtual void get_sim_time(uint32_t *high, uint32_t *low) = 0;\n    virtual void get_sim_precision(int32_t *precision) = 0;\n    virtual const char *get_simulator_product() = 0;\n    virtual const char *get_simulator_version() = 0;\n    virtual int get_simulator_args(int *argc, char const *const **argv) = 0;\n\n    /* Hierarchy related */\n    virtual GpiObjHdl *get_child_by_name(const std::string &name,\n                                         GpiObjHdl *parent) = 0;\n    virtual GpiObjHdl *get_child_by_index(int32_t index, GpiObjHdl *parent) = 0;\n    virtual GpiObjHdl *get_child_from_handle(void *raw_hdl,\n                                             GpiObjHdl *parent) = 0;\n    virtual GpiObjHdl *get_root_handle(const char *name) = 0;\n    virtual GpiIterator *iterate_handle(GpiObjHdl *obj_hdl,\n                                        gpi_iterator_sel type) = 0;\n\n    /* Callback related, these may (will) return the same handle */\n    virtual GpiCbHdl *register_timed_callback(uint64_t time,\n                                              int (*gpi_function)(void *),\n                                              void *gpi_cb_data) = 0;\n    virtual GpiCbHdl *register_readonly_callback(int (*gpi_function)(void *),\n                                                 void *gpi_cb_data) = 0;\n    virtual GpiCbHdl *register_nexttime_callback(int (*gpi_function)(void *),\n                                                 void *gpi_cb_data) = 0;\n    virtual GpiCbHdl *register_readwrite_callback(int (*gpi_function)(void *),\n                                                  void *gpi_cb_data) = 0;\n\n  private:\n    std::string m_name;\n};\n\n/* Called from implementation layers back up the stack */\nGPI_EXPORT int gpi_register_impl(GpiImplInterface *func_tbl);\n\n// GpiImpls are currently expected to register single callbacks with the\n// interface for the start and end of simulation time. These functions are\n// called by the GpiImpls. The GPI layer will do the callback muxing.\nGPI_EXPORT void gpi_start_of_sim_time();\nGPI_EXPORT void gpi_end_of_sim_time();\n\nGPI_EXPORT void gpi_entry_point();\nGPI_EXPORT void gpi_check_cleanup();\nGPI_EXPORT bool gpi_is_finalizing();\nGPI_EXPORT void gpi_init_logging_and_debug();\n\nvoid *utils_dyn_open(const char *lib_name);\nvoid *utils_dyn_sym(void *handle, const char *sym_name);\n\n#define GPI_TO_USER_CB(impl) LOG_TRACE(\"[ \" xstr(impl) \" ] => User Callback\")\n\n#define USER_CB_TO_GPI(impl) LOG_TRACE(\"User Callback => [ \" xstr(impl) \" ]\")\n\n#define SIM_TO_GPI(impl, ptr, cb_reason) \\\n    LOG_TRACE(\"Sim => [ \" xstr(impl) \" %p for %s ]\", ptr, cb_reason)\n\n#define GPI_TO_SIM(impl, ptr)                           \\\n    do {                                                \\\n        gpi_check_cleanup();                            \\\n        LOG_TRACE(\"[ \" xstr(impl) \" %p ] => Sim\", ptr); \\\n    } while (0)\n\ntypedef void (*layer_entry_func)();\n\n/* Use this macro in an implementation layer to define an entry point */\n#define GPI_ENTRY_POINT(NAME, func)                     \\\n    extern \"C\" {                                        \\\n    COCOTB_EXPORT void NAME##_entry_point() { func(); } \\\n    }\n\n#endif /* COCOTB_GPI_PRIV_H_ */\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/logging.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include \"./logging.hpp\"\n\n#include <gpi.h>\n\n#include <cstdarg>\n#include <cstdio>\n#include <cstring>\n#include <map>\n#include <vector>\n\n#include \"../utils.hpp\"  // DEFER\n\n/*******************************************************************************\n * GPI Internal API\n *******************************************************************************/\n\nint gpi_debug_enabled = 0;\n\nstatic int current_native_logger_level = GPI_NOTSET;\n\nstatic void gpi_native_logger_vlog(void *, const char *name,\n                                   enum gpi_log_level level,\n                                   const char *pathname, const char *funcname,\n                                   long lineno, const char *msg, va_list argp) {\n    int curr_level = current_native_logger_level;\n    if (current_native_logger_level == GPI_NOTSET) {\n        curr_level = GPI_INFO;\n    }\n    if (level < curr_level) {\n        return;\n    }\n\n    va_list argp_copy;\n    va_copy(argp_copy, argp);\n    DEFER(va_end(argp_copy));\n\n    static std::vector<char> log_buff(512);\n\n    log_buff.clear();\n    int n = vsnprintf(log_buff.data(), log_buff.capacity(), msg, argp);\n    if (n < 0) {\n        // On Windows with the Visual C Runtime prior to 2015 the above call to\n        // vsnprintf will return -1 if the buffer would overflow, rather than\n        // the number of bytes that would be written as required by the C99\n        // standard.\n        // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l\n        // So we try the call again with the buffer NULL and the size 0, which\n        // should return the number of bytes that would be written.\n        va_list argp_copy_again;\n        va_copy(argp_copy_again, argp_copy);\n        DEFER(va_end(argp_copy_again));\n        n = vsnprintf(NULL, 0, msg, argp_copy_again);\n        if (n < 0) {\n            // Here we know the error is for real, so we complain and move on.\n            // LCOV_EXCL_START\n            fprintf(stderr,\n                    \"Log message construction failed: (error code) %d\\n\", n);\n            return;\n            // LCOV_EXCL_STOP\n        }\n    }\n    if ((unsigned)n >= log_buff.capacity()) {\n        log_buff.reserve((unsigned)n + 1);\n        n = vsnprintf(log_buff.data(), (unsigned)n + 1, msg, argp_copy);\n        if (n < 0) {\n            // LCOV_EXCL_START\n            fprintf(stderr,\n                    \"Log message construction failed: (error code) %d\\n\", n);\n            return;\n            // LCOV_EXCL_STOP\n        }\n    }\n\n    fprintf(stdout, \"     -.--ns \");\n    fprintf(stdout, \"%-9s\", gpi_log_level_to_str(level));\n    fprintf(stdout, \"%-35s\", name);\n\n    size_t pathlen = strlen(pathname);\n    if (pathlen > 20) {\n        fprintf(stdout, \"..%18s:\", (pathname + (pathlen - 18)));\n    } else {\n        fprintf(stdout, \"%20s:\", pathname);\n    }\n\n    fprintf(stdout, \"%-4ld\", lineno);\n    fprintf(stdout, \" in %-31s \", funcname);\n    fprintf(stdout, \"%s\", log_buff.data());\n    fprintf(stdout, \"\\n\");\n    fflush(stdout);\n}\n\nstatic gpi_log_handler_ftype current_handler = gpi_native_logger_vlog;\nstatic void *current_userdata = nullptr;\n\nvoid gpi_log_(const char *name, enum gpi_log_level level, const char *pathname,\n              const char *funcname, long lineno, const char *msg, ...) {\n    va_list argp;\n    va_start(argp, msg);\n    gpi_vlog_(name, level, pathname, funcname, lineno, msg, argp);\n    va_end(argp);\n}\n\nvoid gpi_vlog_(const char *name, enum gpi_log_level level, const char *pathname,\n               const char *funcname, long lineno, const char *msg,\n               va_list argp) {\n    (*current_handler)(current_userdata, name, level, pathname, funcname,\n                       lineno, msg, argp);\n}\n\nstatic const std::map<int, const char *> log_level_str_table = {\n    {GPI_TRACE, \"TRACE\"},     {GPI_DEBUG, \"DEBUG\"}, {GPI_INFO, \"INFO\"},\n    {GPI_WARNING, \"WARNING\"}, {GPI_ERROR, \"ERROR\"}, {GPI_CRITICAL, \"CRITICAL\"},\n};\n\nstatic const char *unknown_level = \"------\";\n\nconst char *gpi_log_level_to_str(enum gpi_log_level level) {\n    const char *log_level_str = unknown_level;\n    auto idx = log_level_str_table.find(level);\n    if (idx != log_level_str_table.end()) {\n        log_level_str = idx->second;\n    }\n    return log_level_str;\n}\n\n/*******************************************************************************\n * GPI Logger Public API\n *******************************************************************************/\n\nextern \"C\" int gpi_native_logger_set_level(enum gpi_log_level level) {\n    int old_level = current_native_logger_level;\n    current_native_logger_level = level;\n    return old_level;\n}\n\nextern \"C\" void gpi_get_log_handler(gpi_log_handler_ftype *handler,\n                                    void **userdata) {\n    *handler = current_handler;\n    *userdata = current_userdata;\n}\n\nextern \"C\" void gpi_set_log_handler(gpi_log_handler_ftype handler,\n                                    void *userdata) {\n    current_handler = handler;\n    current_userdata = userdata;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/logging.hpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#ifndef GPI_LOGGING_HPP_\n#define GPI_LOGGING_HPP_\n\n/** @file logging.hpp\n\nGPI Logging\n===========\n\nLogging functionality for the GPI and its implementations.\n*/\n\n#include <exports.h>\n#include <gpi.h>\n\n#include <cstdarg>  // va_list\n#include <cstring>  // strlen\n\n#ifdef GPI_EXPORTS\n#define GPI_EXPORT COCOTB_EXPORT\n#else\n#define GPI_EXPORT COCOTB_IMPORT\n#endif\n\nextern GPI_EXPORT int gpi_debug_enabled;\n\n/** @return The string representation of the GPI log level. */\nGPI_EXPORT const char *gpi_log_level_to_str(enum gpi_log_level level);\n\n/** Logs a message at a given log level using the current log handler.\n * The caller provides explicit location information.\n */\n#define LOG_EXPLICIT(logger, level, file, func, lineno, ...) \\\n    gpi_log_(logger, level, file, func, lineno, __VA_ARGS__)\n\n/** Logs a message at a given log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define LOG_(level, ...) \\\n    gpi_log_(\"gpi\", level, __FILE__, __func__, __LINE__, __VA_ARGS__)\n\n/** Logs a message at TRACE log level using the current log handler.\n * Only logs if GPI debug is enabled.\n * Automatically populates arguments using information in the called context.\n */\n#define LOG_TRACE(...)                    \\\n    do {                                  \\\n        if (gpi_debug_enabled) {          \\\n            LOG_(GPI_TRACE, __VA_ARGS__); \\\n        }                                 \\\n    } while (0)\n\n/** Logs a message at DEBUG log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define LOG_DEBUG(...) LOG_(GPI_DEBUG, __VA_ARGS__)\n\n/** Logs a message at INFO log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define LOG_INFO(...) LOG_(GPI_INFO, __VA_ARGS__)\n\n/** Logs a message at WARN log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define LOG_WARN(...) LOG_(GPI_WARNING, __VA_ARGS__)\n\n/** Logs a message at ERROR log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define LOG_ERROR(...) LOG_(GPI_ERROR, __VA_ARGS__)\n\n/** Logs a message at CRITICAL log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define LOG_CRITICAL(...) LOG_(GPI_CRITICAL, __VA_ARGS__)\n\n#define MAKE_LOG_NAME_(extra_name) \\\n    (extra_name[0] == '\\0' ? \"gpi\" : \"gpi.\" extra_name)\n\n/** Log a message using the currently registered log handler.\n *\n * @param extra_name  Name of the \"gpi\" child logger, \"\" for the root logger\n * @param level       Level at which to log the message\n * @param pathname    Name of the file where the call site is located\n * @param funcname    Name of the function where the call site is located\n * @param lineno      Line number of the call site\n * @param msg         The message to log, uses C-sprintf-style format specifier\n * @param ...         Additional arguments; formatted and inserted in message\n *                    according to format specifier in msg argument\n */\n#define gpi_log(extra_name, level, pathname, funcname, lineno, ...)         \\\n    gpi_log_(MAKE_LOG_NAME_(extra_name), level, pathname, funcname, lineno, \\\n             __VA_ARGS__)\n\n// Don't call this function directly unless the name is \"gpi\" or starts with\n// \"gpi.\"\nGPI_EXPORT void gpi_log_(const char *name, enum gpi_log_level level,\n                         const char *pathname, const char *funcname,\n                         long lineno, const char *msg, ...);\n\n/** Log a message using the currently registered log handler.\n *\n * @param extra_name  Name of the \"gpi\" child logger, \"\" for the root logger\n * @param level       Level at which to log the message\n * @param pathname    Name of the file where the call site is located\n * @param funcname    Name of the function where the call site is located\n * @param lineno      Line number of the call site\n * @param msg         The message to log, uses C-sprintf-style format specifier\n * @param args        Additional arguments; formatted and inserted in message\n *                    according to format specifier in msg argument\n */\n#define gpi_vlog(extra_name, level, pathname, funcname, lineno, msg, args)   \\\n    gpi_vlog_(MAKE_LOG_NAME_(extra_name), level, pathname, funcname, lineno, \\\n              msg, args)\n\n// Don't call this function directly unless the name is \"gpi\" or starts with\n// \"gpi.\"\nGPI_EXPORT void gpi_vlog_(const char *name, enum gpi_log_level level,\n                          const char *pathname, const char *funcname,\n                          long lineno, const char *msg, va_list args);\n\n#endif /* GPI_LOGGING_HPP_ */\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vhpi/VhpiCbHdl.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <cstring>\n\n#include \"../logging.hpp\"\n#include \"./VhpiImpl.hpp\"\n#include \"_vendor/vhpi/vhpi_user.h\"\n#include \"gpi.h\"\n\n// Main entry point for callbacks from simulator\nvoid handle_vhpi_callback(const vhpiCbDataT *cb_data) {\n    SIM_TO_GPI(VHPI, cb_data->user_data,\n               VhpiImpl::reason_to_string(cb_data->reason));\n\n    VhpiCbHdl *cb_hdl = (VhpiCbHdl *)cb_data->user_data;\n\n    int error = (!cb_hdl);\n    // LCOV_EXCL_START\n    if (error) {\n        LOG_CRITICAL(\"VHPI: Callback data corrupted: ABORTING\");\n    }\n    // LCOV_EXCL_STOP\n\n    if (!error) {\n        GPI_TO_USER_CB(VHPI);\n        error = cb_hdl->run();\n        USER_CB_TO_GPI(VHPI);\n    }\n\n    if (error) {\n        gpi_end_of_sim_time();\n    }\n\n    GPI_TO_SIM(VHPI, cb_data->user_data);\n}\n\nVhpiCbHdl::VhpiCbHdl(GpiImplInterface *impl) : GpiCbHdl(impl) {\n    cb_data.reason = 0;\n    cb_data.cb_rtn = handle_vhpi_callback;\n    cb_data.obj = NULL;\n    cb_data.time = NULL;\n    cb_data.value = NULL;\n    cb_data.user_data = (char *)this;\n\n    vhpi_time.high = 0;\n    vhpi_time.low = 0;\n}\n\nint VhpiCbHdl::remove() {\n    auto err = vhpi_remove_cb(get_handle<vhpiHandleT>());\n    // LCOV_EXCL_START\n    if (err) {\n        LOG_DEBUG(\"VHPI: Unable to remove callback!\");\n        check_vhpi_error();\n        // If we fail to remove the callback, mark it as removed so once it\n        // fires we can squash it then remove the callback cleanly.\n        m_removed = true;\n    }\n    // LCOV_EXCL_STOP\n    else {\n        delete this;\n    }\n    return 0;\n}\n\nint VhpiCbHdl::arm() {\n    vhpiHandleT new_hdl = vhpi_register_cb(&cb_data, vhpiReturnCb);\n    LOG_TRACE(\"VHPI: Registered callback %p for reason %s\", this,\n              VhpiImpl::reason_to_string(cb_data.reason));\n\n    // LCOV_EXCL_START\n    if (!new_hdl) {\n        check_vhpi_error();\n        LOG_ERROR(\n            \"VHPI: Unable to register a callback handle for VHPI type \"\n            \"%s(%d)\",\n            VhpiImpl::reason_to_string(cb_data.reason), cb_data.reason);\n        check_vhpi_error();\n        return -1;\n    }\n    // LCOV_EXCL_STOP\n\n    m_obj_hdl = new_hdl;\n    return 0;\n}\n\nint VhpiCbHdl::run() {\n    int res = 0;\n\n    // LCOV_EXCL_START\n    if (!m_removed) {\n        // Only call up if not removed.\n        res = m_cb_func(m_cb_data);\n    }\n    // LCOV_EXCL_STOP\n\n    // Many callbacks in VHPI are recurring, so we try to remove them after they\n    // fire. For the callbacks that aren't recurring, this doesn't seem to make\n    // the simulator unhappy, so whatever.\n    auto err = vhpi_remove_cb(get_handle<vhpiHandleT>());\n    // LCOV_EXCL_START\n    if (err) {\n        LOG_DEBUG(\"VHPI: Unable to remove callback!\");\n        check_vhpi_error();\n        // If we fail to remove the callback, mark it as removed so if it fires\n        // we can squash it.\n        m_removed = true;\n    }\n    // LCOV_EXCL_STOP\n    else {\n        delete this;\n    }\n    return res;\n}\n\nVhpiValueCbHdl::VhpiValueCbHdl(GpiImplInterface *impl, VhpiSignalObjHdl *sig,\n                               gpi_edge edge)\n    : VhpiCbHdl(impl), m_signal(sig), m_edge(edge) {\n    cb_data.reason = vhpiCbValueChange;\n    cb_data.time = &vhpi_time;\n    cb_data.obj = m_signal->get_handle<vhpiHandleT>();\n}\n\nint VhpiValueCbHdl::run() {\n    // LCOV_EXCL_START\n    if (m_removed) {\n        // Only call up if not removed.\n        return 0;\n    }\n    // LCOV_EXCL_STOP\n\n    bool pass = false;\n    switch (m_edge) {\n        case GPI_RISING: {\n            pass = !strcmp(m_signal->get_signal_value_binstr(), \"1\");\n            break;\n        }\n        case GPI_FALLING: {\n            pass = !strcmp(m_signal->get_signal_value_binstr(), \"0\");\n            break;\n        }\n        case GPI_VALUE_CHANGE: {\n            pass = true;\n            break;\n        }\n    }\n\n    int res = 0;\n    if (pass) {\n        res = m_cb_func(m_cb_data);\n\n        // Remove recurring callback once fired\n        auto err = vhpi_remove_cb(get_handle<vhpiHandleT>());\n        // LCOV_EXCL_START\n        if (err) {\n            LOG_DEBUG(\"VHPI: Unable to remove callback!\");\n            check_vhpi_error();\n            // If we fail to remove the callback, mark it as removed so if it\n            // fires we can squash it.\n            m_removed = true;\n        }\n        // LCOV_EXCL_STOP\n        else {\n            delete this;\n        }\n\n    }  // else Don't remove and let it fire again.\n\n    return res;\n}\n\nVhpiStartupCbHdl::VhpiStartupCbHdl(GpiImplInterface *impl) : VhpiCbHdl(impl) {\n    cb_data.reason = vhpiCbStartOfSimulation;\n}\n\nVhpiShutdownCbHdl::VhpiShutdownCbHdl(GpiImplInterface *impl) : VhpiCbHdl(impl) {\n    cb_data.reason = vhpiCbEndOfSimulation;\n}\n\nVhpiTimedCbHdl::VhpiTimedCbHdl(GpiImplInterface *impl, uint64_t time)\n    : VhpiCbHdl(impl) {\n    vhpi_time.high = (uint32_t)(time >> 32);\n    vhpi_time.low = (uint32_t)(time);\n\n    cb_data.reason = vhpiCbAfterDelay;\n    cb_data.time = &vhpi_time;\n}\n\nVhpiReadWriteCbHdl::VhpiReadWriteCbHdl(GpiImplInterface *impl)\n    : VhpiCbHdl(impl) {\n    cb_data.reason = vhpiCbRepLastKnownDeltaCycle;\n    cb_data.time = &vhpi_time;\n}\n\nVhpiReadOnlyCbHdl::VhpiReadOnlyCbHdl(GpiImplInterface *impl) : VhpiCbHdl(impl) {\n    cb_data.reason = vhpiCbRepEndOfTimeStep;\n    cb_data.time = &vhpi_time;\n}\n\nVhpiNextPhaseCbHdl::VhpiNextPhaseCbHdl(GpiImplInterface *impl)\n    : VhpiCbHdl(impl) {\n    cb_data.reason = vhpiCbRepNextTimeStep;\n    cb_data.time = &vhpi_time;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vhpi/VhpiImpl.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2014, 2018 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include \"./VhpiImpl.hpp\"\n\n#include <stdlib.h>\n\n#include <cassert>\n#include <cmath>\n#include <cstring>\n\n#include \"../logging.hpp\"\n#include \"_vendor/vhpi/vhpi_user.h\"\n#include \"vhpi_user_ext.h\"\n\n#ifdef NVC\n#include <algorithm>\n#endif\n\n#define CASE_STR(_X) \\\n    case _X:         \\\n        return #_X\n\nconst char *VhpiImpl::format_to_string(int format) {\n    switch (format) {\n        CASE_STR(vhpiBinStrVal);\n        CASE_STR(vhpiOctStrVal);\n        CASE_STR(vhpiDecStrVal);\n        CASE_STR(vhpiHexStrVal);\n        CASE_STR(vhpiEnumVal);\n        CASE_STR(vhpiSmallEnumVal);\n        CASE_STR(vhpiIntVal);\n        CASE_STR(vhpiLogicVal);\n        CASE_STR(vhpiRealVal);\n        CASE_STR(vhpiStrVal);\n        CASE_STR(vhpiCharVal);\n        CASE_STR(vhpiTimeVal);\n        CASE_STR(vhpiPhysVal);\n        CASE_STR(vhpiObjTypeVal);\n        CASE_STR(vhpiPtrVal);\n        CASE_STR(vhpiEnumVecVal);\n        CASE_STR(vhpiRawDataVal);\n\n        default:\n            return \"unknown\";\n    }\n}\n\nconst char *VhpiImpl::reason_to_string(int reason) {\n    switch (reason) {\n        CASE_STR(vhpiCbValueChange);\n        CASE_STR(vhpiCbStartOfNextCycle);\n        CASE_STR(vhpiCbStartOfPostponed);\n        CASE_STR(vhpiCbEndOfTimeStep);\n        CASE_STR(vhpiCbNextTimeStep);\n        CASE_STR(vhpiCbAfterDelay);\n        CASE_STR(vhpiCbStartOfSimulation);\n        CASE_STR(vhpiCbEndOfSimulation);\n        CASE_STR(vhpiCbEndOfProcesses);\n        CASE_STR(vhpiCbLastKnownDeltaCycle);\n\n        default:\n            return \"unknown\";\n    }\n}\n\n#undef CASE_STR\n\nvoid VhpiImpl::get_sim_time(uint32_t *high, uint32_t *low) {\n    vhpiTimeT vhpi_time_s;\n    vhpi_get_time(&vhpi_time_s, NULL);\n    check_vhpi_error();\n    *high = vhpi_time_s.high;\n    *low = vhpi_time_s.low;\n}\n\nstatic int32_t log10int(uint64_t v) {\n    int32_t i = -1;\n    do {\n        v /= 10;\n        i += 1;\n    } while (v);\n    return i;\n}\n\nvoid VhpiImpl::get_sim_precision(int32_t *precision) {\n    /* The value returned is in number of femtoseconds */\n    vhpiPhysT prec = vhpi_get_phys(vhpiResolutionLimitP, NULL);\n    uint64_t femtoseconds = ((uint64_t)prec.high << 32) | prec.low;\n    *precision = log10int(femtoseconds) - 15;\n}\n\nconst char *VhpiImpl::get_simulator_product() {\n    if (m_product.empty()) {\n        vhpiHandleT tool = vhpi_handle(vhpiTool, NULL);\n        if (tool) {\n            m_product = vhpi_get_str(vhpiNameP, tool);\n            vhpi_release_handle(tool);\n        } else {\n            m_product = \"UNKNOWN\";\n        }\n    }\n    return m_product.c_str();\n}\n\nconst char *VhpiImpl::get_simulator_version() {\n    if (m_version.empty()) {\n        vhpiHandleT tool = vhpi_handle(vhpiTool, NULL);\n        if (tool) {\n            m_version = vhpi_get_str(vhpiToolVersionP, tool);\n            vhpi_release_handle(tool);\n        } else {\n            m_version = \"UNKNOWN\";\n        }\n    }\n    return m_version.c_str();\n}\n\nint VhpiImpl::get_simulator_args(int *argc, char const *const **argv) {\n    if (m_argv == nullptr) {\n        auto tool = vhpi_handle(vhpiTool, NULL);\n        if (tool) {\n            m_argc = static_cast<int>(vhpi_get(vhpiArgcP, tool));\n            m_argv = new char const *[m_argc];\n\n            auto argv_iter = vhpi_iterator(vhpiArgvs, tool);\n            if (argv_iter) {\n                vhpiHandleT argv_hdl;\n                for (size_t i = 0; (argv_hdl = vhpi_scan(argv_iter)); i++) {\n                    m_argv[i] = const_cast<char *>(static_cast<const char *>(\n                        vhpi_get_str(vhpiStrValP, argv_hdl)));\n                }\n            }\n\n            vhpi_release_handle(tool);\n        }\n    }\n    *argc = m_argc;\n    *argv = m_argv;\n    return 0;\n}\n\n// Determine whether a VHPI object type is a constant or not\nbool is_const(vhpiHandleT hdl) {\n    vhpiHandleT tmp = hdl;\n\n    /* Need to walk the prefix's back to the original handle to get a type\n     * that is not vhpiSelectedNameK or vhpiIndexedNameK\n     */\n    do {\n        vhpiIntT vhpitype = vhpi_get(vhpiKindP, tmp);\n        if (vhpiConstDeclK == vhpitype || vhpiGenericDeclK == vhpitype)\n            return true;\n    } while ((tmp = vhpi_handle(vhpiPrefix, tmp)) != NULL);\n\n    return false;\n}\n\nbool is_enum_logic(vhpiHandleT hdl) {\n    const char *type = vhpi_get_str(vhpiNameP, hdl);\n\n    if (0 == strncmp(type, \"BIT\", sizeof(\"BIT\") - 1) ||\n        0 == strncmp(type, \"STD_ULOGIC\", sizeof(\"STD_ULOGIC\") - 1) ||\n        0 == strncmp(type, \"STD_LOGIC\", sizeof(\"STD_LOGIC\") - 1)) {\n        return true;\n    } else {\n        vhpiIntT num_enum = vhpi_get(vhpiNumLiteralsP, hdl);\n\n        if (2 == num_enum) {\n            vhpiHandleT it = vhpi_iterator(vhpiEnumLiterals, hdl);\n            if (it != NULL) {\n                const char *enums_1[2] = {\n                    \"0\", \"1\"};  // Aldec does not return the single quotes\n                const char *enums_2[2] = {\"'0'\", \"'1'\"};\n                vhpiHandleT enum_hdl;\n                int cnt = 0;\n\n                while ((enum_hdl = vhpi_scan(it)) != NULL) {\n                    const char *etype = vhpi_get_str(vhpiStrValP, enum_hdl);\n                    if (1 < cnt || (0 != strncmp(etype, enums_1[cnt],\n                                                 strlen(enums_1[cnt])) &&\n                                    0 != strncmp(etype, enums_2[cnt],\n                                                 strlen(enums_2[cnt])))) {\n                        vhpi_release_handle(it);\n                        return false;\n                    }\n                    ++cnt;\n                }\n                return true;\n            }\n        } else if (9 == num_enum) {\n            vhpiHandleT it = vhpi_iterator(vhpiEnumLiterals, hdl);\n            if (it != NULL) {\n                const char *enums_1[9] = {\n                    \"U\", \"X\", \"0\", \"1\", \"Z\",\n                    \"W\", \"L\", \"H\", \"-\"};  // Aldec does not return the single\n                                          // quotes\n                const char *enums_2[9] = {\"'U'\", \"'X'\", \"'0'\", \"'1'\", \"'Z'\",\n                                          \"'W'\", \"'L'\", \"'H'\", \"'-'\"};\n                vhpiHandleT enum_hdl;\n                int cnt = 0;\n\n                while ((enum_hdl = vhpi_scan(it)) != NULL) {\n                    const char *etype = vhpi_get_str(vhpiStrValP, enum_hdl);\n                    if (8 < cnt || (0 != strncmp(etype, enums_1[cnt],\n                                                 strlen(enums_1[cnt])) &&\n                                    0 != strncmp(etype, enums_2[cnt],\n                                                 strlen(enums_2[cnt])))) {\n                        vhpi_release_handle(it);\n                        return false;\n                    }\n                    ++cnt;\n                }\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nbool is_enum_char(vhpiHandleT hdl) {\n    const vhpiIntT NUM_ENUMS_IN_CHAR_TYPE = 256;\n\n    const char *type = vhpi_get_str(vhpiNameP, hdl);\n\n    if (0 == strncmp(type, \"CHARACTER\", sizeof(\"CHARACTER\") - 1)) {\n        return true;\n    } else {\n        return (vhpi_get(vhpiNumLiteralsP, hdl) == NUM_ENUMS_IN_CHAR_TYPE);\n    }\n}\n\nbool is_enum_boolean(vhpiHandleT hdl) {\n    const char *type = vhpi_get_str(vhpiNameP, hdl);\n\n    if (0 == strncmp(type, \"BOOLEAN\", sizeof(\"BOOLEAN\") - 1)) {\n        return true;\n    } else {\n        vhpiIntT num_enum = vhpi_get(vhpiNumLiteralsP, hdl);\n\n        if (2 == num_enum) {\n            vhpiHandleT it = vhpi_iterator(vhpiEnumLiterals, hdl);\n            if (it != NULL) {\n                vhpiHandleT enum_hdl;\n                int cnt = 0;\n\n                while ((enum_hdl = vhpi_scan(it)) != NULL) {\n                    const char *etype = vhpi_get_str(vhpiStrValP, enum_hdl);\n                    if (((0 == cnt &&\n                          0 != strncmp(etype, \"FALSE\", strlen(\"FALSE\"))) &&\n                         (0 == cnt &&\n                          0 != strncmp(etype, \"false\", strlen(\"false\")))) ||\n                        ((1 == cnt &&\n                          0 != strncmp(etype, \"TRUE\", strlen(\"TRUE\"))) &&\n                         (1 == cnt &&\n                          0 != strncmp(etype, \"true\", strlen(\"true\")))) ||\n                        2 <= cnt) {\n                        vhpi_release_handle(it);\n                        return false;\n                    }\n                    ++cnt;\n                }\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nstatic bool compare_names(const std::string &a, const std::string &b) {\n#ifdef NVC\n    /* NVC does not properly implement the CaseName property and returns\n       Names instead (nickg/nvc#723). */\n    return a.size() == b.size() &&\n           equal(a.begin(), a.end(), b.begin(), [](char x, char y) {\n               return std::toupper(x) == std::toupper(y);\n           });\n#else\n    return a == b;\n#endif\n}\n\nGpiObjHdl *VhpiImpl::create_gpi_obj_from_handle(vhpiHandleT new_hdl,\n                                                const std::string &name,\n                                                const std::string &fq_name) {\n    vhpiIntT type;\n    gpi_objtype gpi_type;\n    GpiObjHdl *new_obj = NULL;\n\n    if (vhpiVerilog == (type = vhpi_get(vhpiKindP, new_hdl))) {\n        LOG_DEBUG(\"VHPI: vhpiVerilog returned from vhpi_get(vhpiType, ...)\");\n        return NULL;\n    }\n\n    /* We need to delve further here to determine how to later set\n       the values of an object */\n    vhpiHandleT base_hdl = vhpi_handle(vhpiBaseType, new_hdl);\n\n    if (base_hdl == NULL) {\n        vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, new_hdl);\n\n        if (st_hdl != NULL) {\n            base_hdl = vhpi_handle(vhpiBaseType, st_hdl);\n            vhpi_release_handle(st_hdl);\n        }\n    }\n\n    vhpiHandleT query_hdl = (base_hdl != NULL) ? base_hdl : new_hdl;\n\n    vhpiIntT base_type = vhpi_get(vhpiKindP, query_hdl);\n    switch (base_type) {\n        case vhpiArrayTypeDeclK: {\n            vhpiIntT num_dim = vhpi_get(vhpiNumDimensionsP, query_hdl);\n\n            if (num_dim > 1) {\n                LOG_DEBUG(\"VHPI: Detected a MULTI-DIMENSIONAL ARRAY type %s\",\n                          fq_name.c_str());\n                gpi_type = GPI_ARRAY;\n            } else {\n                vhpiHandleT elem_base_type_hdl = NULL;\n                vhpiIntT elem_base_type = 0;\n\n                vhpiHandleT elem_sub_type_hdl =\n                    vhpi_handle(vhpiElemType, query_hdl);\n                /* vhpiElemType is not supported in all simulators. */\n                if (!elem_sub_type_hdl) {\n                    elem_sub_type_hdl = vhpi_handle(vhpiElemSubtype, query_hdl);\n                }\n\n                if (elem_sub_type_hdl != NULL) {\n                    elem_base_type_hdl =\n                        vhpi_handle(vhpiBaseType, elem_sub_type_hdl);\n                    if (elem_base_type_hdl == NULL) {\n                        elem_base_type_hdl = elem_sub_type_hdl;\n                    } else {\n                        vhpi_release_handle(elem_sub_type_hdl);\n                    }\n                }\n\n                if (elem_base_type_hdl != NULL) {\n                    elem_base_type = vhpi_get(vhpiKindP, elem_base_type_hdl);\n                    if (elem_base_type == vhpiEnumTypeDeclK) {\n                        if (is_enum_logic(elem_base_type_hdl)) {\n                            LOG_DEBUG(\"VHPI: Detected a LOGIC VECTOR type %s\",\n                                      fq_name.c_str());\n                            gpi_type = GPI_LOGIC_ARRAY;\n                        } else if (is_enum_char(elem_base_type_hdl)) {\n                            LOG_DEBUG(\"VHPI: Detected a STRING type %s\",\n                                      fq_name.c_str());\n                            gpi_type = GPI_STRING;\n                        } else {\n                            LOG_DEBUG(\n                                \"VHPI: Detected a NON-LOGIC ENUM VECTOR type \"\n                                \"%s\",\n                                fq_name.c_str());\n                            gpi_type = GPI_ARRAY;\n                        }\n                    } else {\n                        LOG_DEBUG(\"VHPI: Detected a NON-ENUM VECTOR type %s\",\n                                  fq_name.c_str());\n                        gpi_type = GPI_ARRAY;\n                    }\n                } else {\n                    LOG_ERROR(\n                        \"VHPI: Unable to determine the Array Element Base Type \"\n                        \"for %s.  Defaulting to GPI_ARRAY.\",\n                        vhpi_get_str(vhpiFullCaseNameP, new_hdl));\n                    gpi_type = GPI_ARRAY;\n                }\n            }\n            break;\n        }\n\n        case vhpiEnumTypeDeclK: {\n            if (is_enum_logic(query_hdl)) {\n                LOG_DEBUG(\"VHPI: Detected a LOGIC type %s\", fq_name.c_str());\n                gpi_type = GPI_LOGIC;\n            } else if (is_enum_char(query_hdl)) {\n                LOG_DEBUG(\"VHPI: Detected a CHAR type %s\", fq_name.c_str());\n                gpi_type = GPI_INTEGER;\n            } else if (is_enum_boolean(query_hdl)) {\n                LOG_DEBUG(\"VHPI: Detected a BOOLEAN/INTEGER type %s\",\n                          fq_name.c_str());\n                gpi_type = GPI_INTEGER;\n            } else {\n                LOG_DEBUG(\"VHPI: Detected an ENUM type %s\", fq_name.c_str());\n                gpi_type = GPI_ENUM;\n            }\n            break;\n        }\n\n        case vhpiIntTypeDeclK: {\n            LOG_DEBUG(\"VHPI: Detected an INT type %s\", fq_name.c_str());\n            gpi_type = GPI_INTEGER;\n            break;\n        }\n\n        case vhpiFloatTypeDeclK: {\n            LOG_DEBUG(\"VHPI: Detected a REAL type %s\", fq_name.c_str());\n            gpi_type = GPI_REAL;\n            break;\n        }\n\n        case vhpiRecordTypeDeclK: {\n            LOG_DEBUG(\"VHPI: Detected a STRUCTURE type %s\", fq_name.c_str());\n            gpi_type = GPI_STRUCTURE;\n            break;\n        }\n\n        case vhpiProcessStmtK:\n        case vhpiSimpleSigAssignStmtK:\n        case vhpiCondSigAssignStmtK:\n        case vhpiSelectSigAssignStmtK: {\n            gpi_type = GPI_MODULE;\n            break;\n        }\n\n        case vhpiRootInstK:\n        case vhpiIfGenerateK:\n        case vhpiForGenerateK:\n        case vhpiBlockStmtK:\n        case vhpiCompInstStmtK: {\n            std::string hdl_name = vhpi_get_str(vhpiCaseNameP, new_hdl);\n\n            if (base_type == vhpiRootInstK && !compare_names(hdl_name, name)) {\n                vhpiHandleT arch = vhpi_handle(vhpiDesignUnit, new_hdl);\n\n                if (NULL != arch) {\n                    vhpiHandleT prim = vhpi_handle(vhpiPrimaryUnit, arch);\n\n                    if (NULL != prim) {\n                        hdl_name = vhpi_get_str(vhpiCaseNameP, prim);\n                    }\n                }\n            }\n\n            if (!compare_names(name, hdl_name)) {\n                LOG_DEBUG(\"VHPI: Found pseudo-region %s\", fq_name.c_str());\n                gpi_type = GPI_GENARRAY;\n            } else {\n                gpi_type = GPI_MODULE;\n            }\n            break;\n        }\n\n        default: {\n            vhpiIntT is_static = vhpi_get(vhpiStaticnessP, query_hdl);\n\n            /* Non locally static objects are not accessible for read/write\n               so we create this as a GpiObjType\n            */\n            if (is_static == vhpiGloballyStatic) {\n                gpi_type = GPI_MODULE;\n                break;\n            }\n\n            LOG_ERROR(\"VHPI: Not able to map type (%s) %u to object\",\n                      vhpi_get_str(vhpiKindStrP, query_hdl), type);\n            new_obj = NULL;\n            goto out;\n        }\n    }\n\n    LOG_DEBUG(\"VHPI: Creating %s of type %d (%s)\",\n              vhpi_get_str(vhpiFullCaseNameP, new_hdl), gpi_type,\n              vhpi_get_str(vhpiKindStrP, query_hdl));\n\n    switch (gpi_type) {\n        case GPI_ARRAY: {\n            new_obj = new VhpiArrayObjHdl(this, new_hdl, gpi_type);\n            break;\n        }\n        case GPI_GENARRAY:\n        case GPI_MODULE:\n        case GPI_STRUCTURE:\n        case GPI_PACKAGE: {\n            new_obj = new VhpiObjHdl(this, new_hdl, gpi_type);\n            break;\n        }\n        case GPI_LOGIC:\n        case GPI_LOGIC_ARRAY: {\n            new_obj = new VhpiLogicSignalObjHdl(this, new_hdl, gpi_type,\n                                                is_const(new_hdl));\n            break;\n        }\n        default: {\n            new_obj = new VhpiSignalObjHdl(this, new_hdl, gpi_type,\n                                           is_const(new_hdl));\n            break;\n        }\n    }\n\n    if (new_obj->initialise(name, fq_name)) {\n        delete new_obj;\n        new_obj = NULL;\n    }\n\nout:\n    if (base_hdl != NULL) vhpi_release_handle(base_hdl);\n\n    return new_obj;\n}\n\nstatic std::string fully_qualified_name(const std::string &name,\n                                        GpiObjHdl *parent) {\n    std::string fq_name = parent->get_fullname();\n    if (fq_name == \":\") {\n        fq_name += name;\n    } else {\n        fq_name += \".\" + name;\n    }\n#ifdef NVC\n    /* Convert to a canonical form to avoid problems with case insensitivity. */\n    std::transform(fq_name.begin(), fq_name.end(), fq_name.begin(), ::toupper);\n#endif\n    return fq_name;\n}\n\nGpiObjHdl *VhpiImpl::get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) {\n    LOG_DEBUG(\"VHPI: Trying to convert raw to VHPI handle\");\n\n    vhpiHandleT new_hdl = (vhpiHandleT)raw_hdl;\n\n    const char *c_name = vhpi_get_str(vhpiCaseNameP, new_hdl);\n    if (!c_name) {\n        LOG_DEBUG(\"VHPI: Unable to query name of passed in handle\");\n        return NULL;\n    }\n\n    std::string name = c_name;\n    std::string fq_name = fully_qualified_name(name, parent);\n\n    GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name);\n    if (new_obj == NULL) {\n        vhpi_release_handle(new_hdl);\n        LOG_DEBUG(\"VHPI: Unable to fetch object %s\", fq_name.c_str());\n        return NULL;\n    }\n\n    return new_obj;\n}\n\nGpiObjHdl *VhpiImpl::get_child_by_name(const std::string &name,\n                                       GpiObjHdl *parent) {\n    vhpiHandleT vhpi_hdl = parent->get_handle<vhpiHandleT>();\n\n    vhpiHandleT new_hdl;\n    std::string fq_name = fully_qualified_name(name, parent);\n\n    std::vector<char> writable(fq_name.begin(), fq_name.end());\n    writable.push_back('\\0');\n\n    new_hdl = vhpi_handle_by_name(&writable[0], NULL);\n\n    if (new_hdl == NULL && parent->get_type() == GPI_STRUCTURE) {\n        /* vhpi_handle_by_name() doesn't always work for records, specifically\n         * records in generics */\n        vhpiHandleT iter = vhpi_iterator(vhpiSelectedNames, vhpi_hdl);\n        if (iter != NULL) {\n            while ((new_hdl = vhpi_scan(iter)) != NULL) {\n                std::string selected_name =\n                    vhpi_get_str(vhpiCaseNameP, new_hdl);\n                std::size_t found = selected_name.find_last_of(\".\");\n\n                if (found != std::string::npos) {\n                    selected_name = selected_name.substr(found + 1);\n                }\n\n                if (compare_names(selected_name, name)) {\n                    vhpi_release_handle(iter);\n                    break;\n                }\n            }\n        }\n    } else if (new_hdl == NULL) {\n        /* If not found, check to see if the name of a generate loop */\n        vhpiHandleT iter = vhpi_iterator(vhpiInternalRegions, vhpi_hdl);\n\n        if (iter != NULL) {\n            vhpiHandleT rgn;\n            for (rgn = vhpi_scan(iter); rgn != NULL; rgn = vhpi_scan(iter)) {\n                if (vhpi_get(vhpiKindP, rgn) == vhpiForGenerateK) {\n                    std::string rgn_name = vhpi_get_str(vhpiCaseNameP, rgn);\n                    if (compare_generate_labels(rgn_name, name)) {\n                        new_hdl = vhpi_hdl;\n                        vhpi_release_handle(iter);\n                        break;\n                    }\n                }\n            }\n        }\n        if (new_hdl == NULL) {\n            LOG_DEBUG(\"VHPI: Unable to query vhpi_handle_by_name %s\",\n                      fq_name.c_str());\n            return NULL;\n        }\n    }\n\n    /* Generate Loops have inconsistent behavior across VHPI.  A \"name\"\n     * without an index, i.e. dut.loop vs dut.loop(0), may or may not map to\n     * to the start index.  If it doesn't then it won't find anything.\n     *\n     * If this unique case is hit, we need to create the Pseudo-region, with the\n     * handle being equivalent to the parent handle.\n     */\n    if (vhpi_get(vhpiKindP, new_hdl) == vhpiForGenerateK) {\n        vhpi_release_handle(new_hdl);\n\n        new_hdl = vhpi_hdl;\n    }\n\n    GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name);\n    if (new_obj == NULL) {\n        vhpi_release_handle(new_hdl);\n        LOG_DEBUG(\"VHPI: Unable to fetch object %s\", fq_name.c_str());\n        return NULL;\n    }\n\n    return new_obj;\n}\n\nGpiObjHdl *VhpiImpl::get_child_by_index(int32_t index, GpiObjHdl *parent) {\n    vhpiHandleT vhpi_hdl = parent->get_handle<vhpiHandleT>();\n    std::string name = parent->get_name();\n    std::string fq_name = parent->get_fullname();\n    vhpiHandleT new_hdl = NULL;\n    char buff[14];  // needs to be large enough to hold -2^31 to 2^31-1 in\n                    // string form ('(''-'10+'')'\\0')\n\n    gpi_objtype obj_type = parent->get_type();\n\n    if (obj_type == GPI_GENARRAY) {\n        LOG_DEBUG(\n            \"VHPI: Get child at index %d of parent %s \"\n            \"(pseudo-region)\",\n            index, parent->get_name_str());\n\n        snprintf(buff, sizeof(buff), \"%d\", index);\n\n        std::string idx_str = buff;\n        name += (GEN_IDX_SEP_LHS + idx_str + GEN_IDX_SEP_RHS);\n        fq_name += (GEN_IDX_SEP_LHS + idx_str + GEN_IDX_SEP_RHS);\n\n        std::vector<char> writable(fq_name.begin(), fq_name.end());\n        writable.push_back('\\0');\n\n        new_hdl = vhpi_handle_by_name(&writable[0], NULL);\n    } else if (obj_type == GPI_LOGIC || obj_type == GPI_LOGIC_ARRAY ||\n               obj_type == GPI_ARRAY || obj_type == GPI_STRING) {\n        LOG_DEBUG(\"VHPI: Get child at index %d of parent %s (%s)\", index,\n                  parent->get_fullname_str(),\n                  vhpi_get_str(vhpiKindStrP, vhpi_hdl));\n\n        snprintf(buff, sizeof(buff), \"(%d)\", index);\n\n        std::string idx_str = buff;\n        name += idx_str;\n        fq_name += idx_str;\n\n        vhpiHandleT base_hdl = vhpi_handle(vhpiBaseType, vhpi_hdl);\n\n        if (base_hdl == NULL) {\n            vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, vhpi_hdl);\n\n            if (st_hdl != NULL) {\n                base_hdl = vhpi_handle(vhpiBaseType, st_hdl);\n                vhpi_release_handle(st_hdl);\n            }\n        }\n\n        if (base_hdl == NULL) {\n            LOG_ERROR(\"VHPI: Unable to get the vhpiBaseType of %s\",\n                      parent->get_fullname_str());\n            return NULL;\n        }\n\n        vhpiIntT num_dim = vhpi_get(vhpiNumDimensionsP, base_hdl);\n        int idx = 0;\n\n        /* Need to translate the index into a zero-based flattened array index\n         */\n        if (num_dim > 1) {\n            std::string hdl_name = vhpi_get_str(vhpiCaseNameP, vhpi_hdl);\n            std::vector<int> indices;\n\n            /* Need to determine how many indices have been received.  A valid\n             * handle will only be found when all indices are received,\n             * otherwise need a pseudo-handle.\n             *\n             * When working with pseudo-handles:\n             *              hdl_name:   sig_name\n             *    parent->get_name():   sig_name(x)(y)...  where x,y,... are the\n             * indices to a multi-dimensional array. pseudo_idx:   (x)(y)...\n             */\n            if (hdl_name.length() < parent->get_name().length()) {\n                std::string pseudo_idx =\n                    parent->get_name().substr(hdl_name.length());\n\n                while (pseudo_idx.length() > 0) {\n                    std::size_t found = pseudo_idx.find_first_of(\")\");\n\n                    if (found != std::string::npos) {\n                        indices.push_back(\n                            atoi(pseudo_idx.substr(1, found - 1).c_str()));\n                        pseudo_idx = pseudo_idx.substr(found + 1);\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            indices.push_back(index);\n\n            if (indices.size() == num_dim) {\n#ifdef IUS\n                /* IUS/Xcelium does not appear to set the vhpiIsUnconstrainedP\n                 * property.  IUS Docs say it will return -1 if unconstrained,\n                 * but with vhpiIntT being unsigned, the value returned is\n                 * below.\n                 */\n                const vhpiIntT UNCONSTRAINED = 2147483647;\n#endif\n\n                std::vector<vhpiHandleT> constraints;\n\n                /* All necessary indices are available, need to iterate over\n                 * dimension constraints to determine the index into the\n                 * zero-based flattened array.\n                 *\n                 * Check the constraints on the base type first. (always works\n                 * for Aldec, but not unconstrained types in IUS/Xcelium) If the\n                 * base type fails, then try the sub-type.  (sub-type is listed\n                 * as deprecated for Aldec)\n                 */\n                vhpiHandleT it, constraint;\n\n                it = vhpi_iterator(vhpiConstraints, base_hdl);\n\n                if (it != NULL) {\n                    while ((constraint = vhpi_scan(it)) != NULL) {\n#ifdef IUS\n                        vhpiIntT l_rng = vhpi_get(vhpiLeftBoundP, constraint);\n                        vhpiIntT r_rng = vhpi_get(vhpiRightBoundP, constraint);\n                        if (l_rng == UNCONSTRAINED || r_rng == UNCONSTRAINED) {\n#else\n                        if (vhpi_get(vhpiIsUnconstrainedP, constraint)) {\n#endif\n                            /* Bail and try the sub-type handle */\n                            vhpi_release_handle(it);\n                            break;\n                        }\n                        constraints.push_back(constraint);\n                    }\n                }\n\n                /* If all the dimensions were not obtained, try again with the\n                 * sub-type handle */\n                if (constraints.size() != num_dim) {\n                    vhpiHandleT sub_hdl = vhpi_handle(vhpiSubtype, vhpi_hdl);\n                    ;\n\n                    constraints.clear();\n\n                    if (sub_hdl != NULL) {\n                        it = vhpi_iterator(vhpiConstraints, sub_hdl);\n\n                        if (it != NULL) {\n                            while ((constraint = vhpi_scan(it)) != NULL) {\n                                /* IUS/Xcelium only sets the\n                                 * vhpiIsUnconstrainedP incorrectly on the base\n                                 * type */\n                                if (vhpi_get(vhpiIsUnconstrainedP,\n                                             constraint)) {\n                                    vhpi_release_handle(it);\n                                    break;\n                                }\n                                constraints.push_back(constraint);\n                            }\n                        }\n                    }\n                }\n\n                if (constraints.size() == num_dim) {\n                    int scale = 1;\n\n                    while (constraints.size() > 0) {\n                        int raw_idx = indices.back();\n                        constraint = constraints.back();\n\n                        int left = static_cast<int>(\n                            vhpi_get(vhpiLeftBoundP, constraint));\n                        int right = static_cast<int>(\n                            vhpi_get(vhpiRightBoundP, constraint));\n                        int len = 0;\n\n                        if (left > right) {\n                            idx += (scale * (left - raw_idx));\n                            len = left - right + 1;\n                        } else {\n                            idx += (scale * (raw_idx - left));\n                            len = right - left + 1;\n                        }\n                        scale = scale * len;\n\n                        indices.pop_back();\n                        constraints.pop_back();\n                    }\n                } else {\n                    LOG_ERROR(\"VHPI: Unable to access all constraints for %s\",\n                              parent->get_fullname_str());\n                    return NULL;\n                }\n\n            } else {\n                new_hdl = vhpi_hdl;  // Set to the parent handle to create the\n                                     // pseudo-handle\n            }\n        } else {\n            int left = parent->get_range_left();\n            int right = parent->get_range_right();\n\n            if (left > right) {\n                idx = left - index;\n            } else {\n                idx = index - left;\n            }\n        }\n\n        if (new_hdl == NULL) {\n            new_hdl = vhpi_handle_by_index(vhpiIndexedNames, vhpi_hdl, idx);\n            if (!new_hdl) {\n                /* Support for the above seems poor, so if it did not work\n                   try an iteration instead, spotty support for\n                   multi-dimensional arrays */\n\n                vhpiHandleT iter = vhpi_iterator(vhpiIndexedNames, vhpi_hdl);\n                if (iter != NULL) {\n                    int curr_index = 0;\n                    while ((new_hdl = vhpi_scan(iter)) != NULL) {\n                        if (idx == curr_index) {\n                            vhpi_release_handle(iter);\n                            break;\n                        }\n                        curr_index++;\n                    }\n                }\n            }\n\n            if (new_hdl != NULL) {\n                LOG_DEBUG(\"VHPI: Index (%d->%d) found %s (%s)\", index, idx,\n                          vhpi_get_str(vhpiCaseNameP, new_hdl),\n                          vhpi_get_str(vhpiKindStrP, new_hdl));\n            }\n        }\n    } else {\n        LOG_ERROR(\n            \"VHPI: Parent of type %s must be of type GPI_GENARRAY, \"\n            \"GPI_LOGIC, GPI_ARRAY, or GPI_STRING to have an index.\",\n            parent->get_type_str());\n        return NULL;\n    }\n\n    if (new_hdl == NULL) {\n        LOG_DEBUG(\"VHPI: Unable to query vhpi_handle_by_index %d\", index);\n        return NULL;\n    }\n\n    GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name);\n    if (new_obj == NULL) {\n        vhpi_release_handle(new_hdl);\n        LOG_DEBUG(\n            \"VHPI: Could not fetch object below entity (%s) at index (%d)\",\n            parent->get_name_str(), index);\n        return NULL;\n    }\n\n    return new_obj;\n}\n\nGpiObjHdl *VhpiImpl::get_root_handle(const char *name) {\n    vhpiHandleT root = vhpi_handle(vhpiRootInst, NULL);\n    if (!root) {\n        LOG_ERROR(\"VHPI: Attempting to get the vhpiRootInst failed\");\n        check_vhpi_error();\n        return NULL;\n    }\n\n    // IEEE 1076-2019 Clause 19.4.3\n    // For an object of class rootInst, the values of the Name and CaseName\n    // properties are the simple name of the entity declaration whose\n    // instantiation is represented by the object.\n    std::string root_name = vhpi_get_str(vhpiCaseNameP, root);\n    LOG_DEBUG(\"VHPI: We have found root='%s'\", root_name.c_str());\n\n    if (name && !compare_names(name, root_name)) {\n        LOG_DEBUG(\n            \"VHPI: root name '%s' doesn't match requested name '%s'. Trying \"\n            \"fallbacks\",\n            root_name.c_str(), name);\n    } else {\n        return create_gpi_obj_from_handle(root, root_name, root_name);\n    }\n\n    // Some simulators do not return the correct entity name for rootInst,\n    // so implement fallbacks.\n\n    // First, try to get the entity (primaryUnit) associated with the rootInst\n    // and its name.\n    vhpiHandleT arch = vhpi_handle(vhpiDesignUnit, root);\n    if (!arch) {\n        LOG_DEBUG(\n            \"VHPI: Unable to get vhpiDesignUnit (arch) from root handle. \"\n            \"Trying handle lookup by name\");\n        check_vhpi_error();\n    }\n\n    vhpiHandleT entity = NULL;\n    if (arch && !(entity = vhpi_handle(vhpiPrimaryUnit, arch))) {\n        LOG_DEBUG(\n            \"VHPI: Unable to get vhpiPrimaryUnit (entity) from arch handle. \"\n            \"Trying handle lookup by name\");\n        check_vhpi_error();\n    }\n\n    if (entity) {\n        root_name = vhpi_get_str(vhpiCaseNameP, entity);\n\n        // If this matches the name then it is what we want,\n        // but we use the root handle two levels up as the DUT\n        // because we do not want an object of type vhpiEntityDeclK as the DUT\n        if (name && !compare_names(name, root_name)) {\n            LOG_DEBUG(\n                \"VHPI: Root entity name '%s' doesn't match requested name \"\n                \"'%s'. Trying handle lookup by name\",\n                root_name.c_str(), name);\n        } else {\n            return create_gpi_obj_from_handle(root, root_name, root_name);\n        }\n    }\n\n    // Second, we search for the root handle by name\n    if (!name) {\n        // name should never be null here, but fail if it is.\n        LOG_ERROR(\"VHPI: Couldn't find root handle\");\n        return NULL;\n    }\n\n    // Search using hierarchical path, which starts with ':',\n    // to disambiguate with library information model objects\n    // that have the same name as the rootInst entity.\n    std::string search_name;\n    if (name[0] != ':') {\n        search_name = \":\";\n    }\n    search_name += name;\n\n    vhpiHandleT dut = vhpi_handle_by_name(search_name.c_str(), NULL);\n    if (!dut) {\n        LOG_DEBUG(\"VHPI: Unable to get root handle by name\");\n        check_vhpi_error();\n    } else {\n        root_name = vhpi_get_str(vhpiCaseNameP, dut);\n        vhpiIntT dut_kind = vhpi_get(vhpiKindP, dut);\n        std::string dut_kind_str = vhpi_get_str(vhpiKindStrP, dut);\n\n        if (!compare_names(name, root_name)) {\n            LOG_DEBUG(\n                \"VHPI: found root handle of type %s (%d) with name '%s' \"\n                \"doesn't match requested name '%s'\",\n                dut_kind_str.c_str(), dut_kind, root_name.c_str(), name);\n        } else {\n            return create_gpi_obj_from_handle(dut, root_name, root_name);\n        }\n    }\n\n    LOG_ERROR(\"VHPI: Couldn't find root handle '%s'\", name);\n    return NULL;\n}\n\nGpiIterator *VhpiImpl::iterate_handle(GpiObjHdl *obj_hdl,\n                                      gpi_iterator_sel type) {\n    GpiIterator *new_iter = NULL;\n\n    switch (type) {\n        case GPI_OBJECTS:\n            new_iter = new VhpiIterator(this, obj_hdl);\n            break;\n        case GPI_DRIVERS:\n            LOG_WARN(\"VHPI: Drivers iterator not implemented yet\");\n            break;\n        case GPI_LOADS:\n            LOG_WARN(\"VHPI: Loads iterator not implemented yet\");\n            break;\n        default:\n            LOG_WARN(\"VHPI: Other iterator types not implemented yet\");\n            break;\n    }\n    return new_iter;\n}\n\nGpiCbHdl *VhpiImpl::register_timed_callback(uint64_t time,\n                                            int (*cb_func)(void *),\n                                            void *cb_data) {\n    auto *cb_hdl = new VhpiTimedCbHdl(this, time);\n\n    auto err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        delete cb_hdl;\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiCbHdl *VhpiImpl::register_readwrite_callback(int (*cb_func)(void *),\n                                                void *cb_data) {\n    auto *cb_hdl = new VhpiReadWriteCbHdl(this);\n\n    auto err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        delete cb_hdl;\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiCbHdl *VhpiImpl::register_readonly_callback(int (*cb_func)(void *),\n                                               void *cb_data) {\n    auto *cb_hdl = new VhpiReadOnlyCbHdl(this);\n\n    auto err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        delete cb_hdl;\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiCbHdl *VhpiImpl::register_nexttime_callback(int (*cb_func)(void *),\n                                               void *cb_data) {\n    auto *cb_hdl = new VhpiNextPhaseCbHdl(this);\n\n    auto err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        delete cb_hdl;\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nvoid VhpiImpl::sim_end() {\n    m_sim_finish_cb->remove();\n    int err = vhpi_control(vhpiFinish, vhpiDiagTimeLoc);\n    // LCOV_EXCL_START\n    if (err) {\n        LOG_DEBUG(\"VHPI: Failed to end simulation\");\n        check_vhpi_error();\n    }\n    // LCOV_EXCL_STOP\n}\n\nbool VhpiImpl::compare_generate_labels(const std::string &a,\n                                       const std::string &b) {\n    /* Compare two generate labels for equality ignoring any suffixed index. */\n    std::size_t a_idx = a.rfind(GEN_IDX_SEP_LHS);\n    std::size_t b_idx = b.rfind(GEN_IDX_SEP_LHS);\n    return compare_names(a.substr(0, a_idx), b.substr(0, b_idx));\n}\n\nstatic int startup_callback(void *) {\n    LOG_TRACE(\"GPI => [ GPI (VHPI startup) ]\");\n    gpi_start_of_sim_time();\n    LOG_TRACE(\"[ GPI (VHPI startup) ] => GPI\");\n    return 0;\n}\n\nstatic int shutdown_callback(void *) {\n    LOG_TRACE(\"GPI => [ GPI (VHPI shutdown) ]\");\n    gpi_end_of_sim_time();\n    LOG_TRACE(\"[ GPI (VHPI shutdown) ] => GPI\");\n    return 0;\n}\n\nvoid VhpiImpl::main() noexcept {\n    auto startup_cb = new VhpiStartupCbHdl(this);\n    auto err = startup_cb->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        LOG_CRITICAL(\n            \"VHPI: Unable to register startup callback! Simulation will end.\");\n        check_vhpi_error();\n        delete startup_cb;\n        exit(1);\n    }\n    // LCOV_EXCL_STOP\n    startup_cb->set_cb_info(startup_callback, nullptr);\n\n    auto shutdown_cb = new VhpiShutdownCbHdl(this);\n    err = shutdown_cb->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        LOG_CRITICAL(\n            \"VHPI: Unable to register shutdown callback! Simulation will end.\");\n        check_vhpi_error();\n        startup_cb->remove();\n        delete shutdown_cb;\n        exit(1);\n    }\n    // LCOV_EXCL_STOP\n    shutdown_cb->set_cb_info(shutdown_callback, nullptr);\n    m_sim_finish_cb = shutdown_cb;\n\n    gpi_register_impl(this);\n    gpi_entry_point();\n}\n\nstatic bool from_bootstrap = false;\n\n// This is run by the simulator at startup when this is the main GPI entrypoint\nstatic void vhpi_main() {\n    LOG_TRACE(\"%s => [ VHPI (vhpi_main) ]\",\n              from_bootstrap ? \"Bootstrap\" : \"Sim (vhpi_startup_routines)\");\n    auto vhpi_table = new VhpiImpl(\"VHPI\");\n    vhpi_table->main();\n    LOG_TRACE(\"[ VHPI (vhpi_main) ] => %s\",\n              from_bootstrap ? \"Bootstrap\" : \"Sim (vhpi_startup_routines)\");\n}\n\n// This is run by GPI when requested for mixed-language simulations\nstatic void register_impl() {\n    LOG_TRACE(\"GPI Init => [ VHPI (register_impl) ]\");\n    auto vhpi_table = new VhpiImpl(\"VHPI\");\n    gpi_register_impl(vhpi_table);\n    LOG_TRACE(\"[ VHPI (register_impl) ] => GPI Init\");\n}\n\n// pre-defined VHPI registration table\nextern \"C\" {\nCOCOTBVHPI_EXPORT void (*vhpi_startup_routines[])() = {\n    gpi_init_logging_and_debug, vhpi_main, nullptr};\n\n// For non-VHPI compliant applications that cannot find vhpi_startup_routines\nCOCOTBVHPI_EXPORT void vhpi_startup_routines_bootstrap() {\n    gpi_init_logging_and_debug();\n    LOG_TRACE(\"Sim => [ VHPI (vhpi_startup_routines_bootstrap) ]\");\n    from_bootstrap = true;\n    vhpi_main();\n    LOG_TRACE(\"[ VHPI (vhpi_startup_routines_bootstrap) ] => Sim\");\n}\n}\n\nGPI_ENTRY_POINT(cocotbvhpi, register_impl)\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vhpi/VhpiImpl.hpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#ifndef COCOTB_VHPI_IMPL_H_\n#define COCOTB_VHPI_IMPL_H_\n\n#include <exports.h>\n#include <gpi.h>\n\n#include <map>\n#include <vector>\n\n#include \"../gpi_priv.hpp\"\n#include \"../logging.hpp\"\n#include \"_vendor/vhpi/vhpi_user.h\"\n\n#ifdef COCOTBVHPI_EXPORTS\n#define COCOTBVHPI_EXPORT COCOTB_EXPORT\n#else\n#define COCOTBVHPI_EXPORT COCOTB_IMPORT\n#endif\n\n// Define Index separator\n#ifdef ALDEC\n// Aldec\n#define GEN_IDX_SEP_LHS \"__\"\n#define GEN_IDX_SEP_RHS \"\"\n#else\n// IUS/Xcelium and Questa\n#define GEN_IDX_SEP_LHS \"(\"\n#define GEN_IDX_SEP_RHS \")\"\n#endif\n\nbool get_range(vhpiHandleT hdl, vhpiIntT dim, int *left, int *right,\n               gpi_range_dir *dir);\n\n// Should be run after every VHPI call to check error status\nstatic inline void __check_vhpi_error(const char *file, const char *func,\n                                      long line) {\n    if (!gpi_debug_enabled) {\n        return;\n    }\n\n    int err_occurred = 0;\n    vhpiErrorInfoT info;\n    enum gpi_log_level loglevel;\n    err_occurred = vhpi_check_error(&info);\n    if (!err_occurred) return;\n\n    switch (info.severity) {\n        case vhpiNote:\n            loglevel = GPI_INFO;\n            break;\n        case vhpiWarning:\n            loglevel = GPI_WARNING;\n            break;\n        case vhpiError:\n            loglevel = GPI_ERROR;\n            break;\n        case vhpiFailure:\n        case vhpiSystem:\n        case vhpiInternal:\n            loglevel = GPI_CRITICAL;\n            break;\n        default:\n            loglevel = GPI_INFO;\n            break;\n    }\n\n    LOG_EXPLICIT(\"gpi\", GPI_DEBUG, file, func, line,\n                 \"VHPI Internal Error: %s @ %s:%d: %s\",\n                 gpi_log_level_to_str(loglevel), info.file, info.line,\n                 info.message);\n}\n\n#define check_vhpi_error()                                \\\n    do {                                                  \\\n        __check_vhpi_error(__FILE__, __func__, __LINE__); \\\n    } while (0)\n\nclass VhpiCbHdl : public GpiCbHdl {\n  public:\n    VhpiCbHdl(GpiImplInterface *impl);\n\n    int arm() override;\n    int remove() override;\n    int run() override;\n\n  protected:\n    vhpiCbDataT cb_data;\n    vhpiTimeT vhpi_time;\n    bool m_removed = false;\n};\n\nclass VhpiSignalObjHdl;\n\nclass VhpiValueCbHdl : public VhpiCbHdl {\n  public:\n    VhpiValueCbHdl(GpiImplInterface *impl, VhpiSignalObjHdl *sig,\n                   gpi_edge edge);\n    int run() override;\n\n  private:\n    GpiSignalObjHdl *m_signal;\n    gpi_edge m_edge;\n};\n\nclass VhpiTimedCbHdl : public VhpiCbHdl {\n  public:\n    VhpiTimedCbHdl(GpiImplInterface *impl, uint64_t time);\n};\n\nclass VhpiReadOnlyCbHdl : public VhpiCbHdl {\n  public:\n    VhpiReadOnlyCbHdl(GpiImplInterface *impl);\n};\n\nclass VhpiNextPhaseCbHdl : public VhpiCbHdl {\n  public:\n    VhpiNextPhaseCbHdl(GpiImplInterface *impl);\n};\n\nclass VhpiStartupCbHdl : public VhpiCbHdl {\n  public:\n    VhpiStartupCbHdl(GpiImplInterface *impl);\n\n    // Too many sims get upset trying to remove startup callbacks so we just\n    // don't try. TODO Is this still accurate?\n\n    int run() override {\n        int res = 0;\n        if (!m_removed) {\n            res = m_cb_func(m_cb_data);\n        } else {\n            LOG_TRACE(\"[ VHPI (startup) ] callback is removed\");\n        }\n        delete this;\n        return res;\n    }\n\n    int remove() override {\n        m_removed = true;\n        return 0;\n    }\n};\n\nclass VhpiShutdownCbHdl : public VhpiCbHdl {\n  public:\n    VhpiShutdownCbHdl(GpiImplInterface *impl);\n\n    // Too many sims get upset trying to remove startup callbacks so we just\n    // don't try. TODO Is this still accurate?\n\n    int run() override {\n        int res = 0;\n        if (!m_removed) {\n            res = m_cb_func(m_cb_data);\n        } else {\n            LOG_TRACE(\"[ VHPI (shutdown) ] callback is removed\");\n        }\n        delete this;\n        return res;\n    }\n\n    int remove() override {\n        m_removed = true;\n        return 0;\n    }\n};\n\nclass VhpiReadWriteCbHdl : public VhpiCbHdl {\n  public:\n    VhpiReadWriteCbHdl(GpiImplInterface *impl);\n};\n\nclass VhpiArrayObjHdl : public GpiObjHdl {\n  public:\n    VhpiArrayObjHdl(GpiImplInterface *impl, vhpiHandleT hdl,\n                    gpi_objtype objtype)\n        : GpiObjHdl(impl, hdl, objtype) {}\n    ~VhpiArrayObjHdl() override;\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n};\n\nclass VhpiObjHdl : public GpiObjHdl {\n  public:\n    VhpiObjHdl(GpiImplInterface *impl, vhpiHandleT hdl, gpi_objtype objtype)\n        : GpiObjHdl(impl, hdl, objtype) {}\n    ~VhpiObjHdl() override;\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n};\n\nclass VhpiSignalObjHdl : public GpiSignalObjHdl {\n  public:\n    VhpiSignalObjHdl(GpiImplInterface *impl, vhpiHandleT hdl,\n                     gpi_objtype objtype, bool is_const)\n        : GpiSignalObjHdl(impl, hdl, objtype, is_const) {}\n    ~VhpiSignalObjHdl() override;\n\n    int get_signed() override;\n\n    const char *get_signal_value_binstr() override;\n    const char *get_signal_value_str() override;\n    double get_signal_value_real() override;\n    long get_signal_value_long() override;\n\n    using GpiSignalObjHdl::set_signal_value;\n    int set_signal_value(int32_t value, gpi_set_action action) override;\n    int set_signal_value(double value, gpi_set_action action) override;\n    int set_signal_value_str(std::string &value,\n                             gpi_set_action action) override;\n    int set_signal_value_binstr(std::string &value,\n                                gpi_set_action action) override;\n\n    /* Value change callback accessor */\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n    GpiCbHdl *register_value_change_callback(gpi_edge edge,\n                                             int (*function)(void *),\n                                             void *cb_data) override;\n\n  protected:\n    vhpiEnumT chr2vhpi(char value);\n    vhpiValueT m_value;\n    vhpiValueT m_binvalue;\n};\n\nclass VhpiLogicSignalObjHdl : public VhpiSignalObjHdl {\n  public:\n    VhpiLogicSignalObjHdl(GpiImplInterface *impl, vhpiHandleT hdl,\n                          gpi_objtype objtype, bool is_const)\n        : VhpiSignalObjHdl(impl, hdl, objtype, is_const) {}\n\n    using GpiSignalObjHdl::set_signal_value;\n    int set_signal_value(int32_t value, gpi_set_action action) override;\n    int set_signal_value_binstr(std::string &value,\n                                gpi_set_action action) override;\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n};\n\nclass VhpiIterator : public GpiIterator {\n  public:\n    VhpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl);\n\n    ~VhpiIterator() override;\n\n    Status next_handle(std::string &name, GpiObjHdl **hdl,\n                       void **raw_hdl) override;\n\n  private:\n    vhpiHandleT m_iterator;\n    vhpiHandleT m_iter_obj;\n    static std::map<vhpiClassKindT, std::vector<vhpiOneToManyT>>\n        iterate_over;                      /* Possible mappings */\n    std::vector<vhpiOneToManyT> *selected; /* Mapping currently in use */\n    std::vector<vhpiOneToManyT>::iterator one2many;\n};\n\nclass VhpiImpl : public GpiImplInterface {\n  public:\n    VhpiImpl(const std::string &name) : GpiImplInterface(name) {}\n\n    /* Sim related */\n    void sim_end() override;\n    void get_sim_time(uint32_t *high, uint32_t *low) override;\n    void get_sim_precision(int32_t *precision) override;\n    const char *get_simulator_product() override;\n    const char *get_simulator_version() override;\n    int get_simulator_args(int *argc, char const *const **argv) override;\n\n    /* Hierarchy related */\n    GpiObjHdl *get_root_handle(const char *name) override;\n    GpiIterator *iterate_handle(GpiObjHdl *obj_hdl,\n                                gpi_iterator_sel type) override;\n\n    /* Callback related, these may (will) return the same handle*/\n    GpiCbHdl *register_timed_callback(uint64_t time, int (*function)(void *),\n                                      void *cb_data) override;\n    GpiCbHdl *register_readonly_callback(int (*function)(void *),\n                                         void *cb_data) override;\n    GpiCbHdl *register_nexttime_callback(int (*function)(void *),\n                                         void *cb_data) override;\n    GpiCbHdl *register_readwrite_callback(int (*function)(void *),\n                                          void *cb_data) override;\n    GpiObjHdl *get_child_by_name(const std::string &name,\n                                 GpiObjHdl *parent) override;\n    GpiObjHdl *get_child_by_index(int32_t index, GpiObjHdl *parent) override;\n    GpiObjHdl *get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) override;\n\n    static const char *reason_to_string(int reason);\n    static const char *format_to_string(int format);\n\n    GpiObjHdl *create_gpi_obj_from_handle(vhpiHandleT new_hdl,\n                                          const std::string &name,\n                                          const std::string &fq_name);\n\n    static bool compare_generate_labels(const std::string &a,\n                                        const std::string &b);\n\n    /** Entry point for the simulator.\n     *\n     * Called if this GpiImpl will act as the main simulator entry point.\n     * Registers simulator startup and shutdown callbacks, and controls the\n     * behavior gpi_sim_end.\n     */\n    void main() noexcept;\n\n  private:\n    // We store the shutdown callback handle here so sim_end() can remove() it\n    // if it's called.\n    VhpiShutdownCbHdl *m_sim_finish_cb;\n    std::string m_product;\n    std::string m_version;\n    int m_argc = 0;\n    char const **m_argv = nullptr;\n};\n\n#endif /*COCOTB_VHPI_IMPL_H_  */\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vhpi/VhpiIterator.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <cinttypes>  // fixed-size int types and format strings\n#include <stdexcept>\n\n#include \"../logging.hpp\"\n#include \"./VhpiImpl.hpp\"\n#include \"_vendor/vhpi/vhpi_user.h\"\n\ndecltype(VhpiIterator::iterate_over) VhpiIterator::iterate_over = [] {\n    /* for reused lists */\n    std::initializer_list<vhpiOneToManyT> root_options = {\n        vhpiInternalRegions,\n        vhpiSigDecls,\n        vhpiVarDecls,\n        vhpiPortDecls,\n        vhpiGenericDecls,\n        vhpiConstDecls,\n        //    vhpiIndexedNames,\n        vhpiCompInstStmts,\n        vhpiBlockStmts,\n    };\n    std::initializer_list<vhpiOneToManyT> sig_options = {\n        vhpiIndexedNames,\n        vhpiSelectedNames,\n    };\n    std::initializer_list<vhpiOneToManyT> simplesig_options = {\n        vhpiDecls,\n        vhpiInternalRegions,\n        vhpiSensitivitys,\n        vhpiStmts,\n    };\n    std::initializer_list<vhpiOneToManyT> gen_options = {\n        vhpiDecls,      vhpiInternalRegions, vhpiSigDecls,   vhpiVarDecls,\n        vhpiConstDecls, vhpiCompInstStmts,   vhpiBlockStmts,\n    };\n\n    return decltype(VhpiIterator::iterate_over){\n        {vhpiRootInstK, root_options},\n        {vhpiCompInstStmtK, root_options},\n\n        {vhpiGenericDeclK, sig_options},\n        {vhpiSigDeclK, sig_options},\n        {vhpiSelectedNameK, sig_options},\n        {vhpiIndexedNameK, sig_options},\n        {vhpiPortDeclK, sig_options},\n\n        {vhpiCondSigAssignStmtK, simplesig_options},\n        {vhpiSimpleSigAssignStmtK, simplesig_options},\n        {vhpiSelectSigAssignStmtK, simplesig_options},\n\n        {vhpiForGenerateK, gen_options},\n        {vhpiIfGenerateK, gen_options},\n        {vhpiBlockStmtK, gen_options},\n\n        {vhpiConstDeclK,\n         {\n             vhpiAttrSpecs,\n             vhpiIndexedNames,\n             vhpiSelectedNames,\n         }},\n    };\n}();\n\nVhpiIterator::VhpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl)\n    : GpiIterator(impl, hdl), m_iterator(NULL), m_iter_obj(NULL) {\n    vhpiHandleT iterator;\n    vhpiHandleT vhpi_hdl = m_parent->get_handle<vhpiHandleT>();\n\n    vhpiClassKindT type = (vhpiClassKindT)vhpi_get(vhpiKindP, vhpi_hdl);\n    try {\n        selected = &iterate_over.at(type);\n    } catch (std::out_of_range const &) {\n        LOG_WARN(\n            \"VHPI: Implementation does not know how to iterate over %s(%d)\",\n            vhpi_get_str(vhpiKindStrP, vhpi_hdl), type);\n        selected = nullptr;\n        return;\n    }\n\n    /* Find the first mapping type that yields a valid iterator */\n    for (one2many = selected->begin(); one2many != selected->end();\n         one2many++) {\n        /* GPI_GENARRAY are pseudo-regions and all that should be searched for\n         * are the sub-regions */\n        if (m_parent->get_type() == GPI_GENARRAY &&\n            *one2many != vhpiInternalRegions) {\n            LOG_DEBUG(\n                \"VHPI: vhpi_iterator vhpiOneToManyT=%d skipped for \"\n                \"GPI_GENARRAY type\",\n                *one2many);\n            continue;\n        }\n\n        iterator = vhpi_iterator(*one2many, vhpi_hdl);\n\n        if (iterator) break;\n\n        LOG_DEBUG(\"VHPI: vhpi_iterate vhpiOneToManyT=%d returned NULL\",\n                  *one2many);\n    }\n\n    if (NULL == iterator) {\n        LOG_DEBUG(\n            \"VHPI: vhpi_iterate return NULL for all relationships on %s (%d) \"\n            \"kind:%s\",\n            vhpi_get_str(vhpiCaseNameP, vhpi_hdl), type,\n            vhpi_get_str(vhpiKindStrP, vhpi_hdl));\n        selected = NULL;\n        return;\n    }\n\n    LOG_DEBUG(\"VHPI: Created iterator working from scope %d (%s)\",\n              vhpi_get(vhpiKindP, vhpi_hdl),\n              vhpi_get_str(vhpiKindStrP, vhpi_hdl));\n\n    /* On some simulators (Aldec) vhpiRootInstK is a null level of hierarchy.\n     * We check that something is going to come back, if not, we try the level\n     * down.\n     */\n    m_iter_obj = vhpi_hdl;\n    m_iterator = iterator;\n}\n\nVhpiIterator::~VhpiIterator() {\n    if (m_iterator) vhpi_release_handle(m_iterator);\n}\n\n#define VHPI_TYPE_MIN (1000)\n\nGpiIterator::Status VhpiIterator::next_handle(std::string &name,\n                                              GpiObjHdl **hdl, void **raw_hdl) {\n    vhpiHandleT obj;\n    GpiObjHdl *new_obj;\n\n    if (!selected) return GpiIterator::END;\n\n    gpi_objtype obj_type = m_parent->get_type();\n    std::string parent_name = m_parent->get_name();\n\n    /* We want the next object in the current mapping.\n     * If the end of mapping is reached then we want to\n     * try the next one until a new object is found.\n     */\n    do {\n        obj = NULL;\n\n        if (m_iterator) {\n            obj = vhpi_scan(m_iterator);\n\n            /* For GPI_GENARRAY, only allow the generate statements through that\n             * match the name of the generate block.\n             */\n            if (obj != NULL && obj_type == GPI_GENARRAY) {\n                if (vhpi_get(vhpiKindP, obj) == vhpiForGenerateK) {\n                    std::string rgn_name = vhpi_get_str(vhpiCaseNameP, obj);\n                    if (!VhpiImpl::compare_generate_labels(rgn_name,\n                                                           parent_name)) {\n                        obj = NULL;\n                        continue;\n                    }\n                } else {\n                    obj = NULL;\n                    continue;\n                }\n            }\n\n            if (obj != NULL &&\n                (vhpiProcessStmtK == vhpi_get(vhpiKindP, obj) ||\n                 vhpiCondSigAssignStmtK == vhpi_get(vhpiKindP, obj) ||\n                 vhpiSimpleSigAssignStmtK == vhpi_get(vhpiKindP, obj) ||\n                 vhpiSelectSigAssignStmtK == vhpi_get(vhpiKindP, obj))) {\n                LOG_DEBUG(\"VHPI: Skipping %s (%s)\",\n                          vhpi_get_str(vhpiFullNameP, obj),\n                          vhpi_get_str(vhpiKindStrP, obj));\n                obj = NULL;\n                continue;\n            }\n\n            if (obj != NULL) {\n                LOG_DEBUG(\"VHPI: Found an item %s\",\n                          vhpi_get_str(vhpiFullNameP, obj));\n                break;\n            } else {\n                LOG_DEBUG(\"VHPI: vhpi_scan on vhpiOneToManyT=%d returned NULL\",\n                          *one2many);\n            }\n\n            LOG_DEBUG(\"VHPI: End of vhpiOneToManyT=%d iteration\", *one2many);\n            m_iterator = NULL;\n        } else {\n            LOG_DEBUG(\"VHPI: No valid vhpiOneToManyT=%d iterator\", *one2many);\n        }\n\n        if (++one2many >= selected->end()) {\n            obj = NULL;\n            break;\n        }\n\n        /* GPI_GENARRAY are pseudo-regions and all that should be searched for\n         * are the sub-regions */\n        if (obj_type == GPI_GENARRAY && *one2many != vhpiInternalRegions) {\n            LOG_DEBUG(\n                \"VHPI: vhpi_iterator vhpiOneToManyT=%d skipped for \"\n                \"GPI_GENARRAY type\",\n                *one2many);\n            continue;\n        }\n\n        m_iterator = vhpi_iterator(*one2many, m_iter_obj);\n\n    } while (!obj);\n\n    if (NULL == obj) {\n        LOG_DEBUG(\"VHPI: No more children, all relationships have been tested\");\n        return GpiIterator::END;\n    }\n\n    const char *c_name = vhpi_get_str(vhpiCaseNameP, obj);\n    if (!c_name) {\n        vhpiIntT type = vhpi_get(vhpiKindP, obj);\n\n        if (type < VHPI_TYPE_MIN) {\n            *raw_hdl = (void *)obj;\n            return GpiIterator::NOT_NATIVE_NO_NAME;\n        }\n\n        LOG_DEBUG(\n            \"VHPI: Unable to get the name for this object of type \" PRIu32,\n            type);\n\n        return GpiIterator::NATIVE_NO_NAME;\n    }\n\n    /*\n     * If the parent is not a generate loop, then watch for generate handles and\n     * create the pseudo-region.\n     *\n     * NOTE: Taking advantage of the \"caching\" to only create one pseudo-region\n     * object. Otherwise a list would be required and checked while iterating\n     */\n    if (*one2many == vhpiInternalRegions && obj_type != GPI_GENARRAY &&\n        vhpi_get(vhpiKindP, obj) == vhpiForGenerateK) {\n        std::string idx_str = c_name;\n        std::size_t found = idx_str.rfind(GEN_IDX_SEP_LHS);\n\n        if (found != std::string::npos && found != 0) {\n            name = idx_str.substr(0, found);\n            obj = m_parent->get_handle<vhpiHandleT>();\n        } else {\n            LOG_WARN(\"VHPI: Unhandled Generate Loop Format - %s\", name.c_str());\n            name = c_name;\n        }\n    } else {\n        name = c_name;\n    }\n\n    LOG_DEBUG(\"VHPI: vhpi_scan found %s (%d) kind:%s name:%s\", name.c_str(),\n              vhpi_get(vhpiKindP, obj), vhpi_get_str(vhpiKindStrP, obj),\n              vhpi_get_str(vhpiCaseNameP, obj));\n\n    /* We try and create a handle internally, if this is not possible we\n       return and GPI will try other implementations with the name\n       */\n    std::string fq_name = m_parent->get_fullname();\n    if (fq_name == \":\") {\n        fq_name += name;\n    } else if (obj_type == GPI_GENARRAY) {\n        std::size_t found = name.rfind(GEN_IDX_SEP_LHS);\n\n        if (found != std::string::npos) {\n            fq_name += name.substr(found);\n        } else {\n            LOG_WARN(\"VHPI: Unhandled Sub-Element Format - %s\", name.c_str());\n            fq_name += \".\" + name;\n        }\n    } else if (obj_type == GPI_STRUCTURE) {\n        std::size_t found = name.rfind(\".\");\n\n        if (found != std::string::npos) {\n            fq_name += name.substr(found);\n            name = name.substr(found + 1);\n        } else {\n            LOG_WARN(\"VHPI: Unhandled Sub-Element Format - %s\", name.c_str());\n            fq_name += \".\" + name;\n        }\n    } else {\n        fq_name += \".\" + name;\n    }\n    VhpiImpl *vhpi_impl = reinterpret_cast<VhpiImpl *>(m_impl);\n    new_obj = vhpi_impl->create_gpi_obj_from_handle(obj, name, fq_name);\n    if (new_obj) {\n        *hdl = new_obj;\n        return GpiIterator::NATIVE;\n    } else\n        return GpiIterator::NOT_NATIVE;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vhpi/VhpiObj.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include \"../logging.hpp\"\n#include \"./VhpiImpl.hpp\"\n#include \"_vendor/vhpi/vhpi_user.h\"\n\nVhpiArrayObjHdl::~VhpiArrayObjHdl() {\n    LOG_DEBUG(\"VHPI: Releasing VhpiArrayObjHdl handle for %s at %p\",\n              get_fullname_str(), (void *)get_handle<vhpiHandleT>());\n    if (vhpi_release_handle(get_handle<vhpiHandleT>())) check_vhpi_error();\n}\n\nVhpiObjHdl::~VhpiObjHdl() {\n    /* Don't release handles for pseudo-regions, as they borrow the handle of\n     * the containing region */\n    if (m_type != GPI_GENARRAY) {\n        LOG_DEBUG(\"VHPI: Releasing VhpiObjHdl handle for %s at %p\",\n                  get_fullname_str(), (void *)get_handle<vhpiHandleT>());\n        if (vhpi_release_handle(get_handle<vhpiHandleT>())) check_vhpi_error();\n    }\n}\n\nbool get_range(vhpiHandleT hdl, vhpiIntT dim, int *left, int *right,\n               gpi_range_dir *dir) {\n#ifdef IUS\n    /* IUS/Xcelium does not appear to set the vhpiIsUnconstrainedP property. IUS\n     * Docs say will return -1 if unconstrained, but with vhpiIntT being\n     * unsigned, the value returned is below.\n     */\n    const vhpiIntT UNCONSTRAINED = 2147483647;\n#endif\n\n    bool error = true;\n\n    vhpiHandleT base_hdl = vhpi_handle(vhpiBaseType, hdl);\n\n    if (base_hdl == NULL) {\n        vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, hdl);\n\n        if (st_hdl != NULL) {\n            base_hdl = vhpi_handle(vhpiBaseType, st_hdl);\n            vhpi_release_handle(st_hdl);\n        }\n    }\n\n    if (base_hdl != NULL) {\n        vhpiHandleT it = vhpi_iterator(vhpiConstraints, base_hdl);\n        vhpiIntT curr_idx = 0;\n\n        if (it != NULL) {\n            vhpiHandleT constraint;\n            while ((constraint = vhpi_scan(it)) != NULL) {\n                if (curr_idx == dim) {\n                    vhpi_release_handle(it);\n                    vhpiIntT l_rng = vhpi_get(vhpiLeftBoundP, constraint);\n                    vhpiIntT r_rng = vhpi_get(vhpiRightBoundP, constraint);\n#ifdef IUS\n                    if (l_rng != UNCONSTRAINED && r_rng != UNCONSTRAINED) {\n#else\n                    if (!vhpi_get(vhpiIsUnconstrainedP, constraint)) {\n#endif\n                        error = false;\n                        *left = static_cast<int>(l_rng);\n                        *right = static_cast<int>(r_rng);\n#ifdef MODELSIM\n                        /* Issue #4236: Questa's VHPI sets vhpiIsUpP incorrectly\n                         * so we must rely on the values of `left` and `right`\n                         * to infer direction.\n                         */\n                        if (*left < *right) {\n#else\n                        if (vhpi_get(vhpiIsUpP, constraint) == 1) {\n#endif\n                            *dir = GPI_RANGE_UP;\n                        } else {\n                            *dir = GPI_RANGE_DOWN;\n                        }\n                    }\n                    break;\n                }\n                ++curr_idx;\n            }\n        }\n        vhpi_release_handle(base_hdl);\n    }\n\n    if (error) {\n        vhpiHandleT sub_type_hdl = vhpi_handle(vhpiSubtype, hdl);\n\n        if (sub_type_hdl != NULL) {\n            vhpiHandleT it = vhpi_iterator(vhpiConstraints, sub_type_hdl);\n            vhpiIntT curr_idx = 0;\n\n            if (it != NULL) {\n                vhpiHandleT constraint;\n                while ((constraint = vhpi_scan(it)) != NULL) {\n                    if (curr_idx == dim) {\n                        vhpi_release_handle(it);\n\n                        /* IUS/Xcelium only sets the vhpiIsUnconstrainedP\n                         * incorrectly on the base type */\n                        if (!vhpi_get(vhpiIsUnconstrainedP, constraint)) {\n                            error = false;\n                            *left = static_cast<int>(\n                                vhpi_get(vhpiLeftBoundP, constraint));\n                            *right = static_cast<int>(\n                                vhpi_get(vhpiRightBoundP, constraint));\n#ifdef MODELSIM\n                            /* Issue #4236: See above */\n                            if (*left < *right) {\n#else\n                            if (vhpi_get(vhpiIsUpP, constraint) == 1) {\n#endif\n                                *dir = GPI_RANGE_UP;\n                            } else {\n                                *dir = GPI_RANGE_DOWN;\n                            }\n                        }\n                        break;\n                    }\n                    ++curr_idx;\n                }\n            }\n            vhpi_release_handle(sub_type_hdl);\n        }\n    }\n\n    return error;\n}\n\nint VhpiArrayObjHdl::initialise(const std::string &name,\n                                const std::string &fq_name) {\n    vhpiHandleT handle = GpiObjHdl::get_handle<vhpiHandleT>();\n\n    m_indexable = true;\n\n    vhpiHandleT type = vhpi_handle(vhpiBaseType, handle);\n\n    if (type == NULL) {\n        vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, handle);\n\n        if (st_hdl != NULL) {\n            type = vhpi_handle(vhpiBaseType, st_hdl);\n            vhpi_release_handle(st_hdl);\n        }\n    }\n\n    if (NULL == type) {\n        LOG_ERROR(\"VHPI: Unable to get vhpiBaseType for %s\", fq_name.c_str());\n        return -1;\n    }\n\n    vhpiIntT num_dim = vhpi_get(vhpiNumDimensionsP, type);\n    vhpiIntT dim_idx = 0;\n\n    /* Need to determine which dimension constraint is needed */\n    if (num_dim > 1) {\n        std::string hdl_name = vhpi_get_str(vhpiCaseNameP, handle);\n\n        if (hdl_name.length() < name.length()) {\n            std::string pseudo_idx = name.substr(hdl_name.length());\n\n            while (pseudo_idx.length() > 0) {\n                std::size_t found = pseudo_idx.find_first_of(\")\");\n\n                if (found != std::string::npos) {\n                    ++dim_idx;\n                    pseudo_idx = pseudo_idx.substr(found + 1);\n                } else {\n                    break;\n                }\n            }\n        }\n    }\n\n    bool error =\n        get_range(handle, dim_idx, &m_range_left, &m_range_right, &m_range_dir);\n\n    if (error) {\n        LOG_ERROR(\n            \"VHPI: Unable to obtain constraints for an indexable object %s.\",\n            fq_name.c_str());\n        return -1;\n    }\n\n    if (m_range_dir == GPI_RANGE_DOWN) {\n        m_num_elems = m_range_left - m_range_right + 1;\n    } else {\n        m_num_elems = m_range_right - m_range_left + 1;\n    }\n    if (m_num_elems < 0) {\n        m_num_elems = 0;\n    }\n\n    return GpiObjHdl::initialise(name, fq_name);\n}\n\nint VhpiObjHdl::initialise(const std::string &name,\n                           const std::string &fq_name) {\n    vhpiHandleT handle = GpiObjHdl::get_handle<vhpiHandleT>();\n    if (handle != NULL && m_type != GPI_STRUCTURE) {\n        vhpiHandleT du_handle = vhpi_handle(vhpiDesignUnit, handle);\n        if (du_handle != NULL) {\n            vhpiHandleT pu_handle = vhpi_handle(vhpiPrimaryUnit, du_handle);\n            if (pu_handle != NULL) {\n                const char *str;\n                str = vhpi_get_str(vhpiNameP, pu_handle);\n                if (str != NULL) m_definition_name = str;\n\n                str = vhpi_get_str(vhpiFileNameP, pu_handle);\n                if (str != NULL) m_definition_file = str;\n            }\n        }\n    }\n\n    return GpiObjHdl::initialise(name, fq_name);\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vhpi/VhpiSignal.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <cassert>\n#include <cstring>\n#include <limits>  // numeric_limits\n\n#include \"../logging.hpp\"\n#include \"./VhpiImpl.hpp\"\n#include \"_vendor/vhpi/vhpi_user.h\"\n\nnamespace {\nusing bufSize_type = decltype(vhpiValueT::bufSize);\n}\n\nVhpiSignalObjHdl::~VhpiSignalObjHdl() {\n    switch (m_value.format) {\n        case vhpiIntVecVal:\n        case vhpiEnumVecVal:\n        case vhpiLogicVecVal:\n            delete[] m_value.value.enumvs;\n        default:\n            break;\n    }\n\n    if (m_binvalue.value.str) delete[] m_binvalue.value.str;\n\n    LOG_DEBUG(\"VHPI: Releasing VhpiSignalObjHdl handle for %s at %p\",\n              get_fullname_str(), (void *)get_handle<vhpiHandleT>());\n    if (vhpi_release_handle(get_handle<vhpiHandleT>())) check_vhpi_error();\n}\n\nvhpiPutValueModeT map_put_value_mode(gpi_set_action action) {\n    vhpiPutValueModeT put_value_mode = vhpiDeposit;\n    switch (action) {\n        case GPI_DEPOSIT:\n        case GPI_NO_DELAY:\n            put_value_mode = vhpiDepositPropagate;\n            break;\n        case GPI_FORCE:\n            put_value_mode = vhpiForcePropagate;\n            break;\n        case GPI_RELEASE:\n            put_value_mode = vhpiRelease;\n            break;\n        default:\n            assert(0);\n    }\n    return put_value_mode;\n}\n\nint VhpiSignalObjHdl::initialise(const std::string &name,\n                                 const std::string &fq_name) {\n    // Determine the type of object, either scalar or vector\n    m_value.format = vhpiObjTypeVal;\n    m_value.bufSize = 0;\n    m_value.value.str = NULL;\n    m_value.numElems = 0;\n    /* We also alloc a second value member for use with read string operations\n     */\n    m_binvalue.format = vhpiBinStrVal;\n    m_binvalue.bufSize = 0;\n    m_binvalue.numElems = 0;\n    m_binvalue.value.str = NULL;\n\n    vhpiHandleT handle = GpiObjHdl::get_handle<vhpiHandleT>();\n\n    if (0 > vhpi_get_value(get_handle<vhpiHandleT>(), &m_value)) {\n        LOG_ERROR(\"VHPI: vhpi_get_value failed for %s (%s)\", fq_name.c_str(),\n                  vhpi_get_str(vhpiKindStrP, handle));\n        return -1;\n    }\n\n    LOG_DEBUG(\n        \"VHPI: Found %s of format type %s (%d) format object with %d elems \"\n        \"buffsize %d size %d\",\n        name.c_str(), VhpiImpl::format_to_string(m_value.format),\n        m_value.format, m_value.numElems, m_value.bufSize,\n        vhpi_get(vhpiSizeP, handle));\n\n    // Default - overridden below in certain special cases\n    m_num_elems = m_value.numElems;\n\n    switch (m_value.format) {\n        case vhpiIntVal:\n        case vhpiEnumVal:\n            m_num_elems = 32;\n            break;\n\n        case vhpiLongIntVal:\n        case vhpiRealVal:\n            m_num_elems = 64;\n            break;\n\n        case vhpiSmallEnumVal:\n        case vhpiCharVal:\n            m_num_elems = 8;\n            break;\n\n        case vhpiStrVal: {\n            m_indexable = true;\n            m_num_elems = static_cast<int>(vhpi_get(vhpiSizeP, handle));\n            int bufSize = m_num_elems * static_cast<int>(sizeof(vhpiCharT)) + 1;\n            m_value.bufSize = static_cast<bufSize_type>(bufSize);\n            m_value.value.str = new vhpiCharT[bufSize];\n            m_value.numElems = m_num_elems;\n            LOG_DEBUG(\"VHPI: Overriding num_elems to %d\", m_num_elems);\n            break;\n        }\n\n        default: {\n            LOG_ERROR(\n                \"VHPI: Unable to determine property for %s (%d) format object\",\n                VhpiImpl::format_to_string(m_value.format), m_value.format);\n            return -1;\n        }\n    }\n\n    if (m_indexable &&\n        get_range(handle, 0, &m_range_left, &m_range_right, &m_range_dir)) {\n        m_indexable = false;\n    }\n\n    if (m_num_elems) {\n        int bufSize = m_num_elems * static_cast<int>(sizeof(vhpiCharT)) + 1;\n        m_binvalue.bufSize = static_cast<bufSize_type>(bufSize);\n        m_binvalue.value.str = new vhpiCharT[bufSize];\n    }\n\n    return GpiObjHdl::initialise(name, fq_name);\n}\n\nint VhpiLogicSignalObjHdl::initialise(const std::string &name,\n                                      const std::string &fq_name) {\n    // Determine the type of object, either scalar or vector\n    m_value.format = vhpiLogicVal;\n    m_value.bufSize = 0;\n    m_value.value.str = NULL;\n    m_value.numElems = 0;\n    /* We also alloc a second value member for use with read string operations\n     */\n    m_binvalue.format = vhpiBinStrVal;\n    m_binvalue.bufSize = 0;\n    m_binvalue.numElems = 0;\n    m_binvalue.value.str = NULL;\n\n    vhpiHandleT handle = GpiObjHdl::get_handle<vhpiHandleT>();\n    vhpiHandleT base_hdl = vhpi_handle(vhpiBaseType, handle);\n\n    if (base_hdl == NULL) {\n        vhpiHandleT st_hdl = vhpi_handle(vhpiSubtype, handle);\n\n        if (st_hdl != NULL) {\n            base_hdl = vhpi_handle(vhpiBaseType, st_hdl);\n            vhpi_release_handle(st_hdl);\n        }\n    }\n\n    vhpiHandleT query_hdl = (base_hdl != NULL) ? base_hdl : handle;\n\n    m_num_elems = static_cast<int>(vhpi_get(vhpiSizeP, handle));\n\n    if (vhpi_get(vhpiKindP, query_hdl) == vhpiArrayTypeDeclK) {\n        m_indexable = true;\n        m_value.format = vhpiLogicVecVal;\n        int bufSize = m_num_elems * static_cast<int>(sizeof(vhpiEnumT));\n        m_value.bufSize = static_cast<bufSize_type>(bufSize);\n        m_value.value.enumvs = new vhpiEnumT[bufSize];\n    }\n\n    if (m_indexable &&\n        get_range(handle, 0, &m_range_left, &m_range_right, &m_range_dir)) {\n        m_indexable = false;\n    }\n\n    if (m_num_elems) {\n        int bufSize = m_num_elems * static_cast<int>(sizeof(vhpiCharT)) + 1;\n        m_binvalue.bufSize = static_cast<bufSize_type>(bufSize);\n        m_binvalue.value.str = new vhpiCharT[bufSize];\n    }\n\n    return GpiObjHdl::initialise(name, fq_name);\n}\n\n// Value related functions\nvhpiEnumT VhpiSignalObjHdl::chr2vhpi(const char value) {\n    switch (value) {\n        case '0':\n            return vhpi0;\n        case '1':\n            return vhpi1;\n        case 'U':\n        case 'u':\n            return vhpiU;\n        case 'Z':\n        case 'z':\n            return vhpiZ;\n        case 'X':\n        case 'x':\n            return vhpiX;\n        case 'W':\n        case 'w':\n            return vhpiW;\n        case 'L':\n        case 'l':\n            return vhpiL;\n        case 'H':\n        case 'h':\n            return vhpiH;\n        case '-':\n            return vhpiDontCare;\n        default:\n            LOG_ERROR(\"VHPI: Character '%c' is not a valid vhpiEnumT\", value);\n            return vhpiDontCare;\n    }\n}\n\n// Value related functions\nint VhpiLogicSignalObjHdl::set_signal_value(int32_t value,\n                                            gpi_set_action action) {\n    switch (m_value.format) {\n        case vhpiEnumVal:\n        case vhpiLogicVal: {\n            m_value.value.enumv = value ? vhpi1 : vhpi0;\n            break;\n        }\n\n        case vhpiEnumVecVal:\n        case vhpiLogicVecVal: {\n            int i;\n            for (i = 0; i < m_num_elems; i++)\n                m_value.value.enumvs[m_num_elems - i - 1] =\n                    value & (1 << i) ? vhpi1 : vhpi0;\n\n            m_value.numElems = m_num_elems;\n            break;\n        }\n\n        default: {\n            LOG_ERROR(\n                \"VHPI: Unable to set a std_logic signal with a raw value\");\n            return -1;\n        }\n    }\n\n    if (vhpi_put_value(GpiObjHdl::get_handle<vhpiHandleT>(), &m_value,\n                       map_put_value_mode(action))) {\n        check_vhpi_error();\n        return -1;\n    }\n\n    return 0;\n}\n\nint VhpiLogicSignalObjHdl::set_signal_value_binstr(std::string &value,\n                                                   gpi_set_action action) {\n    switch (m_value.format) {\n        case vhpiEnumVal:\n        case vhpiLogicVal: {\n            m_value.value.enumv = chr2vhpi(value.c_str()[0]);\n            break;\n        }\n\n        case vhpiEnumVecVal:\n        case vhpiLogicVecVal: {\n            if ((int)value.length() != m_num_elems) {\n                LOG_ERROR(\n                    \"VHPI: Unable to set logic vector due to the string having \"\n                    \"incorrect length.  Length of %d needs to be %d\",\n                    value.length(), m_num_elems);\n                return -1;\n            }\n\n            m_value.numElems = m_num_elems;\n\n            std::string::iterator iter;\n\n            int i = 0;\n            for (iter = value.begin();\n                 (iter != value.end()) && (i < m_num_elems); iter++, i++) {\n                m_value.value.enumvs[i] = chr2vhpi(*iter);\n            }\n\n            break;\n        }\n\n        default: {\n            LOG_ERROR(\n                \"VHPI: Unable to set a std_logic signal with a raw value\");\n            return -1;\n        }\n    }\n\n    if (vhpi_put_value(GpiObjHdl::get_handle<vhpiHandleT>(), &m_value,\n                       map_put_value_mode(action))) {\n        check_vhpi_error();\n        return -1;\n    }\n\n    return 0;\n}\n\n// Value related functions\nint VhpiSignalObjHdl::set_signal_value(int32_t value, gpi_set_action action) {\n    switch (m_value.format) {\n        case vhpiEnumVecVal:\n        case vhpiLogicVecVal: {\n            int i;\n            for (i = 0; i < m_num_elems; i++)\n                m_value.value.enumvs[m_num_elems - i - 1] =\n                    value & (1 << i) ? vhpi1 : vhpi0;\n\n            // Since we may not get the numElems correctly from the sim and have\n            // to infer it we also need to set it here as well each time.\n\n            m_value.numElems = m_num_elems;\n            break;\n        }\n\n        case vhpiLogicVal:\n        case vhpiEnumVal: {\n            m_value.value.enumv = static_cast<vhpiEnumT>(value);\n            break;\n        }\n\n        case vhpiSmallEnumVal: {\n            m_value.value.smallenumv = static_cast<vhpiSmallEnumT>(value);\n            break;\n        }\n\n        case vhpiIntVal: {\n            m_value.value.intg = static_cast<vhpiIntT>(value);\n            break;\n        }\n\n        case vhpiCharVal: {\n            using CharLimits = std::numeric_limits<vhpiCharT>;\n            if ((value > CharLimits::max()) || (value < CharLimits::min())) {\n                LOG_ERROR(\"VHPI: Data loss detected\");\n                return -1;\n            }\n            m_value.value.ch = static_cast<vhpiCharT>(value);\n            break;\n        }\n\n        default: {\n            LOG_ERROR(\"VHPI: Unable to handle this format type %s\",\n                      VhpiImpl::format_to_string(m_value.format));\n            return -1;\n        }\n    }\n    if (vhpi_put_value(GpiObjHdl::get_handle<vhpiHandleT>(), &m_value,\n                       map_put_value_mode(action))) {\n        check_vhpi_error();\n        return -1;\n    }\n\n    return 0;\n}\n\nint VhpiSignalObjHdl::set_signal_value(double value, gpi_set_action action) {\n    switch (m_value.format) {\n        case vhpiRealVal:\n            m_value.numElems = 1;\n            m_value.bufSize = sizeof(value);\n            m_value.value.real = value;\n            break;\n\n        default: {\n            LOG_ERROR(\"VHPI: Unable to set a Real handle with format type %s\",\n                      VhpiImpl::format_to_string(m_value.format));\n            return -1;\n        }\n    }\n\n    if (vhpi_put_value(GpiObjHdl::get_handle<vhpiHandleT>(), &m_value,\n                       map_put_value_mode(action))) {\n        check_vhpi_error();\n        return -1;\n    }\n\n    return 0;\n}\n\nint VhpiSignalObjHdl::set_signal_value_binstr(std::string &value,\n                                              gpi_set_action action) {\n    switch (m_value.format) {\n        case vhpiEnumVal:\n        case vhpiLogicVal: {\n            m_value.value.enumv = chr2vhpi(value.c_str()[0]);\n            break;\n        }\n\n        case vhpiEnumVecVal:\n        case vhpiLogicVecVal: {\n            if ((int)value.length() != m_num_elems) {\n                LOG_ERROR(\n                    \"VHPI: Unable to set logic vector due to the string having \"\n                    \"incorrect length.  Length of %d needs to be %d\",\n                    value.length(), m_num_elems);\n                return -1;\n            }\n\n            m_value.numElems = m_num_elems;\n\n            std::string::iterator iter;\n\n            int i = 0;\n            for (iter = value.begin();\n                 (iter != value.end()) && (i < m_num_elems); iter++, i++) {\n                m_value.value.enumvs[i] = chr2vhpi(*iter);\n            }\n\n            break;\n        }\n\n        default: {\n            LOG_ERROR(\"VHPI: Unable to handle this format type: %s\",\n                      VhpiImpl::format_to_string(m_value.format));\n            return -1;\n        }\n    }\n\n    if (vhpi_put_value(GpiObjHdl::get_handle<vhpiHandleT>(), &m_value,\n                       map_put_value_mode(action))) {\n        check_vhpi_error();\n        return -1;\n    }\n\n    return 0;\n}\n\nint VhpiSignalObjHdl::set_signal_value_str(std::string &value,\n                                           gpi_set_action action) {\n    switch (m_value.format) {\n        case vhpiStrVal: {\n            std::vector<char> writable(value.begin(), value.end());\n            writable.push_back('\\0');\n            strncpy(m_value.value.str, &writable[0],\n                    static_cast<size_t>(m_value.numElems));\n            m_value.value.str[m_value.numElems] = '\\0';\n            break;\n        }\n\n        default: {\n            LOG_ERROR(\"VHPI: Unable to handle this format type: %s\",\n                      VhpiImpl::format_to_string(m_value.format));\n            return -1;\n        }\n    }\n\n    if (vhpi_put_value(GpiObjHdl::get_handle<vhpiHandleT>(), &m_value,\n                       map_put_value_mode(action))) {\n        check_vhpi_error();\n        return -1;\n    }\n\n    return 0;\n}\n\nconst char *VhpiSignalObjHdl::get_signal_value_binstr() {\n    switch (m_value.format) {\n        case vhpiRealVal:\n            LOG_INFO(\"VHPI: get_signal_value_binstr not supported for %s\",\n                     VhpiImpl::format_to_string(m_value.format));\n            return \"\";\n        default: {\n            // Getting the value of a zero-length array can cause some\n            // simulators to error.\n            if (m_num_elems == 0) {\n                return \"\";\n            }\n            int ret = vhpi_get_value(GpiObjHdl::get_handle<vhpiHandleT>(),\n                                     &m_binvalue);\n            if (ret) {\n                check_vhpi_error();\n                LOG_ERROR(\n                    \"VHPI: Size of m_binvalue.value.str was not large enough: \"\n                    \"req=%d have=%d for type %s\",\n                    ret, m_binvalue.bufSize,\n                    VhpiImpl::format_to_string(m_value.format));\n            }\n\n            return m_binvalue.value.str;\n        }\n    }\n}\n\nconst char *VhpiSignalObjHdl::get_signal_value_str() {\n    switch (m_value.format) {\n        case vhpiStrVal: {\n            // Getting the value of a zero-length array can cause some\n            // simulators to error.\n            if (m_num_elems == 0) {\n                return \"\";\n            }\n            int ret =\n                vhpi_get_value(GpiObjHdl::get_handle<vhpiHandleT>(), &m_value);\n            if (ret) {\n                check_vhpi_error();\n                LOG_ERROR(\n                    \"VHPI: Size of m_value.value.str was not large enough: \"\n                    \"req=%d have=%d for type %s\",\n                    ret, m_value.bufSize,\n                    VhpiImpl::format_to_string(m_value.format));\n            }\n            break;\n        }\n        default: {\n            LOG_ERROR(\"VHPI: Reading strings not valid for this handle\");\n            return \"\";\n        }\n    }\n    return m_value.value.str;\n}\n\ndouble VhpiSignalObjHdl::get_signal_value_real() {\n    m_value.format = vhpiRealVal;\n    m_value.numElems = 1;\n    m_value.bufSize = sizeof(double);\n\n    if (vhpi_get_value(GpiObjHdl::get_handle<vhpiHandleT>(), &m_value)) {\n        check_vhpi_error();\n        LOG_ERROR(\"VHPI: Failed to get value of type real\");\n    }\n    return m_value.value.real;\n}\n\nlong VhpiSignalObjHdl::get_signal_value_long() {\n    vhpiValueT value;\n    value.format = vhpiIntVal;\n    value.numElems = 0;\n\n    if (vhpi_get_value(GpiObjHdl::get_handle<vhpiHandleT>(), &value)) {\n        check_vhpi_error();\n        LOG_ERROR(\"VHPI: Failed to get value of type long\");\n    }\n\n    return static_cast<int32_t>(value.value.intg);\n}\n\nGpiCbHdl *VhpiSignalObjHdl::register_value_change_callback(\n    gpi_edge edge, int (*cb_func)(void *), void *cb_data) {\n    auto cb_hdl = new VhpiValueCbHdl(m_impl, this, edge);\n    auto err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        delete cb_hdl;\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nint VhpiSignalObjHdl::get_signed() {\n    if (m_type == GPI_INTEGER) {\n        return 1;\n    } else {\n        return -1;\n    }\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vpi/VpiCbHdl.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include \"../gpi_priv.hpp\"\n#include \"../logging.hpp\"\n#include \"./VpiImpl.hpp\"\n\n#ifndef VPI_NO_QUEUE_SETIMMEDIATE_CALLBACKS\n#include <algorithm>\n#include <deque>\n\nstatic std::deque<VpiCbHdl *> cb_queue;\n#endif\n\nstatic int32_t handle_vpi_callback_(VpiCbHdl *cb_hdl) {\n    int error = (!cb_hdl);\n    // LCOV_EXCL_START\n    if (error) {\n        LOG_CRITICAL(\"VPI: Callback data corrupted: ABORTING\");\n    }\n    // LCOV_EXCL_STOP\n\n    if (!error) {\n        GPI_TO_USER_CB(VPI);\n        error = cb_hdl->run();\n        USER_CB_TO_GPI(VPI);\n    }\n\n    if (error) {\n        gpi_end_of_sim_time();\n    }\n\n    return error ? -1 : 0;\n}\n\n// Main re-entry point for callbacks from simulator\nint32_t handle_vpi_callback(p_cb_data cb_data) {\n    SIM_TO_GPI(VPI, cb_data->user_data,\n               VpiImpl::reason_to_string(cb_data->reason));\n\n    int ret = 0;\n#ifdef VPI_NO_QUEUE_SETIMMEDIATE_CALLBACKS\n    VpiCbHdl *cb_hdl = (VpiCbHdl *)cb_data->user_data;\n    ret = handle_vpi_callback_(cb_hdl);\n#else\n    // must push things into a queue because Icarus (gh-4067), Xcelium\n    // (gh-4013), and Questa (gh-4105) react to value changes on signals that\n    // are set with vpiNoDelay immediately, and not after the current callback\n    // has ended, causing re-entrancy.\n    static bool reacting = false;\n    VpiCbHdl *cb_hdl = (VpiCbHdl *)cb_data->user_data;\n    if (reacting) {\n        cb_queue.push_back(cb_hdl);\n    } else {\n        reacting = true;\n        ret = handle_vpi_callback_(cb_hdl);\n        while (!cb_queue.empty()) {\n            handle_vpi_callback_(cb_queue.front());\n            cb_queue.pop_front();\n        }\n        reacting = false;\n    }\n#endif\n    GPI_TO_SIM(VPI, cb_data->user_data);\n    return ret;\n}\n\nVpiCbHdl::VpiCbHdl(GpiImplInterface *impl) : GpiCbHdl(impl) {\n    vpi_time.high = 0;\n    vpi_time.low = 0;\n    vpi_time.type = vpiSimTime;\n\n    cb_data.reason = 0;\n    cb_data.cb_rtn = handle_vpi_callback;\n    cb_data.obj = NULL;\n    cb_data.time = &vpi_time;\n    cb_data.value = NULL;\n    cb_data.index = 0;\n    cb_data.user_data = (char *)this;\n}\n\nint VpiCbHdl::arm() {\n    vpiHandle new_hdl = vpi_register_cb(&cb_data);\n    LOG_TRACE(\"VPI: Registered callback %p for reason %s\", this,\n              VpiImpl::reason_to_string(cb_data.reason));\n\n    if (!new_hdl) {\n        LOG_ERROR(\n            \"VPI: Unable to register a callback handle for VPI type %s(%d)\",\n            VpiImpl::reason_to_string(cb_data.reason), cb_data.reason);\n        check_vpi_error();\n        return -1;\n    }\n\n    m_obj_hdl = new_hdl;\n\n    return 0;\n}\n\nint VpiCbHdl::remove() {\n#ifndef VPI_NO_QUEUE_SETIMMEDIATE_CALLBACKS\n    // check if it's already fired and is in callback queue\n    auto it = std::find(cb_queue.begin(), cb_queue.end(), this);\n    if (it != cb_queue.end()) {\n        cb_queue.erase(it);\n        // In Verilator some callbacks are recurring, so we *should* try to\n        // remove by falling through to the code below. Other sims don't like\n        // removing callbacks that have already fired.\n#ifndef VERILATOR\n        // It's already fired, we shouldn't try to vpi_remove_cb() it now.\n        delete this;\n        return 0;\n#endif\n    }\n#endif\n\n    auto err = vpi_remove_cb(get_handle<vpiHandle>());\n    // LCOV_EXCL_START\n    if (!err) {\n        LOG_DEBUG(\"VPI: Unable to remove callback\");\n        check_vpi_error();\n        // put it in a removed state so if it fires we can squash it\n        m_removed = true;\n    }\n    // LCOV_EXCL_STOP\n    else {\n        delete this;\n    }\n    return 0;\n}\n\nint VpiCbHdl::run() {\n    int res = 0;\n\n    // LCOV_EXCL_START\n    if (!m_removed) {\n        // Only call up if not removed.\n        res = m_cb_func(m_cb_data);\n    }\n    // LCOV_EXCL_STOP\n\n// Verilator seems to think some callbacks are recurring that Icarus and other\n// sims do not. So we remove all callbacks here after firing because Verilator\n// doesn't seem to mind (other sims do).\n#ifdef VERILATOR\n    // Remove recurring callback once fired\n    auto err = vpi_remove_cb(get_handle<vpiHandle>());\n    // LCOV_EXCL_START\n    if (!err) {\n        LOG_DEBUG(\"VPI: Unable to remove callback\");\n        check_vpi_error();\n        // put it in a removed state so if it fires we can squash it\n        m_removed = true;\n    }\n    // LCOV_EXCL_STOP\n    else {\n        delete this;\n    }\n#else\n    // For other simulators: VPI spec says one-shot callbacks auto-cleanup\n    // their handle after firing. We just need to delete the C++ object.\n    delete this;\n#endif\n\n    return res;\n}\n\nVpiValueCbHdl::VpiValueCbHdl(GpiImplInterface *impl, VpiSignalObjHdl *signal,\n                             gpi_edge edge)\n    : VpiCbHdl(impl), m_signal(signal), m_edge(edge) {\n    vpi_time.type = vpiSuppressTime;\n    m_vpi_value.format = vpiIntVal;\n\n    cb_data.reason = cbValueChange;\n    cb_data.time = &vpi_time;\n    cb_data.value = &m_vpi_value;\n    cb_data.obj = m_signal->get_handle<vpiHandle>();\n}\n\nint VpiValueCbHdl::run() {\n    // LCOV_EXCL_START\n    if (m_removed) {\n        // Only call up if not removed.\n        return 0;\n    }\n    // LCOV_EXCL_STOP\n\n    bool pass = false;\n    switch (m_edge) {\n        case GPI_RISING: {\n            pass = !strcmp(m_signal->get_signal_value_binstr(), \"1\");\n            break;\n        }\n        case GPI_FALLING: {\n            pass = !strcmp(m_signal->get_signal_value_binstr(), \"0\");\n            break;\n        }\n        case GPI_VALUE_CHANGE: {\n            pass = true;\n            break;\n        }\n    }\n\n    int res = 0;\n    if (pass) {\n        res = m_cb_func(m_cb_data);\n\n        // Remove recurring callback once fired.\n        auto err = vpi_remove_cb(get_handle<vpiHandle>());\n        // LCOV_EXCL_START\n        if (!err) {\n            LOG_DEBUG(\"VPI: Unable to remove callback\");\n            check_vpi_error();\n            // If we fail to remove the callback, put it in a removed state so\n            // if it fires we can squash it.\n            m_removed = true;\n        }\n        // LCOV_EXCL_STOP\n        else {\n            delete this;\n        }\n    }  // else Don't remove and let it fire again.\n\n    return res;\n}\n\nVpiStartupCbHdl::VpiStartupCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) {\n#ifndef IUS\n    cb_data.reason = cbStartOfSimulation;\n#else\n    vpi_time.high = (uint32_t)(0);\n    vpi_time.low = (uint32_t)(0);\n    vpi_time.type = vpiSimTime;\n    cb_data.reason = cbAfterDelay;\n#endif\n}\n\nVpiShutdownCbHdl::VpiShutdownCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) {\n    cb_data.reason = cbEndOfSimulation;\n}\n\nVpiTimedCbHdl::VpiTimedCbHdl(GpiImplInterface *impl, uint64_t time)\n    : VpiCbHdl(impl) {\n    vpi_time.high = (uint32_t)(time >> 32);\n    vpi_time.low = (uint32_t)(time);\n    vpi_time.type = vpiSimTime;\n\n    cb_data.reason = cbAfterDelay;\n}\n\nVpiReadWriteCbHdl::VpiReadWriteCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) {\n    cb_data.reason = cbReadWriteSynch;\n}\n\nVpiReadOnlyCbHdl::VpiReadOnlyCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) {\n    cb_data.reason = cbReadOnlySynch;\n}\n\nVpiNextPhaseCbHdl::VpiNextPhaseCbHdl(GpiImplInterface *impl) : VpiCbHdl(impl) {\n    cb_data.reason = cbNextSimTime;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vpi/VpiImpl.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include \"./VpiImpl.hpp\"\n\n#include <gpi.h>\n#include <vpi_user_ext.h>\n\n#include \"../logging.hpp\"\n#include \"_vendor/vpi/sv_vpi_user.h\"\n#include \"_vendor/vpi/vpi_user.h\"\n\n#define CASE_STR(_X) \\\n    case _X:         \\\n        return #_X\n\nconst char *VpiImpl::reason_to_string(int reason) {\n    switch (reason) {\n        CASE_STR(cbValueChange);\n        CASE_STR(cbAtStartOfSimTime);\n        CASE_STR(cbReadWriteSynch);\n        CASE_STR(cbReadOnlySynch);\n        CASE_STR(cbNextSimTime);\n        CASE_STR(cbAfterDelay);\n        CASE_STR(cbStartOfSimulation);\n        CASE_STR(cbEndOfSimulation);\n\n        default:\n            return \"unknown\";\n    }\n}\n\n#undef CASE_STR\n\nvoid VpiImpl::get_sim_time(uint32_t *high, uint32_t *low) {\n    s_vpi_time vpi_time_s;\n    vpi_time_s.type = vpiSimTime;  // vpiSimTime;\n    vpi_get_time(NULL, &vpi_time_s);\n    check_vpi_error();\n    *high = vpi_time_s.high;\n    *low = vpi_time_s.low;\n}\n\nvoid VpiImpl::get_sim_precision(int32_t *precision) {\n    *precision = vpi_get(vpiTimePrecision, NULL);\n}\n\nconst char *VpiImpl::get_simulator_product() {\n    if (m_product.empty()) {\n        s_vpi_vlog_info info;\n        if (!vpi_get_vlog_info(&info)) {\n            LOG_WARN(\"Could not obtain info about the simulator\");\n            m_product = \"UNKNOWN\";\n            m_version = \"UNKNOWN\";\n            m_argc = 0;\n            m_argv = nullptr;\n        } else {\n            m_product = info.product;\n            m_version = info.version;\n            m_argc = info.argc;\n            m_argv = info.argv;\n        }\n    }\n    return m_product.c_str();\n}\n\nconst char *VpiImpl::get_simulator_version() {\n    get_simulator_product();\n    return m_version.c_str();\n}\n\nint VpiImpl::get_simulator_args(int *argc, char const *const **argv) {\n    get_simulator_product();\n    *argc = m_argc;\n    *argv = m_argv;\n    return 0;\n}\n\nstatic gpi_objtype to_gpi_objtype(int32_t vpitype, int num_elements = 0,\n                                  bool is_vector = false) {\n    switch (vpitype) {\n        case vpiNet:\n        case vpiNetBit:\n        case vpiBitVar:\n        case vpiReg:\n        case vpiRegBit:\n        case vpiMemoryWord:\n        case vpiPackedArrayVar:\n        case vpiPackedArrayNet:\n            if (is_vector || num_elements > 1) {\n                return GPI_PACKED_OBJECT;\n            } else {\n                return GPI_LOGIC;\n            }\n            break;\n\n        case vpiRealNet:\n        case vpiRealVar:\n            return GPI_REAL;\n\n        case vpiInterfaceArray:\n        case vpiRegArray:\n        case vpiNetArray:\n        case vpiGenScopeArray:\n        case vpiMemory:\n            return GPI_ARRAY;\n\n        case vpiEnumNet:\n        case vpiEnumVar:\n            return GPI_ENUM;\n\n        case vpiIntVar:\n        case vpiIntNet:\n        case vpiIntegerVar:\n        case vpiIntegerNet:\n        case vpiByteVar:\n        case vpiByteNet:\n        case vpiShortIntVar:\n        case vpiShortIntNet:\n        case vpiLongIntVar:\n        case vpiLongIntNet:\n            return GPI_INTEGER;\n\n        case vpiStructVar:\n        case vpiStructNet:\n        case vpiUnionVar:\n        case vpiUnionNet:\n            return GPI_STRUCTURE;\n\n        case vpiInterface:\n        case vpiModule:\n        case vpiPort:\n        case vpiGate:\n        case vpiSwitch:\n        case vpiPrimTerm:\n        case vpiGenScope:\n            return GPI_MODULE;\n\n        case vpiPackage:\n            return GPI_PACKAGE;\n\n        case vpiStringVar:\n            return GPI_STRING;\n\n        default:\n            LOG_DEBUG(\"Unable to map VPI type %d onto GPI type\", vpitype);\n            return GPI_UNKNOWN;\n    }\n}\n\nstatic gpi_objtype const_type_to_gpi_objtype(int32_t const_type) {\n    // Most simulators only return vpiDecConst or vpiBinaryConst\n    switch (const_type) {\n#ifdef IUS\n        case vpiUndefined:\n            LOG_WARN(\n                \"VPI: Xcelium reports undefined parameters as vpiUndefined, \"\n                \"guessing this is a logic vector\");\n            return GPI_LOGIC_ARRAY;\n#endif\n        case vpiDecConst:\n        case vpiBinaryConst:\n        case vpiOctConst:\n        case vpiHexConst:\n        case vpiIntConst:\n            return GPI_PACKED_OBJECT;\n        case vpiRealConst:\n            return GPI_REAL;\n        case vpiStringConst:\n            return GPI_STRING;\n        // case vpiTimeConst:  // Not implemented\n        default:\n            LOG_WARN(\n                \"Unable to map vpiConst type %d onto GPI type, \"\n                \"guessing this is a logic vector\",\n                const_type);\n            return GPI_PACKED_OBJECT;\n    }\n}\n\nGpiObjHdl *VpiImpl::create_gpi_obj_from_handle(vpiHandle new_hdl,\n                                               const std::string &name,\n                                               const std::string &fq_name) {\n    int32_t type;\n    GpiObjHdl *new_obj = NULL;\n    if (vpiUnknown == (type = vpi_get(vpiType, new_hdl))) {\n        LOG_DEBUG(\"vpiUnknown returned from vpi_get(vpiType, ...)\");\n        return NULL;\n    }\n\n    /* What sort of instance is this ?*/\n    switch (type) {\n        case vpiNet:\n        case vpiNetBit:\n        case vpiBitVar:\n        case vpiReg:\n        case vpiRegBit:\n        case vpiEnumNet:\n        case vpiEnumVar:\n        case vpiIntVar:\n        case vpiIntNet:\n        case vpiIntegerVar:\n        case vpiIntegerNet:\n        case vpiByteVar:\n        case vpiByteNet:\n        case vpiShortIntVar:\n        case vpiShortIntNet:\n        case vpiLongIntVar:\n        case vpiLongIntNet:\n        case vpiPackedArrayVar:\n        case vpiPackedArrayNet:\n        case vpiRealVar:\n        case vpiRealNet:\n        case vpiStringVar:\n        case vpiMemoryWord:\n        case vpiInterconnectNet: {\n            const auto is_vector = vpi_get(vpiVector, new_hdl);\n            PLI_INT32 num_elements;\n#ifdef MODELSIM\n            // Questa defines the vpiSize of all of scalar types as 1.\n            switch (type) {\n                case vpiByteNet:\n                case vpiByteVar:\n                    num_elements = 8;\n                    break;\n                case vpiShortIntNet:\n                case vpiShortIntVar:\n                    num_elements = 16;\n                    break;\n                case vpiEnumNet:\n                case vpiEnumVar:\n                case vpiIntNet:\n                case vpiIntVar:\n                case vpiIntegerNet:\n                case vpiIntegerVar:\n                    num_elements = 32;\n                    break;\n                case vpiLongIntNet:\n                case vpiLongIntVar:\n                case vpiRealNet:\n                case vpiRealVar:\n                    num_elements = 64;\n                    break;\n                default:\n                    num_elements = vpi_get(vpiSize, new_hdl);\n                    break;\n            }\n#else\n            num_elements = vpi_get(vpiSize, new_hdl);\n#endif\n            new_obj = new VpiSignalObjHdl(\n                this, new_hdl, to_gpi_objtype(type, num_elements, is_vector),\n                false);\n            break;\n        }\n        case vpiParameter:\n        case vpiConstant: {\n            auto const_type = vpi_get(vpiConstType, new_hdl);\n            new_obj = new VpiSignalObjHdl(\n                this, new_hdl, const_type_to_gpi_objtype(const_type), true);\n            break;\n        }\n        case vpiRegArray:\n        case vpiNetArray:\n        case vpiInterfaceArray:\n        case vpiMemory:\n        case vpiInterconnectArray: {\n            const auto is_vector = vpi_get(vpiVector, new_hdl);\n            const auto num_elements = vpi_get(vpiSize, new_hdl);\n            new_obj = new VpiArrayObjHdl(\n                this, new_hdl, to_gpi_objtype(type, num_elements, is_vector));\n            break;\n        }\n        case vpiStructVar:\n        case vpiStructNet:\n        case vpiUnionVar:\n        case vpiUnionNet: {\n            auto is_vector = false;\n            if (vpi_get(vpiPacked, new_hdl)) {\n                LOG_DEBUG(\"VPI: Found packed struct/union data type\");\n                new_obj = new VpiSignalObjHdl(this, new_hdl,\n                                              GPI_PACKED_STRUCTURE, false);\n                break;\n            } else if (vpi_get(vpiVector, new_hdl)) {\n                is_vector = true;\n            }\n            const auto num_elements = vpi_get(vpiSize, new_hdl);\n            new_obj = new VpiObjHdl(\n                this, new_hdl, to_gpi_objtype(type, num_elements, is_vector));\n            break;\n        }\n        case vpiModule:\n        case vpiInterface:\n        case vpiPort:\n        case vpiGate:\n        case vpiSwitch:\n        case vpiPrimTerm:\n        case vpiGenScope:\n        case vpiGenScopeArray: {\n            std::string hdl_name = vpi_get_str(vpiName, new_hdl);\n\n            if (hdl_name != name) {\n                LOG_DEBUG(\"Found pseudo-region %s (hdl_name=%s but name=%s)\",\n                          fq_name.c_str(), hdl_name.c_str(), name.c_str());\n                new_obj = new VpiObjHdl(this, new_hdl, GPI_GENARRAY);\n            } else {\n                new_obj = new VpiObjHdl(this, new_hdl, to_gpi_objtype(type));\n            }\n            break;\n        }\n        default:\n            /* We should only print a warning here if the type is really\n               Verilog, It could be VHDL as some simulators allow querying of\n               both languages via the same handle\n               */\n            const char *type_name = vpi_get_str(vpiType, new_hdl);\n            std::string unknown = \"vpiUnknown\";\n            if (type_name && (unknown != type_name)) {\n                LOG_WARN(\"VPI: Not able to map type %s(%d) to object.\",\n                         type_name, type);\n            } else {\n                LOG_WARN(\"VPI: Simulator does not know this type (%d) via VPI\",\n                         type);\n            }\n            return NULL;\n    }\n\n    new_obj->initialise(name, fq_name);\n\n    LOG_DEBUG(\"VPI: Created GPI object from type %s(%d)\",\n              vpi_get_str(vpiType, new_hdl), type);\n\n    return new_obj;\n}\n\nGpiObjHdl *VpiImpl::get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) {\n    LOG_DEBUG(\"Trying to convert raw to VPI handle\");\n\n    vpiHandle new_hdl = (vpiHandle)raw_hdl;\n\n    const char *c_name = vpi_get_str(vpiName, new_hdl);\n    if (!c_name) {\n        LOG_DEBUG(\"Unable to query name of passed in handle\");\n        return NULL;\n    }\n\n    std::string name = c_name;\n    std::string fq_name =\n        parent->get_fullname() + get_type_delimiter(parent) + name;\n\n    GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name);\n    if (new_obj == NULL) {\n        vpi_free_object(new_hdl);\n        LOG_DEBUG(\"Unable to fetch object %s\", fq_name.c_str());\n        return NULL;\n    }\n    return new_obj;\n}\n\nGpiObjHdl *VpiImpl::get_child_by_name(const std::string &name,\n                                      GpiObjHdl *parent) {\n    const vpiHandle parent_hdl = parent->get_handle<vpiHandle>();\n    std::string fq_name =\n        parent->get_fullname() + get_type_delimiter(parent) + name;\n\n    vpiHandle new_hdl =\n        vpi_handle_by_name(const_cast<char *>(fq_name.c_str()), NULL);\n\n#ifdef IUS\n    if (new_hdl != NULL && vpi_get(vpiType, new_hdl) == vpiGenScope) {\n        // verify that this xcelium scope is valid, or else we segfault on the\n        // invalid scope. Xcelium only returns vpiGenScope, no vpiGenScopeArray\n\n        vpiHandle iter = vpi_iterate(vpiInternalScope, parent_hdl);\n        bool is_valid = [&]() -> bool {\n            for (auto rgn = vpi_scan(iter); rgn != NULL; rgn = vpi_scan(iter)) {\n                if (VpiImpl::compare_generate_labels(vpi_get_str(vpiName, rgn),\n                                                     name)) {\n                    return true;\n                }\n            }\n            return false;\n        }();\n        vpi_free_object(iter);\n\n        if (!is_valid) {\n            vpi_free_object(new_hdl);\n            new_hdl = NULL;\n        }\n    }\n#endif\n\n// Xcelium will segfault on a scope that doesn't exist\n#ifndef IUS\n    /* Some simulators do not support vpiGenScopeArray, only vpiGenScope:\n     * - Icarus Verilog\n     * - Verilator\n     * - Questa/Modelsim\n     *\n     * If handle is not found by name, look for a generate block with\n     * a matching prefix.\n     *     For Example:\n     *         genvar idx;\n     *         generate\n     *             for (idx = 0; idx < 5; idx = idx + 1) begin\n     *                 ...\n     *             end\n     *         endgenerate\n     *\n     *     genblk1      => vpiGenScopeArray (not found)\n     *     genblk1[0]   => vpiGenScope\n     *     ...\n     *     genblk1[4]   => vpiGenScope\n     *\n     *     genblk1 is not found directly, but if genblk1[n] is found,\n     *     genblk1 must exist, so create the pseudo-region object for it.\n     */\n    if (new_hdl == NULL) {\n        LOG_DEBUG(\n            \"Unable to find '%s' through vpi_handle_by_name, looking for \"\n            \"matching generate scope array using fallback\",\n            fq_name.c_str());\n\n        vpiHandle iter = vpi_iterate(vpiInternalScope, parent_hdl);\n        if (iter != NULL) {\n            for (auto rgn = vpi_scan(iter); rgn != NULL; rgn = vpi_scan(iter)) {\n                auto rgn_type = vpi_get(vpiType, rgn);\n                if (rgn_type == vpiGenScope || rgn_type == vpiModule) {\n                    std::string rgn_name = vpi_get_str(vpiName, rgn);\n                    if (VpiImpl::compare_generate_labels(rgn_name, name)) {\n                        new_hdl = parent_hdl;\n                        vpi_free_object(iter);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n#endif\n\n    if (new_hdl == NULL) {\n        LOG_DEBUG(\"Unable to find '%s'\", fq_name.c_str());\n        return NULL;\n    }\n\n    /* Generate Loops have inconsistent behavior across vpi tools.  A \"name\"\n     * without an index, i.e. dut.loop vs dut.loop[0], will find a handle to\n     * vpiGenScopeArray, but not all tools support iterating over the\n     * vpiGenScopeArray.  We don't want to create a GpiObjHdl to this type of\n     * vpiHandle.\n     *\n     * If this unique case is hit, we need to create the Pseudo-region, with the\n     * handle being equivalent to the parent handle.\n     */\n    if (vpi_get(vpiType, new_hdl) == vpiGenScopeArray) {\n        vpi_free_object(new_hdl);\n\n        new_hdl = parent_hdl;\n    }\n\n    GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name);\n    if (new_obj == NULL) {\n        vpi_free_object(new_hdl);\n        LOG_DEBUG(\"Unable to create object '%s'\", fq_name.c_str());\n        return NULL;\n    }\n    return new_obj;\n}\n\nGpiObjHdl *VpiImpl::get_child_by_index(int32_t index, GpiObjHdl *parent) {\n    vpiHandle vpi_hdl = parent->get_handle<vpiHandle>();\n    vpiHandle new_hdl = NULL;\n\n    char buff[14];  // needs to be large enough to hold -2^31 to 2^31-1 in\n                    // string form ('['+'-'10+']'+'\\0')\n\n    gpi_objtype obj_type = parent->get_type();\n\n    if (obj_type == GPI_GENARRAY) {\n        snprintf(buff, 14, \"[%d]\", index);\n\n        LOG_DEBUG(\"VPI: Get child at index %d of parent '%s' (pseudo-region)\",\n                  index, parent->get_name_str());\n\n        std::string idx = buff;\n        std::string hdl_name = parent->get_fullname() + idx;\n        std::vector<char> writable(hdl_name.begin(), hdl_name.end());\n        writable.push_back('\\0');\n\n        new_hdl = vpi_handle_by_name(&writable[0], NULL);\n    } else if (obj_type == GPI_LOGIC || obj_type == GPI_LOGIC_ARRAY ||\n               obj_type == GPI_ARRAY || obj_type == GPI_STRING) {\n        new_hdl = vpi_handle_by_index(vpi_hdl, index);\n\n        /* vpi_handle_by_index() doesn't work for all simulators when dealing\n         * with a two-dimensional array. For example: wire [7:0] sig_t4\n         * [0:1][0:2];\n         *\n         *    Assume vpi_hdl is for \"sig_t4\":\n         *       vpi_handle_by_index(vpi_hdl, 0);   // Returns a handle to\n         * sig_t4[0] for IUS, but NULL on Questa\n         *\n         *    Questa only works when both indices are provided, i.e. will need a\n         * pseudo-handle to behave like the first index.\n         */\n        if (new_hdl == NULL) {\n            int left = parent->get_range_left();\n            int right = parent->get_range_right();\n            bool ascending = parent->get_range_dir() == GPI_RANGE_UP;\n\n            LOG_DEBUG(\n                \"Unable to find handle through vpi_handle_by_index(), \"\n                \"attempting second method\");\n\n            if ((ascending && (index < left || index > right)) ||\n                (!ascending && (index > left || index < right))) {\n                LOG_ERROR(\n                    \"Invalid Index - Index %d is not in the range of [%d:%d]\",\n                    index, left, right);\n                return NULL;\n            }\n\n            /* Get the number of constraints to determine if the index will\n             * result in a pseudo-handle or should be found */\n            vpiHandle p_hdl = parent->get_handle<vpiHandle>();\n            vpiHandle it = vpi_iterate(vpiRange, p_hdl);\n            int constraint_cnt = 0;\n            if (it != NULL) {\n                while (vpi_scan(it) != NULL) {\n                    ++constraint_cnt;\n                }\n            } else {\n                constraint_cnt = 1;\n            }\n\n            std::string act_hdl_name = vpi_get_str(vpiName, p_hdl);\n\n            /* Removing the act_hdl_name from the parent->get_name() will leave\n             * the pseudo-indices */\n            if (act_hdl_name.length() < parent->get_name().length()) {\n                std::string idx_str =\n                    parent->get_name().substr(act_hdl_name.length());\n\n                while (idx_str.length() > 0) {\n                    std::size_t found = idx_str.find_first_of(\"]\");\n\n                    if (found != std::string::npos) {\n                        --constraint_cnt;\n                        idx_str = idx_str.substr(found + 1);\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            snprintf(buff, 14, \"[%d]\", index);\n\n            std::string idx = buff;\n            std::string hdl_name = parent->get_fullname() + idx;\n\n            std::vector<char> writable(hdl_name.begin(), hdl_name.end());\n            writable.push_back('\\0');\n\n            new_hdl = vpi_handle_by_name(&writable[0], NULL);\n\n            /* Create a pseudo-handle if not the last index into a\n             * multi-dimensional array */\n            if (new_hdl == NULL && constraint_cnt > 1) {\n                new_hdl = p_hdl;\n            }\n        }\n    } else {\n        LOG_ERROR(\n            \"VPI: Parent of type %s must be of type GPI_GENARRAY, \"\n            \"GPI_LOGIC, GPI_LOGIC, GPI_ARRAY, or GPI_STRING to have an index.\",\n            parent->get_type_str());\n        return NULL;\n    }\n\n    if (new_hdl == NULL) {\n        LOG_DEBUG(\"Unable to vpi_get_handle_by_index %s[%d]\",\n                  parent->get_name_str(), index);\n        return NULL;\n    }\n\n    snprintf(buff, 14, \"[%d]\", index);\n\n    std::string idx = buff;\n    std::string name = parent->get_name() + idx;\n    std::string fq_name = parent->get_fullname() + idx;\n    GpiObjHdl *new_obj = create_gpi_obj_from_handle(new_hdl, name, fq_name);\n    if (new_obj == NULL) {\n        vpi_free_object(new_hdl);\n        LOG_DEBUG(\"Unable to fetch object below entity (%s) at index (%d)\",\n                  parent->get_name_str(), index);\n        return NULL;\n    }\n    return new_obj;\n}\n\nGpiObjHdl *VpiImpl::get_root_handle(const char *name) {\n    vpiHandle root;\n    vpiHandle iterator;\n    GpiObjHdl *rv;\n    std::string root_name;\n\n    // vpi_iterate with a ref of NULL returns the top level module\n    iterator = vpi_iterate(vpiModule, NULL);\n    check_vpi_error();\n    if (!iterator) {\n        LOG_INFO(\"Nothing visible via VPI\");\n        return NULL;\n    }\n\n    for (root = vpi_scan(iterator); root != NULL; root = vpi_scan(iterator)) {\n        if (to_gpi_objtype(vpi_get(vpiType, root)) != GPI_MODULE) continue;\n\n        // prevents finding virtual classes (which Xcelium puts at the top-level\n        // scope) when looking for objects with get_root_handle.\n        const char *obj_name = vpi_get_str(vpiFullName, root);\n        if ((!name && obj_name[0] != '\\\\') || (name && !strcmp(name, obj_name)))\n            break;\n    }\n\n    if (!root) {\n        check_vpi_error();\n        goto error;\n    }\n\n    // Need to free the iterator if it didn't return NULL\n    if (iterator && !vpi_free_object(iterator)) {\n        LOG_WARN(\"VPI: Attempting to free root iterator failed!\");\n        check_vpi_error();\n    }\n\n    root_name = vpi_get_str(vpiFullName, root);\n    rv = new GpiObjHdl(this, root, to_gpi_objtype(vpi_get(vpiType, root)));\n    rv->initialise(root_name, root_name);\n\n    return rv;\n\nerror:\n\n    LOG_ERROR(\"VPI: Couldn't find root handle %s\", name);\n\n    iterator = vpi_iterate(vpiModule, NULL);\n\n    for (root = vpi_scan(iterator); root != NULL; root = vpi_scan(iterator)) {\n        LOG_ERROR(\"VPI: Toplevel instances: %s != %s...\", name,\n                  vpi_get_str(vpiFullName, root));\n\n        if (name == NULL || !strcmp(name, vpi_get_str(vpiFullName, root)))\n            break;\n    }\n\n    return NULL;\n}\n\nGpiIterator *VpiImpl::iterate_handle(GpiObjHdl *obj_hdl,\n                                     gpi_iterator_sel type) {\n    GpiIterator *new_iter = NULL;\n    switch (type) {\n        case GPI_OBJECTS:\n            new_iter = new VpiIterator(this, obj_hdl);\n            break;\n        case GPI_DRIVERS:\n            new_iter = new VpiSingleIterator(this, obj_hdl, vpiDriver);\n            break;\n        case GPI_LOADS:\n            new_iter = new VpiSingleIterator(this, obj_hdl, vpiLoad);\n            break;\n        case GPI_PACKAGE_SCOPES:\n            new_iter = new VpiPackageIterator(this);\n            break;\n        default:\n            LOG_WARN(\"Other iterator types not implemented yet\");\n            break;\n    }\n    return new_iter;\n}\n\nGpiCbHdl *VpiImpl::register_timed_callback(uint64_t time,\n                                           int (*cb_func)(void *),\n                                           void *cb_data) {\n    auto cb_hdl = new VpiTimedCbHdl(this, time);\n    auto err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        delete cb_hdl;\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiCbHdl *VpiImpl::register_readwrite_callback(int (*cb_func)(void *),\n                                               void *cb_data) {\n    auto cb_hdl = new VpiReadWriteCbHdl(this);\n    auto err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        delete cb_hdl;\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiCbHdl *VpiImpl::register_readonly_callback(int (*cb_func)(void *),\n                                              void *cb_data) {\n    auto cb_hdl = new VpiReadOnlyCbHdl(this);\n    auto err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        delete cb_hdl;\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\nGpiCbHdl *VpiImpl::register_nexttime_callback(int (*cb_func)(void *),\n                                              void *cb_data) {\n    auto cb_hdl = new VpiNextPhaseCbHdl(this);\n    auto err = cb_hdl->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        delete cb_hdl;\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n\n// If the Python world wants things to shut down then unregister\n// the callback for end of sim\nvoid VpiImpl::sim_end() {\n    m_sim_finish_cb->remove();\n#ifdef ICARUS\n    // Must skip checking return value on Icarus because their version of\n    // vpi_control() returns void for some reason.\n    vpi_control(vpiFinish, vpiDiagTimeLoc);\n#else\n    int ok = vpi_control(vpiFinish, vpiDiagTimeLoc);\n    // LCOV_EXCL_START\n    if (!ok) {\n        LOG_DEBUG(\"VPI: Failed to end simulation\");\n        check_vpi_error();\n    }\n    // LCOV_EXCL_STOP\n#endif\n}\n\nbool VpiImpl::compare_generate_labels(const std::string &a,\n                                      const std::string &b) {\n    /* Compare two generate labels for equality ignoring any suffixed index. */\n    std::size_t a_idx = a.rfind(\"[\");\n    std::size_t b_idx = b.rfind(\"[\");\n    return a.substr(0, a_idx) == b.substr(0, b_idx);\n}\n\nconst char *VpiImpl::get_type_delimiter(GpiObjHdl *obj_hdl) {\n    return (obj_hdl->get_type() == GPI_PACKAGE) ? \"\" : \".\";\n}\n\nstatic int startup_callback(void *) {\n    LOG_TRACE(\"GPI => [ GPI (VPI startup) ]\");\n    gpi_start_of_sim_time();\n    LOG_TRACE(\"[ GPI (VPI startup) ] => GPI\");\n    return 0;\n}\n\nstatic int shutdown_callback(void *) {\n    LOG_TRACE(\"GPI => [ GPI (VPI end of sim time) ]\");\n    gpi_end_of_sim_time();\n    LOG_TRACE(\"[ GPI (VPI end of sim time) ] => GPI\");\n    return 0;\n}\n\nvoid VpiImpl::main() noexcept {\n    auto startup_cb = new VpiStartupCbHdl(this);\n    auto err = startup_cb->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        LOG_CRITICAL(\n            \"VPI: Unable to register startup callback! Simulation will end.\");\n        check_vpi_error();\n        delete startup_cb;\n        exit(1);\n    }\n    // LCOV_EXCL_STOP\n    startup_cb->set_cb_info(startup_callback, nullptr);\n\n    auto shutdown_cb = new VpiShutdownCbHdl(this);\n    err = shutdown_cb->arm();\n    // LCOV_EXCL_START\n    if (err) {\n        LOG_CRITICAL(\n            \"VPI: Unable to register shutdown callback! Simulation will end.\");\n        check_vpi_error();\n        startup_cb->remove();\n        delete shutdown_cb;\n        exit(1);\n    }\n    // LCOV_EXCL_STOP\n    shutdown_cb->set_cb_info(shutdown_callback, nullptr);\n    m_sim_finish_cb = shutdown_cb;\n\n    gpi_register_impl(this);\n    gpi_entry_point();\n}\n\nstatic bool from_bootstrap = false;\n\n// This is run by the simulator at startup when this is the main GPI entrypoint\nstatic void vpi_main() {\n    LOG_TRACE(\"%s => [ VPI (vpi_main) ]\",\n              from_bootstrap ? \"Bootstrap\" : \"Sim (vlog_startup_routines)\");\n#ifdef VCS\n    // VCS loads the entry point both during compilation and again at\n    // simulation. Only during simulation are most of the VPI routines\n    // working. So we check if we are in compilation and exit early since we\n    // don't need to do anything for compilation currently.\n    s_vpi_vlog_info info;\n    if (!vpi_get_vlog_info(&info)) {\n        return;\n    }\n#endif\n    auto vpi_table = new VpiImpl(\"VPI\");\n    vpi_table->main();\n    LOG_TRACE(\"[ VPI (vpi_main) ] => %s\",\n              from_bootstrap ? \"Bootstrap\" : \"Sim (vlog_startup_routines)\");\n}\n\n// This is run by GPI when requested for mixed-language simulations\nstatic void register_impl() {\n    LOG_TRACE(\"GPI Init => [ VPI (register_impl) ]\");\n    auto vpi_table = new VpiImpl(\"VPI\");\n    gpi_register_impl(vpi_table);\n    LOG_TRACE(\"[ VPI (register_impl) ] => GPI Init\");\n}\n\nextern \"C\" {\nCOCOTBVPI_EXPORT void (*vlog_startup_routines[])() = {\n    gpi_init_logging_and_debug, vpi_main, nullptr};\n\n// For non-VPI compliant applications that cannot find vlog_startup_routines\n// symbol\nCOCOTBVPI_EXPORT void vlog_startup_routines_bootstrap() {\n    gpi_init_logging_and_debug();\n    LOG_TRACE(\"Sim => [ VPI (vlog_startup_routines_bootstrap) ]\");\n    from_bootstrap = true;\n    vpi_main();\n    LOG_TRACE(\"[ VPI (vlog_startup_routines_bootstrap) ] => Sim\");\n}\n}\n\nGPI_ENTRY_POINT(cocotbvpi, register_impl)\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vpi/VpiImpl.hpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#ifndef COCOTB_VPI_IMPL_H_\n#define COCOTB_VPI_IMPL_H_\n\n#include <exports.h>\n#include <gpi.h>\n\n#include <cstring>\n#include <map>\n#include <vector>\n\n#include \"../gpi_priv.hpp\"\n#include \"../logging.hpp\"\n#include \"_vendor/vpi/sv_vpi_user.h\"\n\n#ifdef COCOTBVPI_EXPORTS\n#define COCOTBVPI_EXPORT COCOTB_EXPORT\n#else\n#define COCOTBVPI_EXPORT COCOTB_IMPORT\n#endif\n\n// TODO Move the check_vpi_error stuff into another file\n\n// Should be run after every VPI call to check error status\nstatic inline void __check_vpi_error(const char *file, const char *func,\n                                     long line) {\n    if (!gpi_debug_enabled) {\n        return;\n    }\n\n    s_vpi_error_info info;\n    enum gpi_log_level loglevel;\n\n    memset(&info, 0, sizeof(info));\n    auto error_occured = vpi_chk_error(&info);\n    if (!error_occured) {\n        return;\n    }\n\n    switch (info.level) {\n        case vpiNotice:\n            loglevel = GPI_INFO;\n            break;\n        case vpiWarning:\n            loglevel = GPI_WARNING;\n            break;\n        case vpiError:\n            loglevel = GPI_ERROR;\n            break;\n        case vpiSystem:\n        case vpiInternal:\n            loglevel = GPI_CRITICAL;\n            break;\n        default:\n            loglevel = GPI_WARNING;\n    }\n\n    LOG_EXPLICIT(\"gpi\", GPI_DEBUG, file, func, line,\n                 \"VPI Internal Error: %s @ %s:%d: %s\",\n                 gpi_log_level_to_str(loglevel), info.file, info.line,\n                 info.message);\n}\n\n#define check_vpi_error()                                \\\n    do {                                                 \\\n        __check_vpi_error(__FILE__, __func__, __LINE__); \\\n    } while (0)\n\nclass VpiCbHdl : public GpiCbHdl {\n  public:\n    VpiCbHdl(GpiImplInterface *impl);\n\n    int arm() override;\n    int remove() override;\n    int run() override;\n\n  protected:\n    s_cb_data cb_data;\n    s_vpi_time vpi_time;\n    bool m_removed = false;\n};\n\nclass VpiSignalObjHdl;\n\nclass VpiValueCbHdl : public VpiCbHdl {\n  public:\n    VpiValueCbHdl(GpiImplInterface *impl, VpiSignalObjHdl *sig, gpi_edge edge);\n    int run() override;\n\n  private:\n    s_vpi_value m_vpi_value;\n    GpiSignalObjHdl *m_signal;\n    gpi_edge m_edge;\n};\n\nclass VpiTimedCbHdl : public VpiCbHdl {\n  public:\n    VpiTimedCbHdl(GpiImplInterface *impl, uint64_t time);\n};\n\nclass VpiReadOnlyCbHdl : public VpiCbHdl {\n  public:\n    VpiReadOnlyCbHdl(GpiImplInterface *impl);\n};\n\nclass VpiNextPhaseCbHdl : public VpiCbHdl {\n  public:\n    VpiNextPhaseCbHdl(GpiImplInterface *impl);\n};\n\nclass VpiReadWriteCbHdl : public VpiCbHdl {\n  public:\n    VpiReadWriteCbHdl(GpiImplInterface *impl);\n};\n\nclass VpiStartupCbHdl : public VpiCbHdl {\n  public:\n    VpiStartupCbHdl(GpiImplInterface *impl);\n\n    // Too many sims get upset trying to remove startup callbacks so we just\n    // don't try. TODO Is this still accurate?\n\n    int run() override {\n        int res = 0;\n        if (!m_removed) {\n            res = m_cb_func(m_cb_data);\n        } else {\n            LOG_TRACE(\"[ VPI (startup) ] callback is removed\");\n        }\n        delete this;\n        return res;\n    }\n\n    int remove() override {\n        m_removed = true;\n        return 0;\n    }\n};\n\nclass VpiShutdownCbHdl : public VpiCbHdl {\n  public:\n    VpiShutdownCbHdl(GpiImplInterface *impl);\n\n    // Too many sims get upset trying to remove startup callbacks so we just\n    // don't try. TODO Is this still accurate?\n\n    int run() override {\n        int res = 0;\n        if (!m_removed) {\n            res = m_cb_func(m_cb_data);\n        } else {\n            LOG_TRACE(\"[ VPI (shutdown) ] callback is removed\");\n        }\n        delete this;\n        return res;\n    }\n\n    int remove() override {\n        m_removed = true;\n        return 0;\n    }\n};\n\nclass VpiArrayObjHdl : public GpiObjHdl {\n  public:\n    VpiArrayObjHdl(GpiImplInterface *impl, vpiHandle hdl, gpi_objtype objtype)\n        : GpiObjHdl(impl, hdl, objtype) {}\n\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n};\n\nclass VpiObjHdl : public GpiObjHdl {\n  public:\n    VpiObjHdl(GpiImplInterface *impl, vpiHandle hdl, gpi_objtype objtype)\n        : GpiObjHdl(impl, hdl, objtype) {}\n\n    const char *get_definition_name() override;\n    const char *get_definition_file() override;\n};\n\nclass VpiSignalObjHdl : public GpiSignalObjHdl {\n  public:\n    VpiSignalObjHdl(GpiImplInterface *impl, vpiHandle hdl, gpi_objtype objtype,\n                    bool is_const)\n        : GpiSignalObjHdl(impl, hdl, objtype, is_const) {}\n\n    const char *get_signal_value_binstr() override;\n    const char *get_signal_value_str() override;\n    double get_signal_value_real() override;\n    long get_signal_value_long() override;\n\n    int set_signal_value(const int32_t value, gpi_set_action action) override;\n    int set_signal_value(const double value, gpi_set_action action) override;\n    int set_signal_value_binstr(std::string &value,\n                                gpi_set_action action) override;\n    int set_signal_value_str(std::string &value,\n                             gpi_set_action action) override;\n\n    /* Value change callback accessor */\n    int initialise(const std::string &name,\n                   const std::string &fq_name) override;\n    GpiCbHdl *register_value_change_callback(gpi_edge edge,\n                                             int (*function)(void *),\n                                             void *cb_data) override;\n    int get_signed() override;\n\n  private:\n    int set_signal_value(s_vpi_value value, gpi_set_action action);\n};\n\nclass VpiIterator : public GpiIterator {\n  public:\n    VpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl);\n\n    ~VpiIterator() override;\n\n    Status next_handle(std::string &name, GpiObjHdl **hdl,\n                       void **raw_hdl) override;\n\n  private:\n    vpiHandle m_iterator;\n    static std::map<int32_t, std::vector<int32_t>>\n        iterate_over;               /* Possible mappings */\n    std::vector<int32_t> *selected; /* Mapping currently in use */\n    std::vector<int32_t>::iterator one2many;\n};\n\n// Base class for simple iterator that only iterates over a single type\nclass VpiSingleIterator : public GpiIterator {\n  public:\n    VpiSingleIterator(GpiImplInterface *impl, GpiObjHdl *hdl, int32_t vpitype)\n        : GpiIterator(impl, hdl)\n\n    {\n        vpiHandle vpi_hdl = m_parent->get_handle<vpiHandle>();\n        m_iterator = vpi_iterate(vpitype, vpi_hdl);\n        if (NULL == m_iterator) {\n            LOG_DEBUG(\"vpi_iterate returned NULL for type %d for object %s(%d)\",\n                      vpitype, vpi_get_str(vpiType, vpi_hdl),\n                      vpi_get(vpiType, vpi_hdl));\n            return;\n        }\n    }\n\n    Status next_handle(std::string &name, GpiObjHdl **hdl,\n                       void **raw_hdl) override;\n\n  protected:\n    vpiHandle m_iterator = nullptr;\n};\n\nclass VpiPackageIterator : public GpiIterator {\n  public:\n    VpiPackageIterator(GpiImplInterface *impl)\n        : GpiIterator(impl, nullptr)\n\n    {\n        // Questa doesn't support iteration over vpiPackage but everything\n        // supports vpiInstance which is a superset\n        m_iterator = vpi_iterate(vpiInstance, nullptr);\n        if (NULL == m_iterator) {\n            LOG_WARN(\n                \"vpi_iterate returned NULL for type vpiInstance for object \"\n                \"NULL\");\n            return;\n        }\n    }\n\n    Status next_handle(std::string &name, GpiObjHdl **hdl,\n                       void **raw_hdl) override;\n\n  private:\n    vpiHandle m_iterator = nullptr;\n};\n\nclass VpiImpl : public GpiImplInterface {\n  public:\n    VpiImpl(const std::string &name) : GpiImplInterface(name) {}\n\n    /* Sim related */\n    void sim_end(void) override;\n    void get_sim_time(uint32_t *high, uint32_t *low) override;\n    void get_sim_precision(int32_t *precision) override;\n    const char *get_simulator_product() override;\n    const char *get_simulator_version() override;\n    int get_simulator_args(int *argc, char const *const **argv) override;\n\n    /* Hierarchy related */\n    GpiObjHdl *get_root_handle(const char *name) override;\n    GpiIterator *iterate_handle(GpiObjHdl *obj_hdl,\n                                gpi_iterator_sel type) override;\n    GpiObjHdl *next_handle(GpiIterator *iter);\n\n    /* Callback related, these may (will) return the same handle*/\n    GpiCbHdl *register_timed_callback(uint64_t time, int (*function)(void *),\n                                      void *cb_data) override;\n    GpiCbHdl *register_readonly_callback(int (*function)(void *),\n                                         void *cb_data) override;\n    GpiCbHdl *register_nexttime_callback(int (*function)(void *),\n                                         void *cb_data) override;\n    GpiCbHdl *register_readwrite_callback(int (*function)(void *),\n                                          void *cb_data) override;\n    GpiObjHdl *get_child_by_name(const std::string &name,\n                                 GpiObjHdl *parent) override;\n    GpiObjHdl *get_child_by_index(int32_t index, GpiObjHdl *parent) override;\n    GpiObjHdl *get_child_from_handle(void *raw_hdl, GpiObjHdl *parent) override;\n    static const char *reason_to_string(int reason);\n    GpiObjHdl *create_gpi_obj_from_handle(vpiHandle new_hdl,\n                                          const std::string &name,\n                                          const std::string &fq_name);\n\n    static bool compare_generate_labels(const std::string &a,\n                                        const std::string &b);\n\n    const char *get_type_delimiter(GpiObjHdl *obj_hdl);\n\n    void main() noexcept;\n\n  private:\n    // We store the shutdown callback handle here so sim_end() can remove() it\n    // if it's called.\n    VpiShutdownCbHdl *m_sim_finish_cb;\n    std::string m_product;\n    std::string m_version;\n    int m_argc = 0;\n    char const *const *m_argv = nullptr;\n};\n\n#endif /*COCOTB_VPI_IMPL_H_  */\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vpi/VpiIterator.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <vpi_user_ext.h>\n\n#include <stdexcept>\n\n#include \"../logging.hpp\"\n#include \"./VpiImpl.hpp\"\n\ndecltype(VpiIterator::iterate_over) VpiIterator::iterate_over = [] {\n    /* for reused lists */\n    // clang-format off\n    // vpiInstance is the base class for module, program, interface, etc.\n    std::vector<int32_t> instance_options = {\n        vpiNet,\n        vpiNetArray,\n        vpiReg,\n        vpiRegArray,\n    };\n    std::vector<int32_t> module_options = {\n        // vpiModule,            // Aldec SEGV on mixed language\n        // vpiModuleArray,       // Aldec SEGV on mixed language\n        vpiMemory,\n        vpiIntegerVar,\n        vpiRealVar,\n        vpiRealNet,\n        vpiStructVar,\n        vpiStructNet,\n        vpiVariables,\n        vpiNamedEvent,\n        vpiNamedEventArray,\n        vpiParameter,\n        vpiPrimitive,\n        vpiPrimitiveArray,\n        vpiInternalScope,\n        // vpiInterface,         // Aldec SEGV on mixed language\n        // vpiInterfaceArray,    // Aldec SEGV on mixed language\n    };\n    // clang-format on\n\n    // append base class vpiInstance members\n    module_options.insert(module_options.begin(), instance_options.begin(),\n                          instance_options.end());\n\n    std::vector<int32_t> struct_options = {\n        vpiNet,\n#ifndef IUS\n        vpiNetArray,\n#endif\n        vpiReg,       vpiRegArray,       vpiMemory, vpiParameter,\n        vpiPrimitive, vpiPrimitiveArray, vpiMember,\n    };\n\n    return decltype(VpiIterator::iterate_over){\n        {vpiModule, module_options},\n        {vpiInterface, instance_options},\n        {vpiGenScope, module_options},\n\n        {vpiStructVar, struct_options},\n        {vpiStructNet, struct_options},\n\n        {vpiNet,\n         {\n             vpiNetBit,\n         }},\n        {vpiNetArray,\n         {\n             vpiNet,\n         }},\n        {vpiRegArray,\n         {\n             vpiReg,\n         }},\n        {vpiMemory,\n         {\n             vpiMemoryWord,\n         }},\n        {vpiPackage,\n         {\n             vpiParameter,\n         }},\n    };\n}();\n\nVpiIterator::VpiIterator(GpiImplInterface *impl, GpiObjHdl *hdl)\n    : GpiIterator(impl, hdl), m_iterator(NULL) {\n    vpiHandle iterator;\n    vpiHandle vpi_hdl = m_parent->get_handle<vpiHandle>();\n\n    int type = vpi_get(vpiType, vpi_hdl);\n\n    try {\n        selected = &iterate_over.at(type);\n    } catch (std::out_of_range const &) {\n        LOG_WARN(\"VPI: Implementation does not know how to iterate over %s(%d)\",\n                 vpi_get_str(vpiType, vpi_hdl), type);\n        selected = nullptr;\n        return;\n    }\n\n    for (one2many = selected->begin(); one2many != selected->end();\n         one2many++) {\n        /* GPI_GENARRAY are pseudo-regions and all that should be searched for\n         * are the sub-regions */\n        if (m_parent->get_type() == GPI_GENARRAY &&\n            *one2many != vpiInternalScope) {\n            LOG_DEBUG(\n                \"vpi_iterator vpiOneToManyT=%d skipped for GPI_GENARRAY type\",\n                *one2many);\n            continue;\n        }\n\n        iterator = vpi_iterate(*one2many, vpi_hdl);\n\n        if (iterator) {\n            break;\n        }\n\n        LOG_DEBUG(\"vpi_iterate type=%d returned NULL\", *one2many);\n    }\n\n    if (NULL == iterator) {\n        LOG_DEBUG(\n            \"vpi_iterate return NULL for all relationships on %s (%d) type:%s\",\n            vpi_get_str(vpiName, vpi_hdl), type, vpi_get_str(vpiType, vpi_hdl));\n        selected = NULL;\n        return;\n    }\n\n    LOG_DEBUG(\"Created iterator working from '%s' with type %s(%d)\",\n              vpi_get_str(vpiFullName, vpi_hdl), vpi_get_str(vpiType, vpi_hdl),\n              type);\n\n    m_iterator = iterator;\n}\n\nVpiIterator::~VpiIterator() {\n    if (m_iterator) vpi_free_object(m_iterator);\n}\n\n#define VPI_TYPE_MAX (1000)\n\nGpiIterator::Status VpiSingleIterator::next_handle(std::string &name,\n                                                   GpiObjHdl **hdl,\n                                                   void **raw_hdl) {\n    GpiObjHdl *new_obj;\n    vpiHandle obj;\n\n    if (NULL == m_iterator) return GpiIterator::END;\n\n    obj = vpi_scan(m_iterator);\n    if (NULL == obj) return GpiIterator::END;\n\n    const char *c_name = vpi_get_str(vpiName, obj);\n    if (!c_name) {\n        int type = vpi_get(vpiType, obj);\n\n        if (type >= VPI_TYPE_MAX) {\n            *raw_hdl = (void *)obj;\n            return GpiIterator::NOT_NATIVE_NO_NAME;\n        }\n\n        LOG_DEBUG(\"Unable to get the name for this object of type %d\", type);\n\n        return GpiIterator::NATIVE_NO_NAME;\n    }\n\n    std::string fq_name = c_name;\n\n    LOG_DEBUG(\"vpi_scan found '%s = '%s'\", name.c_str(), fq_name.c_str());\n\n    VpiImpl *vpi_impl = reinterpret_cast<VpiImpl *>(m_impl);\n    new_obj = vpi_impl->create_gpi_obj_from_handle(obj, name, fq_name);\n    if (new_obj) {\n        *hdl = new_obj;\n        return GpiIterator::NATIVE;\n    } else\n        return GpiIterator::NOT_NATIVE;\n}\n\nGpiIterator::Status VpiPackageIterator::next_handle(std::string &,\n                                                    GpiObjHdl **hdl, void **) {\n    GpiObjHdl *new_obj;\n    vpiHandle obj;\n\n    if (NULL == m_iterator) return GpiIterator::END;\n\n    // obj might not be a package since we are forced to iterate over all\n    // vpiInstance due to a limitation in Questa so we keep searching until we\n    // find one\n    // Check that an object has a non-NULL name during iteration, and pass over\n    // it if it does. This happens with xcelium.\n    std::string name;\n    while (true) {\n        obj = vpi_scan(m_iterator);\n        check_vpi_error();\n        if (obj == nullptr) return GpiIterator::END;\n\n        PLI_INT32 type = vpi_get(vpiType, obj);\n        check_vpi_error();\n        if (type == vpiPackage) {\n            auto name_cstr = vpi_get_str(vpiName, obj);\n            check_vpi_error();\n            if (name_cstr != nullptr) {\n                name = name_cstr;\n                break;\n            }\n        }\n    }\n\n    VpiImpl *vpi_impl = reinterpret_cast<VpiImpl *>(m_impl);\n    std::string fq_name = vpi_get_str(vpiFullName, obj);\n    LOG_DEBUG(\"VPI: package found '%s' = '%s'\", name.c_str(), fq_name.c_str());\n    // '::' may or may not be included in the package vpiFullName:\n    std::string package_delim = \"::\";\n    if (fq_name.compare(fq_name.length() - package_delim.length(),\n                        package_delim.length(), package_delim)) {\n        fq_name += \"::\";\n    }\n    new_obj = new VpiObjHdl(vpi_impl, obj, GPI_PACKAGE);\n    new_obj->initialise(name, fq_name);\n    *hdl = new_obj;\n    return GpiIterator::NATIVE;\n}\n\nGpiIterator::Status VpiIterator::next_handle(std::string &name, GpiObjHdl **hdl,\n                                             void **raw_hdl) {\n    GpiObjHdl *new_obj;\n    vpiHandle obj;\n    vpiHandle iter_obj = m_parent->get_handle<vpiHandle>();\n\n    if (!selected) return GpiIterator::END;\n\n    gpi_objtype obj_type = m_parent->get_type();\n    std::string parent_name = m_parent->get_name();\n\n    do {\n        obj = NULL;\n\n        if (m_iterator) {\n            obj = vpi_scan(m_iterator);\n\n            /* For GPI_GENARRAY, only allow the generate statements through that\n             * match the name of the generate block.\n             */\n            if (obj != NULL && obj_type == GPI_GENARRAY) {\n                auto rgn_type = vpi_get(vpiType, obj);\n                if (rgn_type == vpiGenScope || rgn_type == vpiModule) {\n                    std::string rgn_name = vpi_get_str(vpiName, obj);\n                    if (!VpiImpl::compare_generate_labels(rgn_name,\n                                                          parent_name)) {\n                        obj = NULL;\n                        continue;\n                    }\n                } else {\n                    obj = NULL;\n                    continue;\n                }\n            }\n\n            if (NULL == obj) {\n                /* m_iterator will already be free'd internally here */\n                m_iterator = NULL;\n            } else {\n                break;\n            }\n\n            LOG_DEBUG(\"End of type=%d iteration\", *one2many);\n        } else {\n            LOG_DEBUG(\"No valid type=%d iterator\", *one2many);\n        }\n\n        if (++one2many >= selected->end()) {\n            obj = NULL;\n            break;\n        }\n\n        /* GPI_GENARRAY are pseudo-regions and all that should be searched for\n         * are the sub-regions */\n        if (obj_type == GPI_GENARRAY && *one2many != vpiInternalScope) {\n            LOG_DEBUG(\n                \"vpi_iterator vpiOneToManyT=%d skipped for GPI_GENARRAY type\",\n                *one2many);\n            continue;\n        }\n\n        m_iterator = vpi_iterate(*one2many, iter_obj);\n\n    } while (!obj);\n\n    if (NULL == obj) {\n        LOG_DEBUG(\"No more children, all relationships tested\");\n        return GpiIterator::END;\n    }\n\n    /* Simulators vary here. Some will allow the name to be accessed\n       across boundary. We can simply return this up and allow\n       the object to be created. Others do not. In this case\n       we see if the object is in our type range and if not\n       return the raw_hdl up */\n\n    const char *c_name = vpi_get_str(vpiName, obj);\n    if (!c_name) {\n        /* This may be another type */\n        int type = vpi_get(vpiType, obj);\n\n        if (type >= VPI_TYPE_MAX) {\n            *raw_hdl = (void *)obj;\n            return GpiIterator::NOT_NATIVE_NO_NAME;\n        }\n\n        LOG_DEBUG(\"Unable to get the name for this object of type %d\", type);\n\n        return GpiIterator::NATIVE_NO_NAME;\n    }\n\n    /*\n     * If the parent is not a generate loop, then watch for generate handles and\n     * create the pseudo-region.\n     *\n     * NOTE: Taking advantage of the \"caching\" to only create one pseudo-region\n     * object. Otherwise a list would be required and checked while iterating\n     */\n    if (*one2many == vpiInternalScope && obj_type != GPI_GENARRAY &&\n        vpi_get(vpiType, obj) == vpiGenScope) {\n        std::string idx_str = c_name;\n        std::size_t found = idx_str.rfind(\"[\");\n\n        if (found != std::string::npos && found != 0) {\n            name = idx_str.substr(0, found);\n            obj = m_parent->get_handle<vpiHandle>();\n        } else {\n            name = c_name;\n        }\n    } else {\n        name = c_name;\n    }\n\n    /* We try and create a handle internally, if this is not possible we\n       return and GPI will try other implementations with the name\n       */\n\n    std::string fq_name = m_parent->get_fullname();\n    VpiImpl *vpi_impl = reinterpret_cast<VpiImpl *>(m_impl);\n\n    if (obj_type == GPI_GENARRAY) {\n        std::size_t found = name.rfind(\"[\");\n\n        if (found != std::string::npos) {\n            fq_name += name.substr(found);\n        } else {\n            LOG_WARN(\"Unhandled Sub-Element Format - %s\", name.c_str());\n            fq_name += \".\" + name;\n        }\n    } else if (obj_type == GPI_STRUCTURE) {\n        std::size_t found = name.rfind(\".\");\n\n        if (found != std::string::npos) {\n            fq_name += name.substr(found);\n            name = name.substr(found + 1);\n        } else {\n            LOG_WARN(\"Unhandled Sub-Element Format - %s\", name.c_str());\n            fq_name += \".\" + name;\n        }\n    } else {\n        fq_name += vpi_impl->get_type_delimiter(m_parent) + name;\n    }\n\n    LOG_DEBUG(\"vpi_scan found '%s'\", fq_name.c_str());\n    new_obj = vpi_impl->create_gpi_obj_from_handle(obj, name, fq_name);\n    if (new_obj) {\n        *hdl = new_obj;\n        return GpiIterator::NATIVE;\n    } else\n        return GpiIterator::NOT_NATIVE;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vpi/VpiObj.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <algorithm>\n\n#include \"../logging.hpp\"\n#include \"./VpiImpl.hpp\"\n\nint VpiArrayObjHdl::initialise(const std::string &name,\n                               const std::string &fq_name) {\n    vpiHandle hdl = GpiObjHdl::get_handle<vpiHandle>();\n\n    m_indexable = true;\n\n    int range_idx = 0;\n\n    /* Need to determine if this is a pseudo-handle to be able to select the\n     * correct range */\n    std::string hdl_name = vpi_get_str(vpiName, hdl);\n\n    /* Removing the hdl_name from the name will leave the pseudo-indices */\n    if (hdl_name.length() < name.length()) {\n        // get the last index of hdl_name in name\n        std::size_t idx_str = name.rfind(hdl_name);\n        if (idx_str == std::string::npos) {\n            LOG_ERROR(\"Unable to find name %s in %s\", hdl_name.c_str(),\n                      name.c_str());\n            return -1;\n        }\n        // count occurrences of [\n        auto start =\n            name.begin() + static_cast<std::string::difference_type>(idx_str);\n        range_idx = static_cast<int>(std::count(start, name.end(), '['));\n    }\n\n    /* After determining the range_idx, get the range and set the limits */\n    vpiHandle iter = vpi_iterate(vpiRange, hdl);\n    vpiHandle rangeHdl;\n\n    if (iter != NULL) {\n        rangeHdl = vpi_scan(iter);\n\n// Questa and VCS vpiRange iter always starts from the first index of the array.\n#if defined(MODELSIM) || defined(VCS)\n        for (int i = 0; i < range_idx; ++i) {\n            rangeHdl = vpi_scan(iter);\n            if (rangeHdl == NULL) {\n                break;\n            }\n        }\n#endif\n        if (rangeHdl == NULL) {\n            LOG_ERROR(\"Unable to get range for indexable array\");\n            return -1;\n        }\n        vpi_free_object(iter);  // Need to free iterator since exited early\n    } else if (range_idx == 0) {\n        rangeHdl = hdl;\n    } else {\n        LOG_ERROR(\"Unable to get range for indexable array or memory\");\n        return -1;\n    }\n\n    s_vpi_value val;\n    val.format = vpiIntVal;\n    vpi_get_value(vpi_handle(vpiLeftRange, rangeHdl), &val);\n    check_vpi_error();\n    m_range_left = val.value.integer;\n\n    vpi_get_value(vpi_handle(vpiRightRange, rangeHdl), &val);\n    check_vpi_error();\n    m_range_right = val.value.integer;\n\n    /* vpiSize will return a size that is incorrect for multi-dimensional arrays\n     * so use the range to calculate the m_num_elems.\n     *\n     *    For example:\n     *       wire [7:0] sig_t4 [0:3][7:4]\n     *\n     *    The size of \"sig_t4\" will be reported as 16 through the vpi interface.\n     */\n    if (m_range_left > m_range_right) {\n        m_num_elems = m_range_left - m_range_right + 1;\n        m_range_dir = GPI_RANGE_DOWN;\n    } else {\n        m_num_elems = m_range_right - m_range_left + 1;\n        m_range_dir = GPI_RANGE_UP;\n    }\n\n    return GpiObjHdl::initialise(name, fq_name);\n}\n\nconst char *VpiObjHdl::get_definition_name() {\n    if (m_definition_name.empty()) {\n        auto hdl = get_handle<vpiHandle>();\n        auto *str = vpi_get_str(vpiDefName, hdl);\n        if (str != NULL) {\n            m_definition_name = str;\n        }\n    }\n    return m_definition_name.c_str();\n}\n\nconst char *VpiObjHdl::get_definition_file() {\n    if (m_definition_file.empty()) {\n        auto hdl = GpiObjHdl::get_handle<vpiHandle>();\n        auto *str = vpi_get_str(vpiDefFile, hdl);\n        if (str != NULL) {\n            m_definition_file = str;\n        }\n    }\n    return m_definition_file.c_str();\n}\n\nint VpiSignalObjHdl::get_signed() {\n    return vpi_get(vpiSigned, get_handle<vpiHandle>());\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/gpi/vpi/VpiSignal.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <gpi.h>\n#include <vpi_user_ext.h>\n\n#include <cassert>\n\n#include \"../logging.hpp\"\n#include \"./VpiImpl.hpp\"\n\nint VpiSignalObjHdl::initialise(const std::string &name,\n                                const std::string &fq_name) {\n    int32_t type = vpi_get(vpiType, GpiObjHdl::get_handle<vpiHandle>());\n    if ((vpiIntVar == type) || (vpiIntegerVar == type) ||\n        (vpiIntegerNet == type)) {\n        m_num_elems = vpi_get(vpiSize, GpiObjHdl::get_handle<vpiHandle>());\n    } else if (vpiRealNet == type) {\n        m_num_elems = 1;\n    } else {\n        m_num_elems = vpi_get(vpiSize, GpiObjHdl::get_handle<vpiHandle>());\n\n        if (GpiObjHdl::get_type() == GPI_STRING || type == vpiConstant ||\n            type == vpiParameter) {\n            m_indexable = false;  // Don't want to iterate over indices\n            m_range_left = 0;\n            m_range_right = m_num_elems - 1;\n        } else if (GpiObjHdl::get_type() == GPI_LOGIC ||\n                   GpiObjHdl::get_type() == GPI_PACKED_OBJECT) {\n            vpiHandle hdl = GpiObjHdl::get_handle<vpiHandle>();\n            m_indexable = vpi_get(vpiVector, hdl);\n\n            if (m_indexable) {\n                s_vpi_value val;\n                vpiHandle iter;\n\n                val.format = vpiIntVal;\n\n                iter = vpi_iterate(vpiRange, hdl);\n\n                /* Only ever need the first \"range\" */\n                if (iter != NULL) {\n                    vpiHandle rangeHdl = vpi_scan(iter);\n\n                    vpi_free_object(iter);\n\n                    if (rangeHdl != NULL) {\n                        vpi_get_value(vpi_handle(vpiLeftRange, rangeHdl), &val);\n                        check_vpi_error();\n                        m_range_left = val.value.integer;\n\n                        vpi_get_value(vpi_handle(vpiRightRange, rangeHdl),\n                                      &val);\n                        check_vpi_error();\n                        m_range_right = val.value.integer;\n                    } else {\n                        LOG_ERROR(\n                            \"VPI: Unable to get range for %s of type %s (%d)\",\n                            name.c_str(), vpi_get_str(vpiType, hdl), type);\n                        return -1;\n                    }\n                } else {\n                    vpiHandle leftRange = vpi_handle(vpiLeftRange, hdl);\n                    check_vpi_error();\n                    vpiHandle rightRange = vpi_handle(vpiRightRange, hdl);\n                    check_vpi_error();\n\n                    if (leftRange != NULL and rightRange != NULL) {\n                        vpi_get_value(leftRange, &val);\n                        m_range_left = val.value.integer;\n\n                        vpi_get_value(rightRange, &val);\n                        m_range_right = val.value.integer;\n                    } else {\n                        LOG_WARN(\n                            \"VPI: Cannot discover range bounds, guessing based \"\n                            \"on elements\");\n                        m_range_left = 0;\n                        m_range_right = m_num_elems - 1;\n                    }\n                }\n\n                LOG_DEBUG(\n                    \"VPI: Indexable object initialized with range [%d:%d] and \"\n                    \"length >%d<\",\n                    m_range_left, m_range_right, m_num_elems);\n            } else {\n                m_range_left = 0;\n                m_range_right = m_num_elems - 1;\n            }\n        }\n    }\n    m_range_dir = m_range_left > m_range_right ? GPI_RANGE_DOWN : GPI_RANGE_UP;\n    LOG_DEBUG(\"VPI: %s initialized with %d elements\", name.c_str(),\n              m_num_elems);\n    return GpiObjHdl::initialise(name, fq_name);\n}\n\nconst char *VpiSignalObjHdl::get_signal_value_binstr() {\n    s_vpi_value value_s = {vpiBinStrVal, {NULL}};\n\n    vpi_get_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s);\n    check_vpi_error();\n\n    return value_s.value.str;\n}\n\nconst char *VpiSignalObjHdl::get_signal_value_str() {\n    s_vpi_value value_s = {vpiStringVal, {NULL}};\n\n    vpi_get_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s);\n    check_vpi_error();\n\n    return value_s.value.str;\n}\n\ndouble VpiSignalObjHdl::get_signal_value_real() {\n    s_vpi_value value_s = {vpiRealVal, {NULL}};\n\n    vpi_get_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s);\n    check_vpi_error();\n\n    return value_s.value.real;\n}\n\nlong VpiSignalObjHdl::get_signal_value_long() {\n    s_vpi_value value_s = {vpiIntVal, {NULL}};\n\n    vpi_get_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s);\n    check_vpi_error();\n\n    return value_s.value.integer;\n}\n\n// Value related functions\nint VpiSignalObjHdl::set_signal_value(int32_t value, gpi_set_action action) {\n    s_vpi_value value_s;\n\n    value_s.value.integer = static_cast<PLI_INT32>(value);\n    value_s.format = vpiIntVal;\n\n    return set_signal_value(value_s, action);\n}\n\nint VpiSignalObjHdl::set_signal_value(double value, gpi_set_action action) {\n    s_vpi_value value_s;\n\n    value_s.value.real = value;\n    value_s.format = vpiRealVal;\n\n    return set_signal_value(value_s, action);\n}\n\nint VpiSignalObjHdl::set_signal_value_binstr(std::string &value,\n                                             gpi_set_action action) {\n    s_vpi_value value_s;\n\n    std::vector<char> writable(value.begin(), value.end());\n    writable.push_back('\\0');\n\n    value_s.value.str = &writable[0];\n    value_s.format = vpiBinStrVal;\n\n    return set_signal_value(value_s, action);\n}\n\nint VpiSignalObjHdl::set_signal_value_str(std::string &value,\n                                          gpi_set_action action) {\n    s_vpi_value value_s;\n\n    std::vector<char> writable(value.begin(), value.end());\n    writable.push_back('\\0');\n\n    value_s.value.str = &writable[0];\n    value_s.format = vpiStringVal;\n\n    return set_signal_value(value_s, action);\n}\n\nint VpiSignalObjHdl::set_signal_value(s_vpi_value value_s,\n                                      gpi_set_action action) {\n    PLI_INT32 vpi_put_flag = -1;\n    s_vpi_time vpi_time_s;\n\n    vpi_time_s.type = vpiSimTime;\n    vpi_time_s.high = 0;\n    vpi_time_s.low = 0;\n\n    switch (action) {\n        case GPI_DEPOSIT:\n#if defined(MODELSIM) || defined(IUS)\n            // Xcelium and Questa do not like setting string variables using\n            // vpiInertialDelay.\n            if (vpiStringVar ==\n                vpi_get(vpiType, GpiObjHdl::get_handle<vpiHandle>())) {\n                vpi_put_flag = vpiNoDelay;\n            } else {\n                vpi_put_flag = vpiInertialDelay;\n            }\n#else\n            vpi_put_flag = vpiInertialDelay;\n#endif\n            break;\n        case GPI_FORCE:\n            vpi_put_flag = vpiForceFlag;\n            break;\n        case GPI_RELEASE:\n            // Best to pass its current value to the sim when releasing\n            vpi_get_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s);\n            vpi_put_flag = vpiReleaseFlag;\n            break;\n        case GPI_NO_DELAY:\n            vpi_put_flag = vpiNoDelay;\n            break;\n        default:\n            assert(0);\n    }\n\n    if (vpi_put_flag == vpiNoDelay) {\n        vpi_put_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s, NULL,\n                      vpiNoDelay);\n    } else {\n        vpi_put_value(GpiObjHdl::get_handle<vpiHandle>(), &value_s, &vpi_time_s,\n                      vpi_put_flag);\n    }\n\n    check_vpi_error();\n\n    return 0;\n}\n\nGpiCbHdl *VpiSignalObjHdl::register_value_change_callback(\n    gpi_edge edge, int (*cb_func)(void *), void *cb_data) {\n    VpiValueCbHdl *cb_hdl = new VpiValueCbHdl(this->m_impl, this, edge);\n    if (cb_hdl->arm()) {\n        delete cb_hdl;\n        return NULL;\n    }\n    cb_hdl->set_cb_info(cb_func, cb_data);\n    return cb_hdl;\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/pygpi/bind.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n/**\n * @file   simulatormodule.cpp\n * @brief Python extension to provide access to the simulator\n *\n * Uses GPI calls to interface to the simulator.\n */\n\n#include <Python.h>\n#include <gpi.h>\n\n#include <cerrno>\n#include <cstdint>\n\n#include \"../utils.hpp\"      // DEFER\n#include \"./pygpi_priv.hpp\"  // pygpi_logger_set_level, c_to_python, python_to_c\n\n// This file defines the routines available to Python\n\n#define MODULE_NAME \"simulator\"\n\n// callback user data\nstruct PythonCallback {\n    PythonCallback(PyObject *func, PyObject *_args, PyObject *_kwargs)\n        : function(func), args(_args), kwargs(_kwargs) {\n        Py_XINCREF(function);\n        Py_XINCREF(args);\n        Py_XINCREF(kwargs);\n    }\n    ~PythonCallback() {\n        Py_XDECREF(function);\n        Py_XDECREF(args);\n        Py_XDECREF(kwargs);\n    }\n    intptr_t padding_;   // TODO exists to works around bug with FLI\n    PyObject *function;  // Function to call when the callback fires\n    PyObject *args;      // The arguments to call the function with\n    PyObject *kwargs;    // Keyword arguments to call the function with\n};\n\nclass GpiClock;\nusing gpi_clk_hdl = GpiClock *;\n\n/* define the extension types as templates */\nnamespace {\ntemplate <typename gpi_hdl_type>\nstruct gpi_hdl_Object {\n    PyObject_HEAD gpi_hdl_type hdl;\n\n    // The python type object, in a place that is easy to retrieve in templates\n    static PyTypeObject py_type;\n};\n\n/** __repr__ shows the memory address of the internal handle */\ntemplate <typename gpi_hdl_type>\nstatic PyObject *gpi_hdl_repr(gpi_hdl_Object<gpi_hdl_type> *self) {\n    auto *type = Py_TYPE(self);\n    return PyUnicode_FromFormat(\"<%s at %p>\", type->tp_name, self->hdl);\n}\n\n/** __hash__ returns the pointer itself */\ntemplate <typename gpi_hdl_type>\nstatic Py_hash_t gpi_hdl_hash(gpi_hdl_Object<gpi_hdl_type> *self) {\n    auto ret = reinterpret_cast<Py_hash_t>(self->hdl);\n    // hash must never return -1\n    if (ret == (Py_hash_t)-1) {\n        ret = (Py_hash_t)-2;\n    }\n    return ret;\n}\n\n/**\n * Create a new python handle object from a pointer, returning None if the\n * pointer is NULL.\n */\ntemplate <typename gpi_hdl_type>\nstatic PyObject *gpi_hdl_New(gpi_hdl_type hdl) {\n    if (hdl == NULL) {\n        Py_RETURN_NONE;\n    }\n    auto *obj = PyObject_New(gpi_hdl_Object<gpi_hdl_type>,\n                             &gpi_hdl_Object<gpi_hdl_type>::py_type);\n    if (obj == NULL) {\n        return NULL;\n    }\n    obj->hdl = hdl;\n    return (PyObject *)obj;\n}\n\n/** Comparison checks if the types match, and then compares pointers */\ntemplate <typename gpi_hdl_type>\nstatic PyObject *gpi_hdl_richcompare(PyObject *self, PyObject *other, int op) {\n    if (Py_TYPE(self) != &gpi_hdl_Object<gpi_hdl_type>::py_type ||\n        Py_TYPE(other) != &gpi_hdl_Object<gpi_hdl_type>::py_type) {\n        Py_RETURN_NOTIMPLEMENTED;\n    }\n\n    auto self_hdl_obj = reinterpret_cast<gpi_hdl_Object<gpi_hdl_type> *>(self);\n    auto other_hdl_obj =\n        reinterpret_cast<gpi_hdl_Object<gpi_hdl_type> *>(other);\n\n    switch (op) {\n        case Py_EQ:\n            return PyBool_FromLong(self_hdl_obj->hdl == other_hdl_obj->hdl);\n        case Py_NE:\n            return PyBool_FromLong(self_hdl_obj->hdl != other_hdl_obj->hdl);\n        default:\n            Py_RETURN_NOTIMPLEMENTED;\n    }\n}\n\n// Initialize the Python type slots\ntemplate <typename gpi_hdl_type>\nPyTypeObject fill_common_slots() {\n    PyTypeObject type = {};\n    type.ob_base = {PyObject_HEAD_INIT(NULL) 0};\n    type.tp_basicsize = sizeof(gpi_hdl_Object<gpi_hdl_type>);\n    type.tp_repr = (reprfunc)gpi_hdl_repr<gpi_hdl_type>;\n    type.tp_hash = (hashfunc)gpi_hdl_hash<gpi_hdl_type>;\n    type.tp_flags = Py_TPFLAGS_DEFAULT;\n    type.tp_richcompare = gpi_hdl_richcompare<gpi_hdl_type>;\n    return type;\n}\n\n// these will be initialized later, once the members are all defined\ntemplate <>\nPyTypeObject gpi_hdl_Object<gpi_sim_hdl>::py_type;\ntemplate <>\nPyTypeObject gpi_hdl_Object<gpi_iterator_hdl>::py_type;\ntemplate <>\nPyTypeObject gpi_hdl_Object<gpi_cb_hdl>::py_type;\ntemplate <>\nPyTypeObject gpi_hdl_Object<gpi_clk_hdl>::py_type;\n}  // namespace\n\ntypedef int (*gpi_function_t)(void *);\n\nstruct sim_time {\n    uint32_t high;\n    uint32_t low;\n};\n\n/**\n * @name    Callback Handling\n * @brief   Handle a callback coming from GPI\n * @ingroup python_c_api\n *\n * Returns 0 on success or 1 on a failure.\n *\n * Handles a callback from the simulator, all of which call this function.\n *\n * We extract the associated context and find the Python function (usually\n * cocotb.scheduler.react) calling it with a reference to the trigger that\n * fired. The scheduler can then call next() on all the coroutines that\n * are waiting on that particular trigger.\n *\n */\nint handle_gpi_callback(void *user_data) {\n    PYGPI_LOG_TRACE(\"GPI => [ PYGPI (cocotb.simulator) ]\");\n    DEFER(PYGPI_LOG_TRACE(\"[ PYGPI (cocotb.simulator) ] => GPI\"));\n    c_to_python();\n    DEFER(python_to_c());\n\n    PyGILState_STATE gstate = PyGILState_Ensure();\n    DEFER(PyGILState_Release(gstate));\n\n    PythonCallback *cb_data = (PythonCallback *)user_data;\n    DEFER(delete cb_data);\n\n    // Call the callback\n    PyObject *pValue =\n        PyObject_Call(cb_data->function, cb_data->args, cb_data->kwargs);\n\n    // If the return value is NULL a Python exception has occurred\n    // The best thing to do here is shutdown as any subsequent\n    // calls will go back to Python which is now in an unknown state\n    if (pValue == NULL) {\n        // Printing a SystemExit calls exit(1), which we don't want.\n        if (!PyErr_ExceptionMatches(PyExc_SystemExit)) {\n            PyErr_Print();\n        }\n        // Clear error so re-entering Python doesn't fail.\n        PyErr_Clear();\n        return -1;\n    }\n\n    // We don't care about the result\n    Py_DECREF(pValue);\n\n    return 0;\n}\n\n// Register a callback for read-only state of sim\n// First argument is the function to call\n// Remaining arguments are keyword arguments to be passed to the callback\nstatic PyObject *register_readonly_callback(PyObject *, PyObject *args) {\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    Py_ssize_t numargs = PyTuple_Size(args);\n\n    if (numargs < 1) {\n        PyErr_SetString(PyExc_TypeError,\n                        \"Attempt to register ReadOnly callback without enough \"\n                        \"arguments!\\n\");\n        return NULL;\n    }\n\n    // Extract the callback function\n    PyObject *function = PyTuple_GetItem(args, 0);  // borrow reference\n    if (!PyCallable_Check(function)) {\n        PyErr_SetString(\n            PyExc_TypeError,\n            \"Attempt to register ReadOnly without supplying a callback!\\n\");\n        return NULL;\n    }\n\n    // Remaining args for function\n    PyObject *fArgs = PyTuple_GetSlice(args, 1, numargs);  // New reference\n    if (fArgs == NULL) {\n        return NULL;\n    }\n    DEFER(Py_DECREF(fArgs));\n\n    PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL);\n\n    gpi_cb_hdl hdl = gpi_register_readonly_callback(\n        (gpi_function_t)handle_gpi_callback, cb_data);\n\n    PyObject *rv = gpi_hdl_New(hdl);\n\n    return rv;\n}\n\nstatic PyObject *register_rwsynch_callback(PyObject *, PyObject *args) {\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    Py_ssize_t numargs = PyTuple_Size(args);\n\n    if (numargs < 1) {\n        PyErr_SetString(PyExc_TypeError,\n                        \"Attempt to register ReadWrite callback without enough \"\n                        \"arguments!\\n\");\n        return NULL;\n    }\n\n    // Extract the callback function\n    PyObject *function = PyTuple_GetItem(args, 0);  // borrow reference\n    if (!PyCallable_Check(function)) {\n        PyErr_SetString(\n            PyExc_TypeError,\n            \"Attempt to register ReadWrite without supplying a callback!\\n\");\n        return NULL;\n    }\n\n    // Remaining args for function\n    PyObject *fArgs = PyTuple_GetSlice(args, 1, numargs);  // New reference\n    if (fArgs == NULL) {\n        return NULL;\n    }\n    DEFER(Py_DECREF(fArgs));\n\n    PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL);\n\n    gpi_cb_hdl hdl = gpi_register_readwrite_callback(\n        (gpi_function_t)handle_gpi_callback, cb_data);\n\n    PyObject *rv = gpi_hdl_New(hdl);\n\n    return rv;\n}\n\nstatic PyObject *register_nextstep_callback(PyObject *, PyObject *args) {\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    Py_ssize_t numargs = PyTuple_Size(args);\n\n    if (numargs < 1) {\n        PyErr_SetString(PyExc_TypeError,\n                        \"Attempt to register NextStep callback without enough \"\n                        \"arguments!\\n\");\n        return NULL;\n    }\n\n    // Extract the callback function\n    PyObject *function = PyTuple_GetItem(args, 0);  // borrow reference\n    if (!PyCallable_Check(function)) {\n        PyErr_SetString(\n            PyExc_TypeError,\n            \"Attempt to register NextStep without supplying a callback!\\n\");\n        return NULL;\n    }\n\n    // Remaining args for function\n    PyObject *fArgs = PyTuple_GetSlice(args, 1, numargs);  // New reference\n    if (fArgs == NULL) {\n        return NULL;\n    }\n    DEFER(Py_DECREF(fArgs));\n\n    PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL);\n\n    gpi_cb_hdl hdl = gpi_register_nexttime_callback(\n        (gpi_function_t)handle_gpi_callback, cb_data);\n\n    PyObject *rv = gpi_hdl_New(hdl);\n\n    return rv;\n}\n\n// Register a timed callback.\n// First argument should be the time in picoseconds\n// Second argument is the function to call\n// Remaining arguments and keyword arguments are to be passed to the callback\nstatic PyObject *register_timed_callback(PyObject *, PyObject *args) {\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    Py_ssize_t numargs = PyTuple_Size(args);\n\n    if (numargs < 2) {\n        PyErr_SetString(\n            PyExc_TypeError,\n            \"Attempt to register timed callback without enough arguments!\\n\");\n        return NULL;\n    }\n\n    uint64_t time;\n    {  // Extract the time\n        PyObject *pTime = PyTuple_GetItem(args, 0);\n        long long pTime_as_longlong = PyLong_AsLongLong(pTime);\n        if (pTime_as_longlong == -1 && PyErr_Occurred()) {\n            return NULL;\n        } else if (pTime_as_longlong < 0) {\n            PyErr_SetString(PyExc_ValueError,\n                            \"Timer value must be a positive integer\");\n            return NULL;\n        } else {\n            time = (uint64_t)pTime_as_longlong;\n        }\n    }\n\n    // Extract the callback function\n    PyObject *function = PyTuple_GetItem(args, 1);  // borrow reference\n    if (!PyCallable_Check(function)) {\n        PyErr_SetString(PyExc_TypeError,\n                        \"Attempt to register timed callback without passing a \"\n                        \"callable callback!\\n\");\n        return NULL;\n    }\n\n    // Remaining args for function\n    PyObject *fArgs = PyTuple_GetSlice(args, 2, numargs);  // New reference\n    if (fArgs == NULL) {\n        return NULL;\n    }\n    DEFER(Py_DECREF(fArgs));\n\n    PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL);\n\n    gpi_cb_hdl hdl = gpi_register_timed_callback(\n        (gpi_function_t)handle_gpi_callback, cb_data, time);\n\n    // Check success\n    PyObject *rv = gpi_hdl_New(hdl);\n\n    return rv;\n}\n\n// Register signal change callback\n// First argument should be the signal handle\n// Second argument is the function to call\n// Remaining arguments and keyword arguments are to be passed to the callback\nstatic PyObject *register_value_change_callback(\n    PyObject *, PyObject *args)  //, PyObject *keywds)\n{\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    Py_ssize_t numargs = PyTuple_Size(args);\n\n    if (numargs < 3) {\n        PyErr_SetString(PyExc_TypeError,\n                        \"Attempt to register value change callback without \"\n                        \"enough arguments!\\n\");\n        return NULL;\n    }\n\n    PyObject *pSigHdl = PyTuple_GetItem(args, 0);\n    if (Py_TYPE(pSigHdl) != &gpi_hdl_Object<gpi_sim_hdl>::py_type) {\n        PyErr_SetString(PyExc_TypeError, \"First argument must be a sim_obj\");\n        return NULL;\n    }\n    gpi_sim_hdl sig_hdl = ((gpi_hdl_Object<gpi_sim_hdl> *)pSigHdl)->hdl;\n\n    // Extract the callback function\n    PyObject *function = PyTuple_GetItem(args, 1);  // borrow reference\n    if (!PyCallable_Check(function)) {\n        PyErr_SetString(PyExc_TypeError,\n                        \"Attempt to register value change callback without \"\n                        \"passing a callable callback!\\n\");\n        return NULL;\n    }\n\n    PyObject *pedge = PyTuple_GetItem(args, 2);  // borrow reference\n    gpi_edge edge = (gpi_edge)PyLong_AsLong(pedge);\n\n    // Remaining args for function\n    PyObject *fArgs = PyTuple_GetSlice(args, 3, numargs);  // New reference\n    if (fArgs == NULL) {\n        return NULL;\n    }\n    DEFER(Py_DECREF(fArgs));\n\n    PythonCallback *cb_data = new PythonCallback(function, fArgs, NULL);\n\n    gpi_cb_hdl hdl = gpi_register_value_change_callback(\n        (gpi_function_t)handle_gpi_callback, cb_data, sig_hdl, edge);\n\n    // Check success\n    PyObject *rv = gpi_hdl_New(hdl);\n\n    return rv;\n}\n\nstatic PyObject *iterate(gpi_hdl_Object<gpi_sim_hdl> *self, PyObject *args) {\n    int type;\n\n    if (!PyArg_ParseTuple(args, \"i:iterate\", &type)) {\n        return NULL;\n    }\n\n    gpi_iterator_hdl result = gpi_iterate(self->hdl, (gpi_iterator_sel)type);\n\n    return gpi_hdl_New(result);\n}\n\nstatic PyObject *package_iterate(PyObject *, PyObject *) {\n    gpi_iterator_hdl result = gpi_iterate(NULL, GPI_PACKAGE_SCOPES);\n\n    return gpi_hdl_New(result);\n}\n\nstatic PyObject *iterator_next(gpi_hdl_Object<gpi_iterator_hdl> *self) {\n    gpi_sim_hdl result = gpi_next(self->hdl);\n\n    // Raise StopIteration when we're done\n    if (!result) {\n        PyErr_SetNone(PyExc_StopIteration);\n        return NULL;\n    }\n\n    return gpi_hdl_New(result);\n}\n\n// Raise an exception on failure\n// Return None if for example get bin_string on enum?\n\nstatic PyObject *get_signal_val_binstr(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                       PyObject *) {\n    const char *result = gpi_get_signal_value_binstr(self->hdl);\n    if (result == NULL) {\n        // LCOV_EXCL_START\n        PyErr_SetString(PyExc_RuntimeError,\n                        \"Simulator yielded a null pointer instead of binstr\");\n        return NULL;\n        // LCOV_EXCL_STOP\n    }\n    return PyUnicode_FromString(result);\n}\n\nstatic PyObject *get_signal_val_str(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                    PyObject *) {\n    const char *result = gpi_get_signal_value_str(self->hdl);\n    if (result == NULL) {\n        // LCOV_EXCL_START\n        PyErr_SetString(PyExc_RuntimeError,\n                        \"Simulator yielded a null pointer instead of string\");\n        return NULL;\n        // LCOV_EXCL_STOP\n    }\n    return PyBytes_FromString(result);\n}\n\nstatic PyObject *get_signal_val_real(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                     PyObject *) {\n    double result = gpi_get_signal_value_real(self->hdl);\n    return PyFloat_FromDouble(result);\n}\n\nstatic PyObject *get_signal_val_long(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                     PyObject *) {\n    long result = gpi_get_signal_value_long(self->hdl);\n    return PyLong_FromLong(result);\n}\n\nstatic PyObject *set_signal_val_binstr(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                       PyObject *args) {\n    const char *binstr;\n    gpi_set_action action;\n\n    if (!PyArg_ParseTuple(args, \"is:set_signal_val_binstr\", &action, &binstr)) {\n        return NULL;\n    }\n\n    gpi_set_signal_value_binstr(self->hdl, binstr, action);\n    Py_RETURN_NONE;\n}\n\nstatic PyObject *set_signal_val_str(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                    PyObject *args) {\n    gpi_set_action action;\n    const char *str;\n\n    if (!PyArg_ParseTuple(args, \"iy:set_signal_val_str\", &action, &str)) {\n        return NULL;\n    }\n\n    gpi_set_signal_value_str(self->hdl, str, action);\n    Py_RETURN_NONE;\n}\n\nstatic PyObject *set_signal_val_real(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                     PyObject *args) {\n    double value;\n    gpi_set_action action;\n\n    if (!PyArg_ParseTuple(args, \"id:set_signal_val_real\", &action, &value)) {\n        return NULL;\n    }\n\n    gpi_set_signal_value_real(self->hdl, value, action);\n    Py_RETURN_NONE;\n}\n\nstatic PyObject *set_signal_val_int(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                    PyObject *args) {\n    long long value;\n    gpi_set_action action;\n\n    if (!PyArg_ParseTuple(args, \"iL:set_signal_val_int\", &action, &value)) {\n        return NULL;\n    }\n\n    gpi_set_signal_value_int(self->hdl, static_cast<int32_t>(value), action);\n    Py_RETURN_NONE;\n}\n\nstatic PyObject *get_definition_name(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                     PyObject *) {\n    const char *result = gpi_get_definition_name(self->hdl);\n    return PyUnicode_FromString(result);\n}\n\nstatic PyObject *get_definition_file(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                     PyObject *) {\n    const char *result = gpi_get_definition_file(self->hdl);\n    return PyUnicode_FromString(result);\n}\n\nstatic PyObject *get_handle_by_name(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                    PyObject *args) {\n    const char *name;\n    // if unset, we assume AUTO, which maintains backward-compatibility\n    int py_discovery_method = 0;\n    gpi_discovery c_discovery_method = GPI_AUTO;\n\n    if (!PyArg_ParseTuple(args, \"s|i:get_handle_by_name\", &name,\n                          &py_discovery_method)) {\n        return NULL;\n    }\n    // do some additional input validation, then map to enum\n    if (py_discovery_method < 0 || py_discovery_method > 1) {\n        PyErr_SetString(PyExc_ValueError,\n                        \"Enum value for discovery_method out of range\");\n        return NULL;\n    } else {\n        c_discovery_method = (gpi_discovery)py_discovery_method;\n    }\n\n    gpi_sim_hdl result =\n        gpi_get_handle_by_name(self->hdl, name, c_discovery_method);\n\n    return gpi_hdl_New(result);\n}\n\nstatic PyObject *get_handle_by_index(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                     PyObject *args) {\n    int32_t index;\n\n    if (!PyArg_ParseTuple(args, \"i:get_handle_by_index\", &index)) {\n        return NULL;\n    }\n\n    gpi_sim_hdl result = gpi_get_handle_by_index(self->hdl, index);\n\n    return gpi_hdl_New(result);\n}\n\nstatic PyObject *get_root_handle(PyObject *, PyObject *args) {\n    const char *name;\n\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    if (!PyArg_ParseTuple(args, \"z:get_root_handle\", &name)) {\n        return NULL;\n    }\n\n    gpi_sim_hdl result = gpi_get_root_handle(name);\n    if (NULL == result) {\n        Py_RETURN_NONE;\n    }\n\n    return gpi_hdl_New(result);\n}\n\nstatic PyObject *get_name_string(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                 PyObject *) {\n    const char *result = gpi_get_signal_name_str(self->hdl);\n    return PyUnicode_FromString(result);\n}\n\nstatic PyObject *get_type(gpi_hdl_Object<gpi_sim_hdl> *self, PyObject *) {\n    gpi_objtype result = gpi_get_object_type(self->hdl);\n    return PyLong_FromLong(result);\n}\n\nstatic PyObject *get_const(gpi_hdl_Object<gpi_sim_hdl> *self, PyObject *) {\n    int result = gpi_is_constant(self->hdl);\n    return PyBool_FromLong(result);\n}\n\nstatic PyObject *get_type_string(gpi_hdl_Object<gpi_sim_hdl> *self,\n                                 PyObject *) {\n    const char *result = gpi_get_signal_type_str(self->hdl);\n    return PyUnicode_FromString(result);\n}\n\nstatic PyObject *get_signed(gpi_hdl_Object<gpi_sim_hdl> *self, PyObject *) {\n    int result = gpi_is_signed(self->hdl);\n    return PyLong_FromLong(result);\n}\n\nstatic PyObject *is_running(PyObject *, PyObject *) {\n    return PyBool_FromLong(gpi_has_registered_impl());\n}\n\n// Returns a high, low, tuple of simulator time\n// Note we can never log from this function since the logging mechanism calls\n// this to annotate log messages with the current simulation time\nstatic PyObject *get_sim_time(PyObject *, PyObject *) {\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    struct sim_time local_time;\n\n    gpi_get_sim_time(&local_time.high, &local_time.low);\n\n    PyObject *pTuple = PyTuple_New(2);\n    PyTuple_SetItem(\n        pTuple, 0,\n        PyLong_FromUnsignedLong(\n            local_time\n                .high));  // Note: This function “steals” a reference to o.\n    PyTuple_SetItem(\n        pTuple, 1,\n        PyLong_FromUnsignedLong(\n            local_time.low));  // Note: This function “steals” a reference to o.\n\n    return pTuple;\n}\n\nstatic PyObject *get_precision(PyObject *, PyObject *) {\n    if (!gpi_has_registered_impl()) {\n        char const *msg =\n            \"Simulator is not available! Defaulting precision to 1 fs.\";\n        if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0) {\n            return NULL;\n        }\n        return PyLong_FromLong(-15);  // preserves old behavior\n    }\n\n    int32_t precision;\n\n    gpi_get_sim_precision(&precision);\n\n    return PyLong_FromLong(precision);\n}\n\nstatic PyObject *get_simulator_product(PyObject *, PyObject *) {\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    return PyUnicode_FromString(gpi_get_simulator_product());\n}\n\nstatic PyObject *get_simulator_version(PyObject *, PyObject *) {\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    return PyUnicode_FromString(gpi_get_simulator_version());\n}\n\nstatic PyObject *get_argv(PyObject *, PyObject *) {\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    int argc;\n    char const *const *_argv;\n    gpi_get_simulator_args(&argc, &_argv);\n\n    // Build argv for cocotb module\n    auto argv_list = PyList_New(argc);\n    // LCOV_EXCL_START\n    if (argv_list == NULL) {\n        PyErr_Print();\n        return NULL;\n    }\n    // LCOV_EXCL_STOP\n    for (int i = 0; i < argc; i++) {\n        // Decode, embedding non-decodable bytes using PEP-383. This can only\n        // fail with MemoryError or similar.\n        auto argv_item = PyUnicode_DecodeLocale(_argv[i], \"surrogateescape\");\n        // LCOV_EXCL_START\n        if (!argv_item) {\n            PyErr_Print();\n            return NULL;\n        }\n        // LCOV_EXCL_STOP\n        PyList_SetItem(argv_list, i, argv_item);\n    }\n    return argv_list;\n}\n\nstatic PyObject *get_num_elems(gpi_hdl_Object<gpi_sim_hdl> *self, PyObject *) {\n    int elems = gpi_get_num_elems(self->hdl);\n    return PyLong_FromLong(elems);\n}\n\nstatic PyObject *get_range(gpi_hdl_Object<gpi_sim_hdl> *self, PyObject *) {\n    int rng_left = gpi_get_range_left(self->hdl);\n    int rng_right = gpi_get_range_right(self->hdl);\n    int rng_dir = gpi_get_range_dir(self->hdl);\n\n    return Py_BuildValue(\"(i,i,i)\", rng_left, rng_right, rng_dir);\n}\n\nstatic PyObject *get_indexable(gpi_hdl_Object<gpi_sim_hdl> *self, PyObject *) {\n    int indexable = gpi_is_indexable(self->hdl);\n\n    return PyBool_FromLong(indexable);\n}\n\nstatic PyObject *stop_simulator(PyObject *, PyObject *) {\n    if (!gpi_has_registered_impl()) {\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n    }\n\n    gpi_finish();\n    Py_RETURN_NONE;\n}\n\nstatic PyObject *deregister(gpi_hdl_Object<gpi_cb_hdl> *self, PyObject *) {\n    // cleanup uncalled callback\n    void *cb_data;\n    gpi_get_cb_info(self->hdl, nullptr, &cb_data);\n    auto cb = static_cast<PythonCallback *>(cb_data);\n    delete cb;\n\n    // deregister from interface\n    gpi_remove_cb(self->hdl);\n\n    Py_RETURN_NONE;\n}\n\nstatic PyObject *set_gpi_log_level(PyObject *, PyObject *args) {\n    int l_level;\n\n    if (!PyArg_ParseTuple(args, \"i:log_level\", &l_level)) {\n        return NULL;\n    }\n\n    pygpi_logging_set_level(static_cast<enum gpi_log_level>(l_level));\n\n    Py_RETURN_NONE;\n}\n\nstatic PyObject *initialize_logger(PyObject *, PyObject *args) {\n    PyObject *log_func;\n    PyObject *get_logger;\n    if (!PyArg_ParseTuple(args, \"OO\", &log_func, &get_logger)) {\n        PyErr_Print();\n        return NULL;\n    }\n    pygpi_logging_configure(log_func, get_logger);\n    Py_RETURN_NONE;\n}\n\nstatic PyObject *set_sim_event_callback(PyObject *, PyObject *args) {\n    if (pEventFn) {\n        PyErr_SetString(PyExc_RuntimeError,\n                        \"Simulator event callback already set!\");\n        return NULL;\n    }\n\n    PyObject *sim_event_callback;\n    if (!PyArg_ParseTuple(args, \"O\", &sim_event_callback)) {\n        PyErr_Print();\n        Py_RETURN_NONE;\n    }\n    Py_INCREF(sim_event_callback);\n    pEventFn = sim_event_callback;\n    Py_RETURN_NONE;\n}\n\nclass GpiClock {\n  public:\n    GpiClock(GpiObjHdl *clk_sig) : clk_signal(clk_sig) {}\n\n    ~GpiClock() { stop(); }\n\n    // Start the clock. Returns nonzero in case of failure:\n    //  - EBUSY if the clock was already started (stop first)\n    //  - EINVAL if the parameters are invalid\n    //  - EAGAIN if registering the toggle callback failed\n    int start(uint64_t period_steps, uint64_t high_steps, bool start_high,\n              gpi_set_action set_action);\n\n    int stop();\n\n  private:\n    GpiObjHdl *clk_signal = nullptr;\n    GpiCbHdl *clk_toggle_cb_hdl = nullptr;\n\n    uint64_t period = 0;\n    uint64_t t_high = 0;\n    gpi_set_action m_set_action;\n\n    int clk_val = 0;\n\n    int toggle(bool initialSet);\n    static int toggle_cb(void *gpi_clk);\n};\n\nint GpiClock::start(uint64_t period_steps, uint64_t high_steps, bool start_high,\n                    gpi_set_action set_action) {\n    if (clk_toggle_cb_hdl) {\n        return EBUSY;\n    }\n    if ((period_steps < 2) || (high_steps < 1) ||\n        (high_steps >= period_steps)) {\n        return EINVAL;\n    }\n\n    period = period_steps;\n    t_high = high_steps;\n    m_set_action = set_action;\n\n    clk_val = start_high;\n    return toggle(true);\n}\n\nint GpiClock::stop() {\n    if (!clk_toggle_cb_hdl) {\n        return -1;\n    }\n    gpi_remove_cb(clk_toggle_cb_hdl);\n    clk_toggle_cb_hdl = nullptr;\n    return 0;\n}\n\nint GpiClock::toggle(bool initialSet) {\n    if (!initialSet) {\n        clk_val = !clk_val;\n    }\n    gpi_set_signal_value_int(clk_signal, clk_val, m_set_action);\n\n    uint64_t to_next_edge = clk_val ? t_high : (period - t_high);\n\n    clk_toggle_cb_hdl =\n        gpi_register_timed_callback(&GpiClock::toggle_cb, this, to_next_edge);\n    if (!clk_toggle_cb_hdl) {\n        // LCOV_EXCL_START\n        if (!initialSet) {\n            // Failing when called from start() will be reported via\n            // exception, but log in case of later failure that would\n            // otherwise be silent.\n            PYGPI_LOG_ERROR(\n                \"Clock will be stopped: failed to register toggle cb\");\n        }\n        return EAGAIN;\n        // LCOV_EXCL_STOP\n    }\n\n    return 0;\n}\n\nint GpiClock::toggle_cb(void *gpi_clk) {\n    PYGPI_LOG_TRACE(\"GPI => [ PYGPI (GpiClock) ]\");\n    GpiClock *clk_obj = (GpiClock *)gpi_clk;\n    int result = clk_obj->toggle(false);\n    PYGPI_LOG_TRACE(\"[ PYGPI (GpiClock) ] => GPI\");\n    return result;\n}\n\n// Create a new clock object\nstatic PyObject *clock_create(PyObject *, PyObject *args) {\n    if (!gpi_has_registered_impl()) {\n        // LCOV_EXCL_START\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return NULL;\n        // LCOV_EXCL_STOP\n    }\n\n    // Extract the clock signal sim object\n    PyObject *pSigHdl;\n    if (!PyArg_ParseTuple(args, \"O!:clock_create\",\n                          &gpi_hdl_Object<gpi_sim_hdl>::py_type, &pSigHdl)) {\n        return NULL;\n    }\n    gpi_sim_hdl sim_hdl = ((gpi_hdl_Object<gpi_sim_hdl> *)pSigHdl)->hdl;\n\n    GpiClock *gpi_clk = new GpiClock(sim_hdl);\n\n    if (gpi_clk) {\n        return gpi_hdl_New(gpi_clk);\n    } else {\n        // LCOV_EXCL_START\n        PyErr_SetString(PyExc_RuntimeError, \"Failed to create clock!\");\n        return NULL;\n        // LCOV_EXCL_STOP\n    }\n}\n\nstatic void clock_dealloc(PyObject *self) {\n    if (!gpi_has_registered_impl()) {\n        // LCOV_EXCL_START\n        PyErr_SetString(PyExc_RuntimeError, \"No simulator available!\");\n        return;\n        // LCOV_EXCL_STOP\n    }\n\n    if (Py_TYPE(self) != &gpi_hdl_Object<gpi_clk_hdl>::py_type) {\n        // LCOV_EXCL_START\n        PyErr_SetString(PyExc_TypeError, \"Wrong type for clock_dealloc!\");\n        return;\n        // LCOV_EXCL_STOP\n    }\n\n    GpiClock *gpi_clk = ((gpi_hdl_Object<gpi_clk_hdl> *)self)->hdl;\n\n    delete gpi_clk;\n\n    Py_TYPE(self)->tp_free((PyObject *)self);\n}\n\nstatic PyObject *clock_start(gpi_hdl_Object<gpi_clk_hdl> *self,\n                             PyObject *args) {\n    unsigned long long period, t_high;\n    int start_high;\n    int set_action;\n\n    if (!PyArg_ParseTuple(args, \"KKpi:start\", &period, &t_high, &start_high,\n                          &set_action)) {\n        return NULL;\n    }\n\n    int ret = self->hdl->start(period, t_high, start_high,\n                               (gpi_set_action)set_action);\n\n    if (ret != 0) {\n        if (ret == EINVAL) {\n            PyErr_SetString(PyExc_ValueError,\n                            \"Failed to start clock: invalid arguments!\\n\");\n        } else if (ret == EBUSY) {\n            PyErr_SetString(PyExc_RuntimeError,\n                            \"Failed to start clock: already started!\\n\");\n        } else {\n            // LCOV_EXCL_START\n            PyErr_SetString(PyExc_RuntimeError, \"Failed to start clock!\\n\");\n            // LCOV_EXCL_STOP\n        }\n        return NULL;\n    }\n\n    Py_RETURN_NONE;\n}\n\nstatic PyObject *clk_stop(gpi_hdl_Object<gpi_clk_hdl> *self, PyObject *) {\n    self->hdl->stop();\n\n    Py_RETURN_NONE;\n}\n\nstatic int add_module_constants(PyObject *simulator) {\n    // Make the GPI constants accessible from the C world\n    if (PyModule_AddIntConstant(simulator, \"UNKNOWN\", GPI_UNKNOWN) < 0 ||\n        PyModule_AddIntConstant(simulator, \"MEMORY\", GPI_MEMORY) < 0 ||\n        PyModule_AddIntConstant(simulator, \"MODULE\", GPI_MODULE) < 0 ||\n        PyModule_AddIntConstant(simulator, \"NETARRAY\", GPI_ARRAY) < 0 ||\n        PyModule_AddIntConstant(simulator, \"ENUM\", GPI_ENUM) < 0 ||\n        PyModule_AddIntConstant(simulator, \"STRUCTURE\", GPI_STRUCTURE) < 0 ||\n        PyModule_AddIntConstant(simulator, \"PACKED_STRUCTURE\",\n                                GPI_PACKED_STRUCTURE) < 0 ||\n        PyModule_AddIntConstant(simulator, \"REAL\", GPI_REAL) < 0 ||\n        PyModule_AddIntConstant(simulator, \"INTEGER\", GPI_INTEGER) < 0 ||\n        PyModule_AddIntConstant(simulator, \"STRING\", GPI_STRING) < 0 ||\n        PyModule_AddIntConstant(simulator, \"GENARRAY\", GPI_GENARRAY) < 0 ||\n        PyModule_AddIntConstant(simulator, \"PACKAGE\", GPI_PACKAGE) < 0 ||\n        PyModule_AddIntConstant(simulator, \"OBJECTS\", GPI_OBJECTS) < 0 ||\n        PyModule_AddIntConstant(simulator, \"DRIVERS\", GPI_DRIVERS) < 0 ||\n        PyModule_AddIntConstant(simulator, \"LOADS\", GPI_LOADS) < 0 ||\n        PyModule_AddIntConstant(simulator, \"RISING\", GPI_RISING) < 0 ||\n        PyModule_AddIntConstant(simulator, \"FALLING\", GPI_FALLING) < 0 ||\n        PyModule_AddIntConstant(simulator, \"VALUE_CHANGE\", GPI_VALUE_CHANGE) <\n            0 ||\n        PyModule_AddIntConstant(simulator, \"RANGE_UP\", GPI_RANGE_UP) < 0 ||\n        PyModule_AddIntConstant(simulator, \"RANGE_DOWN\", GPI_RANGE_DOWN) < 0 ||\n        PyModule_AddIntConstant(simulator, \"RANGE_NO_DIR\", GPI_RANGE_NO_DIR) <\n            0 ||\n        PyModule_AddIntConstant(simulator, \"LOGIC\", GPI_LOGIC) < 0 ||\n        PyModule_AddIntConstant(simulator, \"LOGIC_ARRAY\", GPI_LOGIC_ARRAY) <\n            0 ||\n        PyModule_AddIntConstant(simulator, \"PACKED_OBJECT\", GPI_PACKED_OBJECT) <\n            0 ||\n        false) {\n        return -1;\n    }\n\n    return 0;\n}\n\n// Add the extension types as entries in the module namespace\nstatic int add_module_types(PyObject *simulator) {\n    PyObject *typ;\n\n    typ = (PyObject *)&gpi_hdl_Object<gpi_sim_hdl>::py_type;\n    Py_INCREF(typ);\n    if (PyModule_AddObject(simulator, \"sim_obj\", typ) < 0) {\n        Py_DECREF(typ);\n        return -1;\n    }\n\n    typ = (PyObject *)&gpi_hdl_Object<gpi_cb_hdl>::py_type;\n    Py_INCREF(typ);\n    if (PyModule_AddObject(simulator, \"sim_callback\", typ) < 0) {\n        Py_DECREF(typ);\n        return -1;\n    }\n\n    typ = (PyObject *)&gpi_hdl_Object<gpi_iterator_hdl>::py_type;\n    Py_INCREF(typ);\n    if (PyModule_AddObject(simulator, \"sim_obj_iterator\", typ) < 0) {\n        Py_DECREF(typ);\n        return -1;\n    }\n\n    typ = (PyObject *)&gpi_hdl_Object<gpi_clk_hdl>::py_type;\n    Py_INCREF(typ);\n    if (PyModule_AddObject(simulator, \"cpp_clock\", typ) < 0) {\n        // LCOV_EXCL_START\n        Py_DECREF(typ);\n        return -1;\n        // LCOV_EXCL_STOP\n    }\n\n    return 0;\n}\n\n/* NOTE: in the following docstrings we are specifying the parameters twice, but\n * this is necessary. The first docstring before the long '--' line specifies\n * the __text_signature__ that is used by the help() function. And the second\n * after the '--' line contains type annotations used by the\n * `autodoc_docstring_signature` setting of sphinx.ext.autodoc for generating\n * documentation because type annotations are not supported in\n * __text_signature__.\n */\n\nstatic PyMethodDef SimulatorMethods[] = {\n    {\"get_root_handle\", get_root_handle, METH_VARARGS,\n     PyDoc_STR(\"get_root_handle(name, /)\\n\"\n               \"--\\n\\n\"\n               \"get_root_handle(name: str) -> cocotb.simulator.sim_obj\\n\"\n               \"Get the root handle.\")},\n    {\"package_iterate\", package_iterate, METH_NOARGS,\n     PyDoc_STR(\"package_iterate(/)\\n\"\n               \"--\\n\\n\"\n               \"package_iterate() -> cocotb.simulator.sim_obj_iterator\\n\"\n               \"Get an iterator handle to loop over all HDL packages.\\n\"\n               \"\\n\"\n               \".. versionadded:: 2.0\")},\n    {\"register_timed_callback\", register_timed_callback, METH_VARARGS,\n     PyDoc_STR(\"register_timed_callback(time, func, /, *args)\\n\"\n               \"--\\n\\n\"\n               \"register_timed_callback(time: int, func: Callable[..., Any], \"\n               \"*args: Any) -> cocotb.simulator.sim_callback\\n\"\n               \"Register a timed callback.\")},\n    {\"register_value_change_callback\", register_value_change_callback,\n     METH_VARARGS,\n     PyDoc_STR(\"register_value_change_callback(signal, func, edge, /, *args)\\n\"\n               \"--\\n\\n\"\n               \"register_value_change_callback(signal: \"\n               \"cocotb.simulator.sim_obj, func: Callable[..., Any], edge: \"\n               \"int, *args: Any) -> cocotb.simulator.sim_callback\\n\"\n               \"Register a signal change callback.\")},\n    {\"register_readonly_callback\", register_readonly_callback, METH_VARARGS,\n     PyDoc_STR(\"register_readonly_callback(func, /, *args)\\n\"\n               \"--\\n\\n\"\n               \"register_readonly_callback(func: Callable[..., Any], *args: \"\n               \"Any) -> cocotb.simulator.sim_callback\\n\"\n               \"Register a callback for the read-only phase.\")},\n    {\"register_nextstep_callback\", register_nextstep_callback, METH_VARARGS,\n     PyDoc_STR(\"register_nextstep_callback(func, /, *args)\\n\"\n               \"--\\n\\n\"\n               \"register_nextstep_callback(func: Callable[..., Any], *args: \"\n               \"Any) -> cocotb.simulator.sim_callback\\n\"\n               \"Register a callback for the cbNextSimTime callback.\")},\n    {\"register_rwsynch_callback\", register_rwsynch_callback, METH_VARARGS,\n     PyDoc_STR(\"register_rwsynch_callback(func, /, *args)\\n\"\n               \"--\\n\\n\"\n               \"register_rwsynch_callback(func: Callable[..., Any], *args: \"\n               \"Any) -> cocotb.simulator.sim_callback\\n\"\n               \"Register a callback for the read-write phase.\")},\n    {\"stop_simulator\", stop_simulator, METH_VARARGS,\n     PyDoc_STR(\"stop_simulator()\\n\"\n               \"--\\n\\n\"\n               \"stop_simulator() -> None\\n\"\n               \"Instruct the attached simulator to stop. Users should not call \"\n               \"this function.\")},\n    {\"set_gpi_log_level\", set_gpi_log_level, METH_VARARGS,\n     PyDoc_STR(\"set_gpi_log_level(level, /)\\n\"\n               \"--\\n\\n\"\n               \"set_gpi_log_level(level: int) -> None\\n\"\n               \"Set the log level of GPI logger.\")},\n    {\"is_running\", is_running, METH_NOARGS,\n     PyDoc_STR(\"is_running()\\n\"\n               \"--\\n\\n\"\n               \"is_running() -> bool\\n\"\n               \"Returns ``True`` if the caller is running within a simulator.\\n\"\n               \"\\n\"\n               \".. versionadded:: 1.4\")},\n    {\"get_sim_time\", get_sim_time, METH_NOARGS,\n     PyDoc_STR(\"get_sim_time()\\n\"\n               \"--\\n\\n\"\n               \"get_sim_time() -> Tuple[int, int]\\n\"\n               \"Get the current simulation time.\\n\"\n               \"\\n\"\n               \"Time is represented as a tuple of 32-bit integers (``(low32, \"\n               \"high32)``) comprising a single 64-bit integer.\")},\n    {\"get_precision\", get_precision, METH_NOARGS,\n     PyDoc_STR(\"get_precision()\\n\"\n               \"--\\n\\n\"\n               \"get_precision() -> int\\n\"\n               \"Get the precision of the simulator in powers of 10.\\n\"\n               \"\\n\"\n               \"For example, if ``-12`` is returned, the simulator's time \"\n               \"precision is 10**-12 or 1 ps.\")},\n    {\"get_simulator_product\", get_simulator_product, METH_NOARGS,\n     PyDoc_STR(\"get_simulator_product()\\n\"\n               \"--\\n\\n\"\n               \"get_simulator_product() -> str\\n\"\n               \"Get the simulator's product string.\")},\n    {\"get_simulator_version\", get_simulator_version, METH_NOARGS,\n     PyDoc_STR(\"get_simulator_version()\\n\"\n               \"--\\n\\n\"\n               \"get_simulator_version() -> str\\n\"\n               \"Get the simulator's product version string.\")},\n    {\"get_simulator_args\", get_argv, METH_NOARGS,\n     PyDoc_STR(\"get_simulator_args()\\n\"\n               \"--\\n\\n\"\n               \"get_simulator_args() -> list[str]\\n\"\n               \"Get the simulator's command line arguments.\")},\n    {\"clock_create\", clock_create, METH_VARARGS,\n     PyDoc_STR(\"clock_create(signal, /)\\n\"\n               \"--\\n\\n\"\n               \"clock_create(signal: cocotb.simulator.sim_obj\"\n               \") -> cocotb.simulator.cpp_clock\\n\"\n               \"Create a clock driver on a signal.\\n\"\n               \"\\n\"\n               \".. versionadded:: 2.0\")},\n    {\"initialize_logger\", initialize_logger, METH_VARARGS,\n     PyDoc_STR(\"initialize_logger(log_func, /)\\n\"\n               \"--\\n\\n\"\n               \"initialize_logger(\"\n               \"log_func: Callable[[Logger, int, str, int, str, str], None], \"\n               \"get_logger: Callable[[str], Logger]\"\n               \") -> None\\n\"\n               \"Initialize the GPI logger with Python logging functions.\")},\n    {\"set_sim_event_callback\", set_sim_event_callback, METH_VARARGS,\n     PyDoc_STR(\"set_sim_event_callback(sim_event_callback, /)\\n\"\n               \"--\\n\\n\"\n               \"set_sim_event_callback(sim_event_callback: Callable[[], \"\n               \"object]) -> None\\n\"\n               \"Set the callback for simulator events.\")},\n    {NULL, NULL, 0, NULL} /* Sentinel */\n};\n\nstatic struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT,\n                                       MODULE_NAME,\n                                       NULL,\n                                       -1,\n                                       SimulatorMethods,\n                                       NULL,\n                                       NULL,\n                                       NULL,\n                                       NULL};\n\n#ifndef _WIN32\n// Only required for Python < 3.9, default for 3.9+ (bpo-11410)\n#pragma GCC visibility push(default)\nPyMODINIT_FUNC PyInit_simulator(void);\n#pragma GCC visibility pop\n#endif\n\nPyMODINIT_FUNC PyInit_simulator(void) {\n    /* initialize the extension types */\n    if (PyType_Ready(&gpi_hdl_Object<gpi_sim_hdl>::py_type) < 0) {\n        return NULL;\n    }\n    if (PyType_Ready(&gpi_hdl_Object<gpi_cb_hdl>::py_type) < 0) {\n        return NULL;\n    }\n    if (PyType_Ready(&gpi_hdl_Object<gpi_iterator_hdl>::py_type) < 0) {\n        return NULL;\n    }\n    if (PyType_Ready(&gpi_hdl_Object<gpi_clk_hdl>::py_type) < 0) {\n        // LCOV_EXCL_START\n        return NULL;\n        // LCOV_EXCL_STOP\n    }\n\n    PyObject *simulator = PyModule_Create(&moduledef);\n    if (simulator == NULL) {\n        return NULL;\n    }\n\n    if (add_module_constants(simulator) < 0) {\n        Py_DECREF(simulator);\n        return NULL;\n    }\n\n    if (add_module_types(simulator) < 0) {\n        Py_DECREF(simulator);\n        return NULL;\n    }\n\n    return simulator;\n}\n\n/* NOTE: in the following docstrings we are specifying the parameters twice, but\n * this is necessary. The first docstring before the long '--' line specifies\n * the __text_signature__ that is used by the help() function. And the second\n * after the '--' line contains type annotations used by the\n * `autodoc_docstring_signature` setting of sphinx.ext.autodoc for generating\n * documentation because type annotations are not supported in\n * __text_signature__.\n */\n\nstatic PyMethodDef sim_obj_methods[] = {\n    {\"get_signal_val_long\", (PyCFunction)get_signal_val_long, METH_NOARGS,\n     PyDoc_STR(\"get_signal_val_long($self)\\n\"\n               \"--\\n\\n\"\n               \"get_signal_val_long() -> int\\n\"\n               \"Get the value of a signal as an integer.\")},\n    {\"get_signal_val_str\", (PyCFunction)get_signal_val_str, METH_NOARGS,\n     PyDoc_STR(\"get_signal_val_str($self)\\n\"\n               \"--\\n\\n\"\n               \"get_signal_val_str() -> bytes\\n\"\n               \"Get the value of a signal as a byte string.\")},\n    {\"get_signal_val_binstr\", (PyCFunction)get_signal_val_binstr, METH_NOARGS,\n     PyDoc_STR(\"get_signal_val_binstr($self)\\n\"\n               \"--\\n\\n\"\n               \"get_signal_val_binstr() -> str\\n\"\n               \"Get the value of a logic vector signal as a string of (``0``, \"\n               \"``1``, ``X``, etc.), one element per character.\")},\n    {\"get_signal_val_real\", (PyCFunction)get_signal_val_real, METH_NOARGS,\n     PyDoc_STR(\"get_signal_val_real($self)\\n\"\n               \"--\\n\\n\"\n               \"get_signal_val_real() -> float\\n\"\n               \"Get the value of a signal as a float.\")},\n    {\"set_signal_val_int\", (PyCFunction)set_signal_val_int, METH_VARARGS,\n     PyDoc_STR(\"set_signal_val_int($self, action, value, /)\\n\"\n               \"--\\n\\n\"\n               \"set_signal_val_int(action: int, value: int) -> None\\n\"\n               \"Set the value of a signal using an int.\")},\n    {\"set_signal_val_str\", (PyCFunction)set_signal_val_str, METH_VARARGS,\n     PyDoc_STR(\"set_signal_val_str($self, action, value, /)\\n\"\n               \"--\\n\\n\"\n               \"set_signal_val_str(action: int, value: bytes) -> None\\n\"\n               \"Set the value of a signal using a user-encoded string.\")},\n    {\"set_signal_val_binstr\", (PyCFunction)set_signal_val_binstr, METH_VARARGS,\n     PyDoc_STR(\"set_signal_val_binstr($self, action, value, /)\\n\"\n               \"--\\n\\n\"\n               \"set_signal_val_binstr(action: int, value: str) -> None\\n\"\n               \"Set the value of a logic vector signal using a string of \"\n               \"(``0``, ``1``, ``X``, etc.), one element per character.\")},\n    {\"set_signal_val_real\", (PyCFunction)set_signal_val_real, METH_VARARGS,\n     PyDoc_STR(\"set_signal_val_real($self, action, value, /)\\n\"\n               \"--\\n\\n\"\n               \"set_signal_val_real(action: int, value: float) -> None\\n\"\n               \"Set the value of a signal using a float.\")},\n    {\"get_definition_name\", (PyCFunction)get_definition_name, METH_NOARGS,\n     PyDoc_STR(\"get_definition_name($self)\\n\"\n               \"--\\n\\n\"\n               \"get_definition_name() -> str\\n\"\n               \"Get the name of a GPI object's definition.\")},\n    {\"get_definition_file\", (PyCFunction)get_definition_file, METH_NOARGS,\n     PyDoc_STR(\"get_definition_file($self)\\n\"\n               \"--\\n\\n\"\n               \"get_definition_file() -> str\\n\"\n               \"Get the file that sources the object's definition.\")},\n    {\"get_handle_by_name\", (PyCFunction)get_handle_by_name, METH_VARARGS,\n     PyDoc_STR(\n         \"get_handle_by_name($self, name, discovery_method/)\\n\"\n         \"--\\n\\n\"\n         \"get_handle_by_name(name: str, discovery_method: \"\n         \"cocotb.handle._GPIDiscovery) -> \"\n         \"cocotb.simulator.sim_obj\\n\"\n         \"Get a handle to a child object by name.\\n\"\n         \"Specify *discovery_method* to determine the signal discovery \"\n         \"strategy. :data:`~cocotb.handle.GPIDiscovery.AUTO` by default.\")},\n    {\"get_handle_by_index\", (PyCFunction)get_handle_by_index, METH_VARARGS,\n     PyDoc_STR(\"get_handle_by_index($self, index, /)\\n\"\n               \"--\\n\\n\"\n               \"get_handle_by_index(index: int) -> cocotb.simulator.sim_obj\\n\"\n               \"Get a handle to a child object by index.\")},\n    {\"get_name_string\", (PyCFunction)get_name_string, METH_NOARGS,\n     PyDoc_STR(\"get_name_string($self)\\n\"\n               \"--\\n\\n\"\n               \"get_name_string() -> str\\n\"\n               \"Get the name of an object as a string.\")},\n    {\"get_type_string\", (PyCFunction)get_type_string, METH_NOARGS,\n     PyDoc_STR(\"get_type_string($self)\\n\"\n               \"--\\n\\n\"\n               \"get_type_string() -> str\\n\"\n               \"Get the GPI type of an object as a string.\")},\n    {\"get_type\", (PyCFunction)get_type, METH_NOARGS,\n     PyDoc_STR(\"get_type($self)\\n\"\n               \"--\\n\\n\"\n               \"get_type() -> int\\n\"\n               \"Get the GPI type of an object as an enum.\")},\n    {\"get_const\", (PyCFunction)get_const, METH_NOARGS,\n     PyDoc_STR(\"get_const($self)\\n\"\n               \"--\\n\\n\"\n               \"get_const() -> bool\\n\"\n               \"Return ``True`` if the object is a constant.\")},\n    {\"get_signed\", (PyCFunction)get_signed, METH_NOARGS,\n     PyDoc_STR(\"get_signed($self)\\n\"\n               \"--\\n\\n\"\n               \"get_signed() -> bool\\n\"\n               \"Return ``1`` if the object is a signed integer, ``0`` if \"\n               \"unsigned, and ``-1`` if unknown or not applicable.\")},\n    {\"get_num_elems\", (PyCFunction)get_num_elems, METH_NOARGS,\n     PyDoc_STR(\"get_num_elems($self)\\n\"\n               \"--\\n\\n\"\n               \"get_num_elems() -> int\\n\"\n               \"Get the number of elements contained in the handle.\")},\n    {\"get_range\", (PyCFunction)get_range, METH_NOARGS,\n     PyDoc_STR(\"get_range($self)\\n\"\n               \"--\\n\\n\"\n               \"get_range() -> Tuple[int, int, int]\\n\"\n               \"Get the range of elements (tuple) contained in the handle. \"\n               \"The first two elements of the tuple specify the left and right \"\n               \"bounds, while the third specifies the direction (``1`` for \"\n               \"ascending, ``-1`` for descending, and ``0`` for undefined).\")},\n    {\"get_indexable\", (PyCFunction)get_indexable, METH_NOARGS,\n     PyDoc_STR(\"get_indexable($self)\\n\"\n               \"--\\n\\n\"\n               \"get_indexable() -> bool\\n\"\n               \"Return ``True`` if indexable.\")},\n    {\"iterate\", (PyCFunction)iterate, METH_VARARGS,\n     PyDoc_STR(\n         \"iterate($self, mode, /)\\n\"\n         \"--\\n\\n\"\n         \"iterate(mode: int) -> cocotb.simulator.sim_obj_iterator\\n\"\n         \"Get an iterator handle to loop over all members in an object.\")},\n    {NULL, NULL, 0, NULL} /* Sentinel */\n};\n\n// putting these at the bottom means that all the functions above are accessible\ntemplate <>\nPyTypeObject gpi_hdl_Object<gpi_sim_hdl>::py_type = []() -> PyTypeObject {\n    auto type = fill_common_slots<gpi_sim_hdl>();\n    type.tp_name = \"cocotb.simulator.sim_obj\";\n    type.tp_doc =\n        \"A simulation object that represents a GPI object handle.\\n\"\n        \"\\n\"\n        \"Contains methods for getting and setting the value of a GPI object, \"\n        \"and introspection of the object and design hierarchy.\";\n    type.tp_methods = sim_obj_methods;\n    return type;\n}();\n\ntemplate <>\nPyTypeObject gpi_hdl_Object<gpi_iterator_hdl>::py_type = []() -> PyTypeObject {\n    auto type = fill_common_slots<gpi_iterator_hdl>();\n    type.tp_name = \"cocotb.simulator.sim_obj_iterator\";\n    type.tp_doc =\n        \"A :term:`Python iterator <python:iterator>` that wraps a GPI iterator \"\n        \"handle.\";\n    type.tp_iter = PyObject_SelfIter;\n    type.tp_iternext = (iternextfunc)iterator_next;\n    return type;\n}();\n\nstatic PyMethodDef sim_callback_methods[] = {\n    {\"deregister\", (PyCFunction)deregister, METH_NOARGS,\n     PyDoc_STR(\"deregister($self)\\n\"\n               \"--\\n\\n\"\n               \"deregister() -> None\\n\"\n               \"De-register this callback.\")},\n    {NULL, NULL, 0, NULL} /* Sentinel */\n};\n\ntemplate <>\nPyTypeObject gpi_hdl_Object<gpi_cb_hdl>::py_type = []() -> PyTypeObject {\n    auto type = fill_common_slots<gpi_cb_hdl>();\n    type.tp_name = \"cocotb.simulator.sim_callback\";\n    type.tp_doc =\n        \"A simulation callback object that manages a GPI callback handle.\";\n    type.tp_methods = sim_callback_methods;\n    return type;\n}();\n\nstatic PyMethodDef cpp_clock_methods[] = {\n    {\"start\", (PyCFunction)clock_start, METH_VARARGS,\n     PyDoc_STR(\n         \"start($self, period_steps, high_steps, start_high)\\n\"\n         \"--\\n\\n\"\n         \"start(period_steps: int, high_steps: int, start_high: bool) -> None\\n\"\n         \"Start this clock now.\\n\"\n         \"\\n\"\n         \"The clock will have a period of *period_steps* time steps, \"\n         \"and out of that period it will be high for *high_steps* time steps. \"\n         \"If *start_high* is ``True``, start at the beginning of the high \"\n         \"state, \"\n         \"otherwise start at the beginning of the low state.\\n\"\n         \"\\n\"\n         \"Raises:\\n\"\n         \"    TypeError: If there are an incorrect number of arguments or \"\n         \"they are of the wrong type.\\n\"\n         \"    ValueError: If *period_steps* and *high_steps* are such that in \"\n         \"one \"\n         \"period the duration of the low or high state would be less \"\n         \"than one time step, or *high_steps* is greater than *period_steps*.\\n\"\n         \"    RuntimeError: If the clock was already started, or the \"\n         \"GPI callback could not be registered.\")},\n    {\"stop\", (PyCFunction)clk_stop, METH_NOARGS,\n     PyDoc_STR(\"stop($self)\\n\"\n               \"--\\n\\n\"\n               \"stop() -> None\\n\"\n               \"Stop this clock now.\")},\n    {NULL, NULL, 0, NULL} /* Sentinel */\n};\n\ntemplate <>\nPyTypeObject gpi_hdl_Object<gpi_clk_hdl>::py_type = []() -> PyTypeObject {\n    auto type = fill_common_slots<gpi_clk_hdl>();\n    type.tp_name = \"cocotb.simulator.cpp_clock\";\n    type.tp_doc =\n        \"A clock implemented in C++ that uses the GPI directly.\\n\"\n        \"\\n\"\n        \"The clock signal is driven without interacting with Python to \"\n        \"increase performance.\";\n    type.tp_methods = cpp_clock_methods;\n    type.tp_dealloc = clock_dealloc;\n    return type;\n}();\n"
  },
  {
    "path": "src/cocotb/share/lib/pygpi/embed.cpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n// Embed Python into the simulator using GPI\n\n#include <Python.h>\n#include <gpi.h>  // gpi_register_*\n\n#include <cassert>\n#include <cstdlib>\n#include <cstring>\n#include <string>\n\n#include \"../utils.hpp\"      // DEFER\n#include \"./pygpi_priv.hpp\"  // pygpi_logger_set_level, pygpi_logger_initialize, pygpi_logger_finalize, LOG_* macros, PYGPI_EXPORT\n\n#if defined(_WIN32)\n#include <windows.h>\n#define sleep(n) Sleep(1000 * n)\n#define getpid() GetCurrentProcessId()\n#ifndef PATH_MAX\n#define PATH_MAX MAX_PATH\n#endif\n#else\n#include <unistd.h>\n#endif\n\nstatic bool python_init_called = 0;\nstatic bool embed_init_called = 0;\n\nstatic wchar_t progname[] = L\"cocotb\";\nstatic wchar_t *argv[] = {progname};\n\nstatic int get_interpreter_path(wchar_t *path, size_t path_size) {\n    const char *path_c = getenv(\"PYGPI_PYTHON_BIN\");\n    if (!path_c) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\n            \"PYGPI_PYTHON_BIN variable not set. Can't initialize Python \"\n            \"interpreter!\");\n        return -1;\n        // LCOV_EXCL_STOP\n    }\n\n    auto path_temp = Py_DecodeLocale(path_c, NULL);\n    if (path_temp == NULL) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\n            \"Unable to set Python Program Name. \"\n            \"Decoding error in Python executable path.\");\n        PYGPI_LOG_INFO(\"Python executable path: %s\", path_c);\n        return -1;\n        // LCOV_EXCL_STOP\n    }\n    DEFER(PyMem_RawFree(path_temp));\n\n    wcsncpy(path, path_temp, path_size / sizeof(wchar_t));\n    if (path[(path_size / sizeof(wchar_t)) - 1]) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\n            \"Unable to set Python Program Name. Path to interpreter too long\");\n        PYGPI_LOG_INFO(\"Python executable path: %s\", path_c);\n        return -1;\n        // LCOV_EXCL_STOP\n    }\n\n    return 0;\n}\n\nstatic void pygpi_init_debug() {\n    char *debug_env = getenv(\"PYGPI_DEBUG\");\n    if (debug_env) {\n        std::string pygpi_debug = debug_env;\n        // If it's explicitly set to 0, don't enable\n        if (pygpi_debug != \"0\") {\n            pygpi_debug_enabled = 1;\n            python_context_tracing_enabled = 1;\n        }\n    }\n}\n\nstatic int start_of_sim_time(void *);\nstatic void end_of_sim_time(void *);\nstatic void finalize(void *);\n\nextern \"C\" PYGPI_EXPORT void initialize(void) {\n    pygpi_init_debug();\n    pygpi_logging_initialize();\n\n    PYGPI_LOG_TRACE(\"GPI Init => [ PYGPI Init ]\");\n    DEFER(PYGPI_LOG_TRACE(\"[ PYGPI Init ] => GPI Init\"));\n\n    if (python_init_called) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\"PyGPI library initialized again!\");\n        return;\n        // LCOV_EXCL_STOP\n    }\n    python_init_called = 1;\n\n    // must set program name to Python executable before initialization, so\n    // initialization can determine path from executable\n\n    static wchar_t interpreter_path[PATH_MAX], sys_executable[PATH_MAX];\n\n    if (get_interpreter_path(interpreter_path, sizeof(interpreter_path))) {\n        // LCOV_EXCL_START\n        return;\n        // LCOV_EXCL_STOP\n    }\n    PYGPI_LOG_INFO(\"Using Python %s interpreter at %ls\", PY_VERSION,\n                   interpreter_path);\n\n    /* Use the new Python Initialization Configuration from Python 3.8. */\n    PyConfig config;\n    PyStatus status;\n\n    PyConfig_InitPythonConfig(&config);\n    DEFER(PyConfig_Clear(&config));\n\n    PyConfig_SetString(&config, &config.executable, interpreter_path);\n\n    status = PyConfig_SetArgv(&config, 1, argv);\n    if (PyStatus_Exception(status)) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\"Failed to set ARGV during the Python initialization\");\n        if (status.err_msg != NULL) {\n            PYGPI_LOG_ERROR(\"\\terror: %s\", status.err_msg);\n        }\n        if (status.func != NULL) {\n            PYGPI_LOG_ERROR(\"\\tfunction: %s\", status.func);\n        }\n        return;\n        // LCOV_EXCL_STOP\n    }\n\n    status = Py_InitializeFromConfig(&config);\n    if (PyStatus_Exception(status)) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\"Failed to initialize Python\");\n        if (status.err_msg != NULL) {\n            PYGPI_LOG_ERROR(\"\\terror: %s\", status.err_msg);\n        }\n        if (status.func != NULL) {\n            PYGPI_LOG_ERROR(\"\\tfunction: %s\", status.func);\n        }\n        return;\n        // LCOV_EXCL_STOP\n    }\n\n    /* Sanity check: make sure sys.executable was initialized to\n     * interpreter_path. */\n    PyObject *sys_executable_obj = PySys_GetObject(\"executable\");\n    if (sys_executable_obj == NULL) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\"Failed to load sys.executable\");\n        // LCOV_EXCL_STOP\n    } else if (PyUnicode_AsWideChar(sys_executable_obj, sys_executable,\n                                    sizeof(sys_executable)) == -1) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\"Failed to convert sys.executable to wide string\");\n        // LCOV_EXCL_STOP\n    } else if (wcscmp(interpreter_path, sys_executable) != 0) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\n            \"Unexpected sys.executable value (expected '%ls', got '%ls')\",\n            interpreter_path, sys_executable);\n        // LCOV_EXCL_STOP\n    }\n\n    gpi_register_start_of_sim_time_callback(start_of_sim_time, nullptr);\n    gpi_register_end_of_sim_time_callback(end_of_sim_time, nullptr);\n    gpi_register_finalize_callback(finalize, nullptr);\n\n    /* Before returning we check if the user wants pause the simulator thread\n       such that they can attach */\n    const char *pause = getenv(\"COCOTB_ATTACH\");\n    if (pause) {\n        unsigned long sleep_time = strtoul(pause, NULL, 10);\n        /* This should check for out-of-range parses which returns ULONG_MAX and\n           sets errno, as well as correct parses that would be sliced by the\n           narrowing cast */\n        if (errno == ERANGE || sleep_time >= UINT_MAX) {\n            // LCOV_EXCL_START\n            PYGPI_LOG_ERROR(\n                \"COCOTB_ATTACH only needs to be set to ~30 seconds\");\n            return;\n            // LCOV_EXCL_STOP\n        }\n        if ((errno != 0 && sleep_time == 0) || (sleep_time <= 0)) {\n            // LCOV_EXCL_START\n            PYGPI_LOG_ERROR(\n                \"COCOTB_ATTACH must be set to an integer base 10 or omitted\");\n            return;\n            // LCOV_EXCL_STOP\n        }\n\n        PYGPI_LOG_INFO(\n            \"Waiting for %lu seconds - attach to PID %d with your debugger\",\n            sleep_time, getpid());\n        sleep((unsigned int)sleep_time);\n    }\n}\n\nstatic void finalize(void *) {\n    PYGPI_LOG_TRACE(\"GPI Finalize => [ PYGPI Finalize ]\");\n    DEFER(PYGPI_LOG_TRACE(\"[ PYGPI Finalize ] => GPI Finalize\"));\n    // If initialization fails, this may be called twice:\n    // Before the initial callback returns and in the final callback.\n    // So we check if Python is still initialized before doing cleanup.\n    if (Py_IsInitialized()) {\n        c_to_python();\n        PyGILState_Ensure();  // Don't save state as we are calling Py_Finalize\n        Py_XDECREF(pEventFn);\n        pEventFn = NULL;\n        pygpi_logging_finalize();\n        Py_Finalize();\n        python_to_c();\n    }\n}\n\nstatic int start_of_sim_time(void *) {\n    PYGPI_LOG_TRACE(\"GPI Start Sim => [ PYGPI Start ]\");\n    DEFER(PYGPI_LOG_TRACE(\"[ PYGPI Start ] => GPI Start Sim\"));\n\n    // Check that we are not already initialized\n    if (embed_init_called) {\n        // LCOV_EXCL_START\n        PYGPI_LOG_ERROR(\"PyGPI library initialized again!\");\n        return -1;\n        // LCOV_EXCL_STOP\n    }\n    embed_init_called = 1;\n\n    // Ensure that the current thread is ready to call the Python C API\n    auto gstate = PyGILState_Ensure();\n    DEFER(PyGILState_Release(gstate));\n\n    c_to_python();\n    DEFER(python_to_c());\n\n    auto entry_utility_module = PyImport_ImportModule(\"pygpi.entry\");\n    if (!entry_utility_module) {\n        // LCOV_EXCL_START\n        PyErr_Print();\n        return -1;\n        // LCOV_EXCL_STOP\n    }\n    DEFER(Py_DECREF(entry_utility_module));\n\n    auto cocotb_retval =\n        PyObject_CallMethod(entry_utility_module, \"load_entry\", nullptr);\n    if (!cocotb_retval) {\n        // Printing a SystemExit calls exit(1), which we don't want.\n        if (!PyErr_ExceptionMatches(PyExc_SystemExit)) {\n            PyErr_Print();\n        }\n        // Clear error so re-entering Python doesn't fail.\n        PyErr_Clear();\n        return -1;\n    }\n    Py_DECREF(cocotb_retval);\n\n    return 0;\n}\n\nstatic void end_of_sim_time(void *) {\n    PYGPI_LOG_TRACE(\"GPI End Sim => [ PYGPI End ]\");\n    DEFER(PYGPI_LOG_TRACE(\"[ PYGPI End ] => GPI End Sim\"));\n\n    /* Indicate to the upper layer that a sim event occurred */\n\n    if (pEventFn) {\n        PyGILState_STATE gstate;\n        c_to_python();\n        gstate = PyGILState_Ensure();\n\n        PyObject *pValue = PyObject_CallNoArgs(pEventFn);\n        if (pValue == NULL) {\n            // Printing a SystemExit calls exit(1), which we don't want.\n            if (!PyErr_ExceptionMatches(PyExc_SystemExit)) {\n                PyErr_Print();\n            }\n            // Clear error so re-entering Python doesn't fail.\n            PyErr_Clear();\n            PYGPI_LOG_ERROR(\"Passing event to upper layer failed\");\n        }\n        Py_XDECREF(pValue);\n        PyGILState_Release(gstate);\n        python_to_c();\n    }\n}\n"
  },
  {
    "path": "src/cocotb/share/lib/pygpi/logging.cpp",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <Python.h>  // all things Python\n#include <gpi.h>     // all things GPI logging\n\n#include <cstdarg>  // va_list, va_copy, va_end\n#include <cstdio>   // fprintf, vsnprintf\n#include <map>      // std::map\n#include <string>   // std::string\n#include <vector>   // std::vector\n\n#include \"../utils.hpp\"  // DEFER\n#include \"./pygpi_priv.hpp\"\n\nstatic int pygpi_log_level = GPI_NOTSET;\n\nstatic PyObject *m_log_func = nullptr;\nstatic std::map<std::string, PyObject *> m_logger_map;\nstatic PyObject *m_get_logger = nullptr;\n\nstatic gpi_log_handler_ftype fallback_log_handler = nullptr;\nstatic void *fallback_log_userdata = nullptr;\n\nstatic void fallback_handler(const char *name, enum gpi_log_level level,\n                             const char *pathname, const char *funcname,\n                             long lineno, const char *msg, ...) {\n    // The standard provides no way to create an empty va_list, so we have to\n    // make these empty args list to make the compiler happy.\n    va_list args1, args2;\n    va_start(args1, msg);\n    va_copy(args2, args1);\n    DEFER(va_end(args2));\n    DEFER(va_end(args1));\n    // Note: don't call the LOG_ERROR macro because that might recurse\n    fallback_log_handler(fallback_log_userdata, name, level, pathname, funcname,\n                         lineno, msg, args1);\n    fallback_log_handler(fallback_log_userdata, \"gpi\", GPI_ERROR, __FILE__,\n                         __func__, __LINE__,\n                         \"Error calling Python logging function from C++ \"\n                         \"while logging the above\",\n                         args2);\n}\n\nstatic void pygpi_log_handler(void *, const char *name,\n                              enum gpi_log_level level, const char *pathname,\n                              const char *funcname, long lineno,\n                              const char *msg, va_list argp) {\n    // Always pass through messages when NOTSET to let Python make the decision.\n    // Otherwise, skip logs using the local log level for better performance.\n    if (pygpi_log_level != GPI_NOTSET && level < pygpi_log_level) {\n        return;\n    }\n\n    // If we haven't configured yet, use the fallback log handler\n    if (!m_log_func) {\n        return fallback_log_handler(fallback_log_userdata, name, level,\n                                    pathname, funcname, lineno, msg, argp);\n    }\n\n    va_list argp_copy;\n    va_copy(argp_copy, argp);\n    DEFER(va_end(argp_copy));\n\n    // before the log buffer to ensure it isn't clobbered.\n    PyGILState_STATE gstate = PyGILState_Ensure();\n    DEFER(PyGILState_Release(gstate));\n\n    static std::vector<char> log_buff(512);\n\n    log_buff.clear();\n    int n = vsnprintf(log_buff.data(), log_buff.capacity(), msg, argp);\n    if (n < 0) {\n        // On Windows with the Visual C Runtime prior to 2015 the above call to\n        // vsnprintf will return -1 if the buffer would overflow, rather than\n        // the number of bytes that would be written as required by the C99\n        // standard.\n        // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/vsnprintf-vsnprintf-vsnprintf-l-vsnwprintf-vsnwprintf-l\n        // So we try the call again with the buffer NULL and the size 0, which\n        // should return the number of bytes that would be written.\n        va_list argp_copy_again;\n        va_copy(argp_copy_again, argp_copy);\n        DEFER(va_end(argp_copy_again));\n        n = vsnprintf(NULL, 0, msg, argp_copy_again);\n        if (n < 0) {\n            // Here we know the error is for real, so we complain and move on.\n            // LCOV_EXCL_START\n            fprintf(stderr,\n                    \"Log message construction failed: (error code) %d\\n\", n);\n            return;\n            // LCOV_EXCL_STOP\n        }\n    }\n    if ((unsigned)n >= log_buff.capacity()) {\n        log_buff.reserve((unsigned)n + 1);\n        n = vsnprintf(log_buff.data(), (unsigned)n + 1, msg, argp_copy);\n        if (n < 0) {\n            // LCOV_EXCL_START\n            fprintf(stderr,\n                    \"Log message construction failed: (error code) %d\\n\", n);\n            return;\n            // LCOV_EXCL_STOP\n        }\n    }\n\n    PyObject *level_arg = PyLong_FromLong(level);  // New reference\n    if (level_arg == NULL) {\n        // LCOV_EXCL_START\n        PyErr_Print();\n        return fallback_handler(name, level, pathname, funcname, lineno,\n                                log_buff.data());\n        // LCOV_EXCL_STOP\n    }\n    DEFER(Py_DECREF(level_arg));\n\n    PyObject *logger;\n    const auto lookup = m_logger_map.find(name);\n    if (lookup == m_logger_map.end()) {\n        logger = PyObject_CallFunction(m_get_logger, \"s\", name);  // incs a ref\n        // LCOV_EXCL_START\n        if (!logger) {\n            PyErr_Print();\n            return fallback_handler(name, level, pathname, funcname, lineno,\n                                    log_buff.data());\n        }\n        // LCOV_EXCL_STOP\n        m_logger_map[name] = logger;  // steal that ref\n    } else {\n        logger = lookup->second;\n    }\n\n    PyObject *filename_arg = PyUnicode_FromString(pathname);  // New reference\n    if (filename_arg == NULL) {\n        // LCOV_EXCL_START\n        PyErr_Print();\n        return fallback_handler(name, level, pathname, funcname, lineno,\n                                log_buff.data());\n        // LCOV_EXCL_STOP\n    }\n    DEFER(Py_DECREF(filename_arg));\n\n    PyObject *lineno_arg = PyLong_FromLong(lineno);  // New reference\n    if (lineno_arg == NULL) {\n        // LCOV_EXCL_START\n        PyErr_Print();\n        return fallback_handler(name, level, pathname, funcname, lineno,\n                                log_buff.data());\n        // LCOV_EXCL_STOP\n    }\n    DEFER(Py_DECREF(lineno_arg));\n\n    PyObject *msg_arg = PyUnicode_FromString(log_buff.data());  // New reference\n    if (msg_arg == NULL) {\n        // LCOV_EXCL_START\n        PyErr_Print();\n        return fallback_handler(name, level, pathname, funcname, lineno,\n                                log_buff.data());\n        // LCOV_EXCL_STOP\n    }\n    DEFER(Py_DECREF(msg_arg));\n\n    PyObject *function_arg = PyUnicode_FromString(funcname);  // New reference\n    if (function_arg == NULL) {\n        // LCOV_EXCL_START\n        PyErr_Print();\n        return fallback_handler(name, level, pathname, funcname, lineno,\n                                log_buff.data());\n        // LCOV_EXCL_STOP\n    }\n    DEFER(Py_DECREF(function_arg))\n\n    // Log function args are logger_name, level, filename, lineno, msg, function\n    PyObject *handler_ret = PyObject_CallFunctionObjArgs(\n        m_log_func, logger, level_arg, filename_arg, lineno_arg, msg_arg,\n        function_arg, NULL);\n    if (handler_ret == NULL) {\n        // LCOV_EXCL_START\n        PyErr_Print();\n        return fallback_handler(name, level, pathname, funcname, lineno,\n                                log_buff.data());\n        // LCOV_EXCL_STOP\n    }\n    Py_DECREF(handler_ret);\n}\n\nvoid pygpi_log(enum gpi_log_level level, const char *pathname,\n               const char *funcname, long lineno, const char *fmt, ...) {\n    va_list argp;\n    va_start(argp, fmt);\n    DEFER(va_end(argp));\n    pygpi_log_handler(nullptr, \"pygpi\", level, pathname, funcname, lineno, fmt,\n                      argp);\n}\n\nvoid pygpi_logging_set_level(enum gpi_log_level level) {\n    pygpi_log_level = level;\n    gpi_native_logger_set_level(level);\n}\n\nvoid pygpi_logging_initialize() {\n    // Default to using the fallback handler until configured\n    gpi_get_log_handler(&fallback_log_handler, &fallback_log_userdata);\n    gpi_set_log_handler(pygpi_log_handler, nullptr);\n}\n\nvoid pygpi_logging_configure(PyObject *log_func, PyObject *get_logger) {\n    Py_INCREF(log_func);\n    Py_INCREF(get_logger);\n    m_log_func = log_func;\n    m_get_logger = get_logger;\n}\n\nvoid pygpi_logging_finalize() {\n    gpi_set_log_handler(fallback_log_handler, fallback_log_userdata);\n    Py_XDECREF(m_log_func);\n    Py_XDECREF(m_get_logger);\n    m_log_func = nullptr;\n    m_get_logger = nullptr;\n    for (auto &elem : m_logger_map) {\n        Py_DECREF(elem.second);\n    }\n    m_logger_map.clear();\n}\n\nPyObject *pEventFn = NULL;\n\n// Disabled by default\nint pygpi_debug_enabled = 0;\nint python_context_tracing_enabled = 0;\n\n// Tracks if we are in the context of Python or Simulator\nint is_python_context = 0;\n"
  },
  {
    "path": "src/cocotb/share/lib/pygpi/pygpi_priv.hpp",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#ifndef PY_GPI_LOGGING_H\n#define PY_GPI_LOGGING_H\n\n#include <Python.h>\n#include <gpi.h>\n\n#ifdef PYGPI_EXPORTS\n#define PYGPI_EXPORT COCOTB_EXPORT\n#else\n#define PYGPI_EXPORT COCOTB_IMPORT\n#endif\n\nvoid pygpi_logging_initialize();\nvoid pygpi_logging_configure(PyObject *handler, PyObject *get_logger);\nvoid pygpi_logging_finalize();\nvoid pygpi_logging_set_level(enum gpi_log_level level);\n\nextern PyObject *pEventFn;\nextern int pygpi_debug_enabled;\nextern int python_context_tracing_enabled;\nextern int is_python_context;\n\nvoid pygpi_log(enum gpi_log_level level, const char *pathname,\n               const char *funcname, long lineno, const char *fmt, ...);\n\n#define PYGPI_LOG_(level, ...) \\\n    pygpi_log(level, __FILE__, __func__, __LINE__, __VA_ARGS__)\n\n/** Logs a message at TRACE log level if PYGPI tracing is enabled */\n#define PYGPI_LOG_TRACE(...)                    \\\n    do {                                        \\\n        if (pygpi_debug_enabled) {              \\\n            PYGPI_LOG_(GPI_TRACE, __VA_ARGS__); \\\n        }                                       \\\n    } while (0)\n\n/** Logs a message at DEBUG log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define PYGPI_LOG_DEBUG(...) PYGPI_LOG_(GPI_DEBUG, __VA_ARGS__)\n\n/** Logs a message at INFO log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define PYGPI_LOG_INFO(...) PYGPI_LOG_(GPI_INFO, __VA_ARGS__)\n\n/** Logs a message at WARN log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define PYGPI_LOG_WARN(...) PYGPI_LOG_(GPI_WARNING, __VA_ARGS__)\n\n/** Logs a message at ERROR log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define PYGPI_LOG_ERROR(...) PYGPI_LOG_(GPI_ERROR, __VA_ARGS__)\n\n/** Logs a message at CRITICAL log level using the current log handler.\n * Automatically populates arguments using information in the called context.\n */\n#define PYGPI_LOG_CRITICAL(...) PYGPI_LOG_(GPI_CRITICAL, __VA_ARGS__)\n\n// c_to_python and python_to_c are implemented as macros instead of functions so\n// that the logs reference the user's lineno and filename\n\n#define c_to_python()                                                  \\\n    do {                                                               \\\n        if (python_context_tracing_enabled) {                          \\\n            if (is_python_context) {                                   \\\n                PYGPI_LOG_CRITICAL(                                    \\\n                    \"FATAL: Trying C => Python but already in Python \" \\\n                    \"context\");                                        \\\n                exit(1);                                               \\\n            }                                                          \\\n            ++is_python_context;                                       \\\n            PYGPI_LOG_TRACE(\"C => Python\");                            \\\n        }                                                              \\\n    } while (0)\n\n#define python_to_c()                                                      \\\n    do {                                                                   \\\n        if (python_context_tracing_enabled) {                              \\\n            if (!is_python_context) {                                      \\\n                PYGPI_LOG_CRITICAL(                                        \\\n                    \"FATAL: Trying Python => C but already in C context\"); \\\n                exit(1);                                                   \\\n            }                                                              \\\n            --is_python_context;                                           \\\n            PYGPI_LOG_TRACE(\"Python => C\");                                \\\n        }                                                                  \\\n    } while (0)\n\n#endif\n"
  },
  {
    "path": "src/cocotb/share/lib/utils.hpp",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#ifndef COCOTB_UTILS_H_\n#define COCOTB_UTILS_H_\n\n#define xstr(a) str(a)\n#define str(a) #a\n\ntemplate <typename F>\nclass Deferable {\n  public:\n    constexpr Deferable(F f) : f_(f) {};\n    ~Deferable() { f_(); }\n\n  private:\n    F f_;\n};\n\ntemplate <typename F>\nconstexpr Deferable<F> make_deferable(F f) {\n    return Deferable<F>(f);\n}\n\n#define DEFER1(a, b) a##b\n#define DEFER0(a, b) DEFER1(a, b)\n#define DEFER(statement) \\\n    auto DEFER0(_defer, __COUNTER__) = make_deferable([&]() { statement; });\n\n#endif /* COCOTB_UTILS_H_ */\n"
  },
  {
    "path": "src/cocotb/share/lib/verilator/verilator.cpp",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n#include <libgen.h>  // basename\n#include <stdio.h>   // stderr, fprintf\n\n#include <memory>  // std::unique_ptr\n#include <string>  // std::string\n\n#include \"Vtop.h\"\n#include \"verilated.h\"\n#include \"verilated_vpi.h\"\n\n#ifndef VM_TRACE_FST\n// emulate new verilator behavior for legacy versions\n#define VM_TRACE_FST 0\n#endif\n\n#if VM_TRACE\n#if VM_TRACE_FST\n#include <verilated_fst_c.h>\nusing verilated_trace_t = VerilatedFstC;\n#elif VM_TRACE_SAIF\n#include <verilated_saif_c.h>\nusing verilated_trace_t = VerilatedSaifC;\n#else\n// VM_TRACE_VCD\n#include <verilated_vcd_c.h>\nusing verilated_trace_t = VerilatedVcdC;\n#endif\nstatic verilated_trace_t *tfp;\n#endif\n\nstatic vluint64_t main_time = 0;  // Current simulation time\n\ndouble sc_time_stamp() {  // Called by $time in Verilog\n    return main_time;     // converts to double, to match\n                          // what SystemC does\n}\n\nextern \"C\" {\nvoid vlog_startup_routines_bootstrap(void);\n}\n\nstatic inline bool settle_value_callbacks() {\n    bool cbs_called, again;\n\n    // Call Value Change callbacks\n    // These can modify signal values so we loop\n    // until there are no more changes\n    cbs_called = again = VerilatedVpi::callValueCbs();\n    while (again) {\n        again = VerilatedVpi::callValueCbs();\n    }\n\n    return cbs_called;\n}\n\nvoid wrap_up() {\n    VerilatedVpi::callCbs(cbEndOfSimulation);\n\n#if VM_TRACE\n    if (tfp) {\n        delete tfp;\n        tfp = nullptr;\n    }\n#endif\n\n    // VM_COVERAGE is a define which is set if Verilator is\n    // instructed to collect coverage (when compiling the simulation)\n#if VM_COVERAGE\n    VerilatedCov::write();  // Uses +verilator+coverage+file+<filename>,\n                            // defaults to coverage.dat\n#endif\n}\n\nint main(int argc, char **argv) {\n#if VM_TRACE_FST\n    const char *traceFile = \"dump.fst\";\n#elif VM_TRACE_SAIF\n    const char *traceFile = \"dump.saif\";\n#else\n    const char *traceFile = \"dump.vcd\";\n#endif\n    bool traceOn = false;\n    bool traceFlush = false;\n\n    for (int i = 1; i < argc; i++) {\n        std::string arg = std::string(argv[i]);\n        if (arg == \"--trace\") {\n#if VM_TRACE\n            traceOn = true;\n#else\n            fprintf(stderr,\n                    \"Error: --trace requires the design to be built with trace \"\n                    \"support\\n\");\n            return -1;\n#endif\n        } else if (arg == \"--trace-flush\") {\n            traceFlush = true;\n        } else if (arg == \"--trace-file\") {\n            if (++i < argc) {\n                traceFile = argv[i];\n            } else {\n                fprintf(stderr, \"Error: --trace-file requires a parameter\\n\");\n                return -1;\n            }\n        } else if (arg == \"--help\") {\n            fprintf(\n                stderr,\n                \"usage: %s [--trace] [--trace-flush] [--trace-file TRACEFILE]\\n\"\n                \"\\n\"\n                \"cocotb + Verilator sim\\n\"\n                \"\\n\"\n                \"options:\\n\"\n                \"  --trace       Enable tracing (VCD, SAIF or FST)\\n\"\n                \"  --trace-flush Flush trace at each time step (slow)\\n\"\n                \"  --trace-file  Specify the trace file name (%s by \"\n                \"default)\\n\",\n                basename(argv[0]), traceFile);\n            return 0;\n        }\n    }\n\n    Verilated::commandArgs(argc, argv);\n#ifdef VERILATOR_SIM_DEBUG\n    Verilated::debug(99);\n#endif\n    std::unique_ptr<Vtop> top(new Vtop(\"\"));\n    Verilated::fatalOnVpiError(false);  // otherwise it will fail on systemtf\n\n#ifdef VERILATOR_SIM_DEBUG\n    Verilated::internalsDump();\n#endif\n\n#if VM_TRACE\n    Verilated::traceEverOn(true);\n    if (traceOn) {\n        tfp = new verilated_trace_t;\n        top->trace(tfp, 99);\n        tfp->open(traceFile);\n    }\n#endif\n\n    vlog_startup_routines_bootstrap();\n    Verilated::addExitCb([](void *) { wrap_up(); }, nullptr);\n    VerilatedVpi::callCbs(cbStartOfSimulation);\n    settle_value_callbacks();\n\n    while (!Verilated::gotFinish()) {\n        do {\n            // We must evaluate whole design until we process all 'events' for\n            // this time step\n            do {\n                top->eval_step();\n                VerilatedVpi::clearEvalNeeded();\n                VerilatedVpi::doInertialPuts();\n                settle_value_callbacks();\n            } while (VerilatedVpi::evalNeeded());\n\n            // Run ReadWrite callback as we are done processing this eval step\n            VerilatedVpi::callCbs(cbReadWriteSynch);\n            VerilatedVpi::doInertialPuts();\n            settle_value_callbacks();\n        } while (VerilatedVpi::evalNeeded());\n\n        top->eval_end_step();\n\n        // Call ReadOnly callbacks\n        VerilatedVpi::callCbs(cbReadOnlySynch);\n\n#if VM_TRACE\n        if (tfp) {\n            tfp->dump(main_time);\n            if (traceFlush) {\n                tfp->flush();\n            }\n        }\n#endif\n        // cocotb controls the clock inputs using cbAfterDelay so\n        // skip ahead to the next registered callback\n        const vluint64_t NO_TOP_EVENTS_PENDING = static_cast<vluint64_t>(~0ULL);\n        vluint64_t next_time_cocotb = VerilatedVpi::cbNextDeadline();\n        vluint64_t next_time_timing =\n            top->eventsPending() ? top->nextTimeSlot() : NO_TOP_EVENTS_PENDING;\n        vluint64_t next_time = std::min(next_time_cocotb, next_time_timing);\n\n        // If there are no more cbAfterDelay callbacks,\n        // the next deadline is max value, so end the simulation now\n        if (next_time == NO_TOP_EVENTS_PENDING) {\n            break;\n        } else {\n            main_time = next_time;\n        }\n\n        // Call registered NextSimTime\n        // It should be called in simulation cycle before everything else\n        // but not on first cycle\n        VerilatedVpi::callCbs(cbNextSimTime);\n        settle_value_callbacks();\n\n        // Call registered timed callbacks (e.g. clock timer)\n        // These are called at the beginning of the time step\n        // before the iterative regions (IEEE 1800-2012 4.4.1)\n        VerilatedVpi::callTimedCbs();\n        settle_value_callbacks();\n    }\n\n    top->final();\n\n    wrap_up();\n\n    return 0;\n}\n"
  },
  {
    "path": "src/cocotb/simtime.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Tools for dealing with simulated time.\"\"\"\n\nfrom __future__ import annotations\n\nimport sys\nimport warnings\nfrom decimal import Decimal\nfrom fractions import Fraction\nfrom functools import cache\nfrom math import ceil, floor\nfrom typing import Literal, cast, overload\n\nimport cocotb.simulator\n\nif sys.version_info >= (3, 10):\n    from typing import TypeAlias\n\n__all__ = (\n    \"RoundMode\",\n    \"TimeUnit\",\n    \"convert\",\n    \"get_sim_time\",\n    \"time_precision\",\n)\n\nRoundMode: TypeAlias = Literal[\"error\", \"round\", \"ceil\", \"floor\"]\n\"\"\"\nHow to handle non-integral step values when quantizing to simulator time steps.\n\nOne of ``'error'``, ``'round'``, ``'ceil'``, or ``'floor'``.\n\nWhen *round_mode* is ``\"error\"``, a :exc:`ValueError` is thrown if the value cannot\nbe accurately represented in terms of simulator time steps.\nWhen *round_mode* is ``\"round\"``, ``\"ceil\"``, or ``\"floor\"``, the corresponding\nrounding function from the standard library will be used to round to a simulator\ntime step.\n\"\"\"\n\nTimeUnit: TypeAlias = Literal[\"step\", \"fs\", \"ps\", \"ns\", \"us\", \"ms\", \"sec\"]\n\"\"\"Unit of simulated time.\n\nOne of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, or ``'sec'``.\n\n``'step'`` represents a quanta of simulated time,\nas defined by the precision specified in ``timescale`` pragmas in Verilog source code,\nor by :make:var:`COCOTB_HDL_TIMEPRECISION`.\n\"\"\"\n\n\n@overload\ndef convert(\n    value: float | Fraction | Decimal,\n    unit: TimeUnit,\n    *,\n    to: Literal[\"step\"],\n    round_mode: RoundMode = \"error\",\n) -> int: ...\n\n\n@overload\ndef convert(\n    value: float | Fraction | Decimal,\n    unit: TimeUnit,\n    *,\n    to: Literal[\"fs\", \"ps\", \"ns\", \"us\", \"ms\", \"sec\"],\n    round_mode: RoundMode = \"error\",\n) -> float: ...\n\n\ndef convert(\n    value: float | Decimal | Fraction,\n    unit: TimeUnit,\n    *,\n    to: TimeUnit,\n    round_mode: RoundMode = \"error\",\n) -> float:\n    \"\"\"Convert time values from one unit to another unit.\n\n    Args:\n        value: The time value.\n\n        unit: The unit of *value* (one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).\n\n        to: The unit to convert *value* to (one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).\n\n        round_mode:\n            How to handle non-integral step values (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``).\n\n            When *round_mode* is ``\"error\"``, a :exc:`ValueError` is thrown if the value cannot\n            be accurately represented in terms of simulator time steps.\n            When *round_mode* is ``\"round\"``, ``\"ceil\"``, or ``\"floor\"``, the corresponding\n            rounding function from the standard library will be used to round to a simulator\n            time step.\n\n    Returns:\n        The value scaled by the difference in units.\n\n    .. versionadded:: 2.0\n    \"\"\"\n    if unit == \"step\":\n        steps = cast(\"int\", value)\n    else:\n        steps = _get_sim_steps(value, unit, round_mode=round_mode)\n    if to == \"step\":\n        return steps\n    else:\n        return _get_time_from_sim_steps(steps, to)\n\n\n@overload\ndef get_sim_time(unit: Literal[\"step\"] = \"step\", *, units: None = None) -> int: ...\n\n\n@overload\ndef get_sim_time(\n    unit: Literal[\"fs\", \"ps\", \"ns\", \"us\", \"ms\", \"sec\"], *, units: None = None\n) -> float: ...\n\n\ndef get_sim_time(unit: TimeUnit = \"step\", *, units: None = None) -> float:\n    \"\"\"Retrieve the simulation time from the simulator.\n\n    Args:\n        unit: String specifying the unit of the result\n            (one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).\n            ``'step'`` will return the raw simulation time.\n\n            .. versionchanged:: 2.0\n                Passing ``None`` as the *unit* argument was removed, use ``'step'`` instead.\n\n            .. versionchanged:: 2.0\n                Renamed from ``units``.\n\n    Raises:\n        ValueError: If *unit* is not a valid unit.\n\n    Returns:\n        The simulation time in the specified unit.\n\n    .. versionchanged:: 1.6\n        Support ``'step'`` as the the *unit* argument to mean \"simulator time step\".\n\n    .. versionchanged:: 2.0\n        Moved from :mod:`cocotb.utils` to :mod:`cocotb.simtime`.\n    \"\"\"\n    if units is not None:\n        warnings.warn(\n            \"The 'units' argument has been renamed to 'unit'.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        unit = units\n    timeh, timel = cocotb.simulator.get_sim_time()\n    steps = timeh << 32 | timel\n    return _get_time_from_sim_steps(steps, unit) if unit != \"step\" else steps\n\n\n@overload\ndef _ldexp10(frac: float, exp: int) -> float: ...\n\n\n@overload\ndef _ldexp10(frac: Fraction, exp: int) -> Fraction: ...\n\n\n@overload\ndef _ldexp10(frac: Decimal, exp: int) -> Decimal: ...\n\n\ndef _ldexp10(frac: float | Fraction | Decimal, exp: int) -> float | Fraction | Decimal:\n    \"\"\"Like :func:`math.ldexp`, but base 10.\"\"\"\n    # using * or / separately prevents rounding errors if `frac` is a\n    # high-precision type\n    if exp > 0:\n        return frac * (10**exp)\n    else:\n        return frac / (10**-exp)\n\n\ndef _get_time_from_sim_steps(\n    steps: int,\n    unit: TimeUnit,\n) -> float:\n    if unit == \"step\":\n        return steps\n    return _ldexp10(steps, time_precision - _get_log_time_scale(unit))\n\n\ndef _get_sim_steps(\n    time: float | Fraction | Decimal,\n    unit: TimeUnit = \"step\",\n    *,\n    round_mode: RoundMode = \"error\",\n) -> int:\n    result: float | Fraction | Decimal\n    if unit != \"step\":\n        result = _ldexp10(time, _get_log_time_scale(unit) - time_precision)\n    else:\n        result = time\n\n    if round_mode == \"error\":\n        result_rounded = floor(result)\n        if result_rounded != result:\n            raise ValueError(\n                f\"Unable to accurately represent {time}({unit}) with the simulator precision of 1e{time_precision}\"\n            )\n    elif round_mode == \"ceil\":\n        result_rounded = ceil(result)\n    elif round_mode == \"round\":\n        result_rounded = round(result)\n    elif round_mode == \"floor\":\n        result_rounded = floor(result)\n    else:\n        raise ValueError(f\"Invalid round_mode specifier: {round_mode}\")\n\n    return result_rounded\n\n\n@cache\ndef _get_log_time_scale(unit: Literal[\"fs\", \"ps\", \"ns\", \"us\", \"ms\", \"sec\"]) -> int:\n    \"\"\"Retrieve the ``log10()`` of the scale factor for a given time unit.\n\n    Args:\n        unit: String specifying the unit\n            (one of ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).\n\n            .. versionchanged:: 2.0\n                Renamed from ``units``.\n\n    Raises:\n        ValueError: If *unit* is not a valid unit.\n\n    Returns:\n        The ``log10()`` of the scale factor for the time unit.\n    \"\"\"\n    scale = {\"fs\": -15, \"ps\": -12, \"ns\": -9, \"us\": -6, \"ms\": -3, \"sec\": 0}\n\n    unit_lwr = unit.lower()\n    if unit_lwr not in scale:\n        raise ValueError(f\"Invalid unit ({unit}) provided\")\n    else:\n        return scale[unit_lwr]\n\n\ntime_precision: int = _get_log_time_scale(\"fs\")\n\"\"\"The precision of time in the current simulation.\n\nThe value is seconds in powers of tens,\ni.e. ``-15`` is ``10**-15`` seconds or 1 femtosecond.\n\n.. versionadded:: 2.0\n\"\"\"\n\n\ndef _init() -> None:\n    global time_precision\n    time_precision = cocotb.simulator.get_precision()\n"
  },
  {
    "path": "src/cocotb/simulator.pyi",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# generated with mypy's stubgen script\n\nfrom logging import Logger\nfrom typing import Any, Callable\n\nfrom cocotb.handle import GPIDiscovery\n\nDRIVERS: int\nENUM: int\nGENARRAY: int\nINTEGER: int\nLOADS: int\nLOGIC: int\nLOGIC_ARRAY: int\nPACKED_OBJECT: int\nMEMORY: int\nMODULE: int\nNETARRAY: int\nOBJECTS: int\nPACKAGE: int\nREAL: int\nSTRING: int\nSTRUCTURE: int\nPACKED_STRUCTURE: int\nUNKNOWN: int\nRISING: int\nFALLING: int\nVALUE_CHANGE: int\nRANGE_UP: int\nRANGE_DOWN: int\nRANGE_NO_DIR: int\n\nclass sim_callback:\n    def deregister(self) -> None: ...\n    def __eq__(self, other: object) -> bool: ...\n    def __ne__(self, other: object) -> bool: ...\n    def __hash__(self) -> int: ...\n\nclass sim_obj_iterator:\n    def __eq__(self, other: object) -> bool: ...\n    def __ne__(self, other: object) -> bool: ...\n    def __hash__(self) -> int: ...\n    def __iter__(self) -> sim_obj_iterator: ...\n    def __next__(self) -> sim_obj: ...\n\nclass sim_obj:\n    def get_const(self) -> bool: ...\n    def get_definition_file(self) -> str: ...\n    def get_definition_name(self) -> str: ...\n    def get_handle_by_index(self, index: int) -> sim_obj | None: ...\n    def get_handle_by_name(\n        self, name: str, discovery_method: GPIDiscovery | None = GPIDiscovery.AUTO\n    ) -> sim_obj | None: ...\n    def get_indexable(self) -> bool: ...\n    def get_name_string(self) -> str: ...\n    def get_num_elems(self) -> int: ...\n    def get_range(self) -> tuple[int, int, int]: ...\n    def get_signal_val_binstr(self) -> str: ...\n    def get_signal_val_long(self) -> int: ...\n    def get_signal_val_real(self) -> float: ...\n    def get_signal_val_str(self) -> bytes: ...\n    def get_signed(self) -> int: ...\n    def get_type(self) -> int: ...\n    def get_type_string(self) -> str: ...\n    def iterate(self, mode: int) -> sim_obj_iterator: ...\n    def set_signal_val_binstr(self, action: int, value: str) -> None: ...\n    def set_signal_val_int(self, action: int, value: int) -> None: ...\n    def set_signal_val_real(self, action: int, value: float) -> None: ...\n    def set_signal_val_str(self, action: int, value: bytes) -> None: ...\n    def __eq__(self, other: object) -> bool: ...\n    def __ne__(self, other: object) -> bool: ...\n    def __hash__(self) -> int: ...\n\ndef get_precision() -> int: ...\ndef get_root_handle(name: str | None) -> sim_obj | None: ...\ndef get_sim_time() -> tuple[int, int]: ...\ndef get_simulator_product() -> str: ...\ndef get_simulator_version() -> str: ...\ndef get_simulator_args() -> list[str]: ...\ndef is_running() -> bool: ...\ndef set_gpi_log_level(level: int) -> None: ...\ndef package_iterate() -> sim_obj_iterator: ...\ndef register_nextstep_callback(\n    func: Callable[..., Any], *args: Any\n) -> sim_callback: ...\ndef register_readonly_callback(\n    func: Callable[..., Any], *args: Any\n) -> sim_callback: ...\ndef register_rwsynch_callback(func: Callable[..., Any], *args: Any) -> sim_callback: ...\ndef register_timed_callback(\n    time: int, func: Callable[..., Any], *args: Any\n) -> sim_callback: ...\ndef register_value_change_callback(\n    signal: sim_obj, func: Callable[..., Any], edge: int, *args: Any\n) -> sim_callback: ...\ndef stop_simulator() -> None: ...\n\nclass cpp_clock:\n    def start(\n        self, period_steps: int, high_steps: int, start_high: bool, set_action: int\n    ) -> None: ...\n    def stop(self) -> None: ...\n\ndef clock_create(hdl: sim_obj) -> cpp_clock: ...\ndef initialize_logger(\n    log_func: Callable[[Logger, int, str, int, str, str], None],\n    get_logger: Callable[[str], Logger],\n) -> None: ...\ndef set_sim_event_callback(sim_event_callback: Callable[[], object]) -> None: ...\n"
  },
  {
    "path": "src/cocotb/task.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport collections.abc\nimport inspect\nimport logging\nimport sys\nimport traceback\nfrom asyncio import CancelledError, InvalidStateError\nfrom bdb import BdbQuit\nfrom collections.abc import Coroutine, Generator\nfrom enum import auto\nfrom functools import cached_property\nfrom types import CoroutineType, SimpleNamespace\nfrom typing import (\n    Any,\n    Callable,\n    Generic,\n    TypeVar,\n    cast,\n)\n\nimport cocotb\nimport cocotb._event_loop\nfrom cocotb import debug\nfrom cocotb._base_triggers import Trigger, TriggerCallback\nfrom cocotb._bridge import bridge, resume\nfrom cocotb._deprecation import deprecated\nfrom cocotb._utils import DocEnum, extract_coro_stack, remove_traceback_frames\n\nif sys.version_info >= (3, 11):\n    from typing import Self\n\n__all__ = (\n    \"Join\",\n    \"Task\",\n    \"TaskComplete\",\n    \"bridge\",\n    \"current_task\",\n    \"resume\",\n)\n\n# Set __module__ on re-exports\nbridge.__module__ = __name__\nresume.__module__ = __name__\n\n#: Task result type\nResultType = TypeVar(\"ResultType\")\n\n\nclass _TaskState(DocEnum):\n    \"\"\"State of a Task.\"\"\"\n\n    UNSTARTED = (auto(), \"Task created, but never run and not scheduled\")\n    SCHEDULED = (auto(), \"Task queued to run soon\")\n    PENDING = (auto(), \"Task waiting for Trigger to fire\")\n    RUNNING = (auto(), \"Task is currently running\")\n    FINISHED = (auto(), \"Task has finished with a value\")\n    ERRORED = (auto(), \"Task has finished with an Exception\")\n    CANCELLED = (auto(), \"Task was cancelled before it finished\")\n\n\nclass Task(Generic[ResultType]):\n    \"\"\"Concurrently executing task.\n\n    This class is not intended for users to directly instantiate.\n    Use :func:`cocotb.create_task` to create a Task object\n    or :func:`cocotb.start_soon` to create a Task and schedule it to run.\n\n    .. versionchanged:: 1.8\n        Moved to the ``cocotb.task`` module.\n\n    .. versionchanged:: 2.0\n        The ``retval``, ``_finished``, and ``__bool__`` methods were removed.\n        Use :meth:`result`, :meth:`done`, and :meth:`done` methods instead, respectively.\n    \"\"\"\n\n    _id_count = 0  # used by the scheduler for debug\n\n    def __init__(\n        self, inst: Coroutine[Trigger, None, ResultType], *, name: str | None = None\n    ) -> None:\n        self._native_coroutine: bool\n        if inspect.iscoroutine(inst):\n            self._native_coroutine = True\n        elif isinstance(inst, collections.abc.Coroutine):\n            self._native_coroutine = False\n        elif inspect.iscoroutinefunction(inst):\n            raise TypeError(\n                f\"Coroutine function {inst} should be called prior to being scheduled.\"\n            )\n        elif inspect.isasyncgen(inst):\n            raise TypeError(\n                f\"{inst.__qualname__} is an async generator, not a coroutine. \"\n                \"You likely used the yield keyword instead of await.\"\n            )\n        else:\n            raise TypeError(f\"{inst} isn't a valid coroutine!\")\n\n        self._coro = inst\n        self._state: _TaskState = _TaskState.UNSTARTED\n        self._outcome: ResultType | BaseException\n        self._trigger: Trigger\n        self._schedule_callback: cocotb._event_loop.ScheduledCallback\n        self._trigger_callback: TriggerCallback\n        self._done_callbacks: list[Callable[[Task[ResultType]], None]] = []\n        self._must_cancel: int = 0\n        self._locals = SimpleNamespace()\n        self._exc: BaseException | None = None\n\n        self._task_id = self._id_count\n        type(self)._id_count += 1\n        self._name = f\"Task {self._task_id}\" if name is None else name\n\n    @property\n    def locals(self) -> SimpleNamespace:\n        '''Task-local variables.\n\n        A modifiable namespace where any user-defined variables can be added.\n        Use :func:`~cocotb.task.current_task` to access the current Task's locals.\n\n        .. autolink-skip::\n        .. code-block:: python\n\n            def get_rng() -> random.Random:\n                \"\"\"Get the random number generator for the current Task.\"\"\"\n                try:\n                    return current_task().locals.rng\n                except AttributeError:\n                    rng = random.Random()\n                    current_task().locals.rng = rng\n                    return rng\n\n\n            # Use Task-local RNG to drive a signal\n            rng = get_rng()\n            for _ in range(10):\n                await drive(rng.randint(0, 100))\n\n        .. versionadded:: 2.0\n        '''\n        return self._locals\n\n    def get_name(self) -> str:\n        \"\"\"Return the name of the :class:`!Task`.\n\n        If not set using :meth:`set_name` or passed during construction,\n        a reasonable default name is generated.\n        \"\"\"\n        return self._name\n\n    def set_name(self, value: object) -> None:\n        \"\"\"Set the name of the :class:`!Task`.\n\n        Args:\n            value: Any object which can be converted to a :class:`str` to use as the name.\n        \"\"\"\n        if \"_log\" in vars(self):\n            del self._log  # clear cached value\n        self._name = str(value)\n\n    @cached_property\n    def _log(self) -> logging.Logger:\n        return logging.getLogger(f\"cocotb.task.{self._name}\")\n\n    def __str__(self) -> str:\n        # TODO Do we really need this?\n        return f\"<{self._name}>\"\n\n    def _get_coro_stack(self) -> traceback.StackSummary:\n        \"\"\"Get the coroutine callstack of this Task.\n\n        Assumes :attr:`_coro` is a native Python coroutine object.\n\n        Raises:\n            TypeError: If :attr:`_coro` is not a native Python coroutine object.\n        \"\"\"\n        if not self._native_coroutine:\n            raise TypeError(\n                \"Task._get_coro_stack() can only be called on native Python coroutines.\"\n            )\n\n        coro_stack = extract_coro_stack(\n            cast(\"CoroutineType[Trigger, None, ResultType]\", self._coro)\n        )\n\n        # Remove Trigger.__await__() from the stack, as it's not really useful\n        if len(coro_stack) > 0 and coro_stack[-1].name == \"__await__\":\n            coro_stack.pop()\n\n        return coro_stack\n\n    def __repr__(self) -> str:\n        if self._native_coroutine:\n            coro_stack = self._get_coro_stack()\n            try:\n                coro_name = coro_stack[-1].name\n            # coro_stack may be empty if:\n            # - exhausted generator\n            # - finished coroutine\n            except IndexError:\n                try:\n                    coro_name = self._coro.__name__\n                except AttributeError:\n                    coro_name = type(self._coro).__name__\n        else:\n            coro_name = type(self._coro).__name__\n\n        state = self._state\n        if state is _TaskState.RUNNING:\n            return f\"<{self._name} running coro={coro_name}()>\"\n        elif state is _TaskState.FINISHED:\n            return (\n                f\"<{self._name} finished coro={coro_name}() outcome={self._outcome!r}>\"\n            )\n        elif state is _TaskState.ERRORED:\n            return f\"<{self._name} error coro={coro_name}() outcome={self._outcome!r}>\"\n        elif state is _TaskState.PENDING:\n            return (\n                f\"<{self._name} pending coro={coro_name}() trigger={self._trigger!r}>\"\n            )\n        elif state is _TaskState.SCHEDULED:\n            return f\"<{self._name} scheduled coro={coro_name}()>\"\n        elif state is _TaskState.UNSTARTED:\n            return f\"<{self._name} created coro={coro_name}()>\"\n        elif state is _TaskState.CANCELLED:\n            return f\"<{self._name} cancelled coro={coro_name} with={self._outcome!r}\"\n        else:\n            raise RuntimeError(\"Task in unknown state\")\n\n    def _ensure_started(self) -> None:\n        state = self._state\n        if state is _TaskState.UNSTARTED:\n            if debug.debug:\n                self._log.debug(\"Starting %r\", self)\n            self._schedule_resume()\n        elif state in (\n            _TaskState.FINISHED,\n            _TaskState.ERRORED,\n            _TaskState.CANCELLED,\n        ):\n            raise RuntimeError(\"Cannot start a finished Task\")\n        # RUNNING, SCHEDULED, PENDING are already running\n\n    def _set_outcome(\n        self,\n        result: ResultType | BaseException,\n        state: _TaskState,\n    ) -> None:\n        self._outcome = result\n        self._state = state\n\n        # Run done callbacks.\n        for callback in self._done_callbacks:\n            callback(self)\n\n        # Wake up waiting Tasks.\n        self.complete._react()\n        self._join._react()\n\n    def _schedule_resume(self, exc: BaseException | None = None) -> None:\n        self._state = _TaskState.SCHEDULED\n        self._exc = exc\n        self._schedule_callback = cocotb._event_loop._inst.schedule(self._resume)\n\n    def _resume(self) -> None:\n        \"\"\"Resume execution of the Task.\n\n        Runs until the coroutine ends, raises, or yields a Trigger.\n        Can optionally throw an Exception into the Task.\n\n        Args:\n            exc: :exc:`BaseException` to throw into the coroutine or nothing.\n\n        Returns:\n            The object yielded from the coroutine or ``None`` if coroutine finished.\n        \"\"\"\n        if debug.debug:\n            self._log.debug(\"Resuming %r\", self)\n\n        self._state = _TaskState.RUNNING\n\n        # Set this Task and the current. Unset in finally block.\n        global _current_task\n        _current_task = self\n\n        try:\n            if self._exc is None:\n                trigger = self._coro.send(None)\n            else:\n                trigger = self._coro.throw(self._exc)\n        except StopIteration as e:\n            if self._must_cancel:\n                if debug.debug:\n                    self._log.debug(\"Task %r was cancelled but exited normally\", self)\n                self._set_outcome(\n                    RuntimeError(\n                        \"Task was cancelled, but exited normally. Did you forget to re-raise the CancelledError?\"\n                    ),\n                    _TaskState.ERRORED,\n                )\n            else:\n                if debug.debug:\n                    self._log.debug(\n                        \"Task %r finished with value of type %r\", self, type(e.value)\n                    )\n                self._set_outcome(e.value, _TaskState.FINISHED)\n        except (KeyboardInterrupt, SystemExit, BdbQuit) as e:\n            # Allow these to bubble up to the execution root to fail the sim immediately.\n            # This follows asyncio's behavior.\n            if debug.debug:\n                self._log.debug(\n                    \"Task %r errored with exception of type %r\", self, type(e)\n                )\n            self._set_outcome(\n                remove_traceback_frames(e, [\"_resume\"]), _TaskState.ERRORED\n            )\n            raise\n        except CancelledError as e:\n            if debug.debug:\n                # Print the message only if it exists\n                reason = str(e)\n                msg = \"Task %r was cancelled\"\n                if reason:\n                    msg += f\": {reason}\"\n                self._log.debug(msg, self)\n            self._set_outcome(\n                remove_traceback_frames(e, [\"_resume\"]), _TaskState.CANCELLED\n            )\n        except BaseException as e:\n            if debug.debug:\n                self._log.debug(\n                    \"Task %r errored with exception of type %r\", self, type(e)\n                )\n            self._set_outcome(\n                remove_traceback_frames(e, [\"_resume\"]), _TaskState.ERRORED\n            )\n        else:\n            if self._must_cancel:\n                if debug.debug:\n                    self._log.debug(\"Task %r was cancelled but continued running\", self)\n                self._set_outcome(\n                    RuntimeError(\n                        \"Task was cancelled, but continued running. Did you forget to re-raise the CancelledError?\"\n                    ),\n                    _TaskState.ERRORED,\n                )\n            elif not isinstance(trigger, Trigger):\n                if debug.debug:\n                    self._log.debug(\n                        \"Task %r yielded non-Trigger of type: %r\", self, type(trigger)\n                    )\n                self._schedule_resume(\n                    TypeError(\n                        f\"Coroutine yielded object of type {type(trigger)!r}, which the scheduler can't handle.\"\n                    )\n                )\n            else:\n                self._state = _TaskState.PENDING\n                self._trigger = trigger\n                # `trigger._register()`` calls `trigger._prime()` and `trigger._prime()`\n                # can call `trigger._react()`, which can immediately schedule this task.\n                # So setting the state to PENDING *must* be done *before* calling\n                # `_register()` so the possible call to `_react()` can override the\n                # state correctly.\n                # TODO Don't allow `_prime()` to call `_react()`?\n                try:\n                    self._trigger_callback = trigger._register(self._schedule_resume)\n                except Exception as e:\n                    self._schedule_resume(remove_traceback_frames(e, [\"_resume\"]))\n                else:\n                    if debug.debug:\n                        self._log.debug(\"Pending %r on %r\", self, trigger)\n\n        finally:\n            _current_task = None\n\n    @deprecated(\"`task.kill()` is deprecated in favor of `task.cancel()`\")\n    def kill(self) -> None:\n        \"\"\"Kill a coroutine.\"\"\"\n\n        state = self._state\n        if state is _TaskState.PENDING:\n            # Unprime triggers if pending.\n            self._trigger_callback.cancel()\n        elif state is _TaskState.SCHEDULED:\n            # Unschedule if scheduled.\n            self._schedule_callback.cancel()\n        elif state is _TaskState.UNSTARTED:\n            pass\n        elif state is _TaskState.RUNNING:\n            raise RuntimeError(\"Can't kill currently running Task\")\n        else:\n            return\n\n        # The coroutine may have never been started (happens in UNSTARTED or SCHEDULED state)\n        # and this will cause a ResourceWarning if the coroutine is not manually closed.\n        # This is only an issue because kill() does not run the coroutine after it's killed.\n        if (\n            self._native_coroutine\n            and inspect.getcoroutinestate(self._coro) == \"CORO_CREATED\"\n        ):\n            self._coro.close()\n\n        if debug.debug:\n            self._log.debug(\"Killed %r\", self)\n        self._set_outcome(\n            None,  # type: ignore  # `kill()` sets the result to None regardless of the ResultType\n            _TaskState.FINISHED,\n        )\n\n    @cached_property\n    def complete(self) -> TaskComplete[ResultType]:\n        r\"\"\"Trigger which fires when the Task completes.\n\n        Unlike :meth:`join`, this Trigger does not return the result of the Task when :keyword:`await`\\ ed.\n\n        .. code-block:: python\n\n            async def coro_inner():\n                await Timer(1, unit=\"ns\")\n                raise ValueError(\"Oops\")\n\n\n            task = cocotb.start_soon(coro_inner())\n            await task.complete  # no exception raised here\n            assert task.exception() == ValueError(\"Oops\")\n        \"\"\"\n        return TaskComplete._make(self)\n\n    @deprecated(\n        \"Using `task` directly is preferred to `task.join()` in all situations where the latter could be used.\"\n    )\n    def join(self) -> Join[ResultType]:\n        r\"\"\"Block until the Task completes and return the result.\n\n        Equivalent to calling :class:`Join(self) <cocotb.task.Join>`.\n\n        .. code-block:: python\n\n            async def coro_inner():\n                await Timer(1, unit=\"ns\")\n                return \"Hello world\"\n\n\n            task = cocotb.start_soon(coro_inner())\n            result = await task.join()\n            assert result == \"Hello world\"\n\n        Returns:\n            Object that can be :keyword:`await`\\ ed or passed into :class:`~cocotb.triggers.First` or :class:`~cocotb.triggers.Combine`;\n            the result of which will be the result of the Task.\n\n        .. deprecated:: 2.0\n            Using ``task`` directly is preferred to ``task.join()`` in all situations where the latter could be used.\n        \"\"\"\n        return self._join\n\n    @cached_property\n    def _join(self) -> Join[ResultType]:\n        return Join._make(self)\n\n    def cancel(self, msg: str | None = None) -> bool:\n        \"\"\"Cancel a Task's further execution.\n\n        When a Task is cancelled, a :exc:`asyncio.CancelledError` is thrown into the Task.\n\n        Returns: ``True`` if the Task was cancelled; ``False`` otherwise.\n        \"\"\"\n        state = self._state\n        if state in (\n            _TaskState.FINISHED,\n            _TaskState.ERRORED,\n            _TaskState.CANCELLED,\n        ):\n            return False\n        elif state is _TaskState.RUNNING:\n            raise RuntimeError(\"Can't cancel() currently running Task\")\n\n        # Set state to do cancel\n        if msg is None:\n            cancelled_error = CancelledError()\n        else:\n            cancelled_error = CancelledError(msg)\n\n        if debug.debug:\n            self._log.debug(\"Cancelling %r\", self)\n\n        if state is _TaskState.PENDING:\n            # Unprime triggers if pending.\n            self._trigger_callback.cancel()\n            self._schedule_resume(cancelled_error)\n        elif state is _TaskState.SCHEDULED:\n            # hijack scheduled callback if scheduled.\n            self._exc = cancelled_error\n        else:  # UNSTARTED\n            # Schedule anyways, the error will come out when calling coro.throw() on an\n            # unstarted coroutine and this will prevent ResourceWarnings from un-awaited\n            # coroutines.\n            self._schedule_resume(cancelled_error)\n\n        self._must_cancel += 1\n\n        return True\n\n    def _cancel_now(self, msg: str | None = None) -> bool:\n        \"\"\"Like cancel(), but throws CancelledError into the Task and puts it into a \"done\" state immediately.\n\n        Not safe to be called from a running Task.\n        Only from done callbacks or scheduler or Task internals.\n        \"\"\"\n        state = self._state\n        if state is _TaskState.PENDING:\n            # Unprime triggers if pending.\n            self._trigger_callback.cancel()\n        elif state is _TaskState.SCHEDULED:\n            # Unschedule if scheduled.\n            self._schedule_callback.cancel()\n        elif state is _TaskState.UNSTARTED:\n            # Resume anyways, the error will come out when calling coro.throw() on an\n            # unstarted coroutine and this will prevent ResourceWarnings from un-awaited\n            # coroutines.\n            pass\n        elif state is _TaskState.RUNNING:\n            raise RuntimeError(\"Can't _cancel_now() currently running Task\")\n        else:  # FINISHED, ERRORED, CANCELLED\n            return False\n\n        # Set state to do cancel\n        if msg is None:\n            cancelled_error = CancelledError()\n        else:\n            cancelled_error = CancelledError(msg)\n        self._must_cancel += 1\n\n        # Throw CancelledError now\n        self._exc = cancelled_error\n        self._resume()\n\n        return True\n\n    def _uncancel(self) -> None:\n        \"\"\"Prevents :exc:`RuntimeError` from occurring when cancelled Tasks suppress :exc:`asyncio.CancelledError`.\n\n        Currently only useful for :class:`.TaskManager`.\n        \"\"\"\n        if self._must_cancel > 0:\n            self._must_cancel -= 1\n\n    def cancelled(self) -> bool:\n        \"\"\"Return ``True`` if the Task was cancelled.\"\"\"\n        return self._state is _TaskState.CANCELLED\n\n    def done(self) -> bool:\n        \"\"\"Return ``True`` if the Task has finished executing.\"\"\"\n        return self._state in (\n            _TaskState.FINISHED,\n            _TaskState.ERRORED,\n            _TaskState.CANCELLED,\n        )\n\n    def result(self) -> ResultType:\n        \"\"\"Return the result of the Task.\n\n        If the Task ran to completion, the result is returned.\n        If the Task failed with an exception, the exception is re-raised.\n        If the Task was cancelled, the :exc:`asyncio.CancelledError` is re-raised.\n        If the coroutine is not yet complete, an :exc:`asyncio.InvalidStateError` is raised.\n        \"\"\"\n        state = self._state\n        if state is _TaskState.CANCELLED:\n            raise cast(\"CancelledError\", self._outcome)\n        elif state is _TaskState.FINISHED:\n            return cast(\"ResultType\", self._outcome)\n        elif state is _TaskState.ERRORED:\n            raise cast(\"BaseException\", self._outcome)\n        else:\n            raise InvalidStateError(\"result is not yet available\")\n\n    def exception(self) -> BaseException | None:\n        \"\"\"Return the exception of the Task.\n\n        If the Task ran to completion, ``None`` is returned.\n        If the Task failed with an exception, the exception is returned.\n        If the Task was cancelled, the :exc:`asyncio.CancelledError` is re-raised.\n        If the coroutine is not yet complete, an :exc:`asyncio.InvalidStateError` is raised.\n        \"\"\"\n        state = self._state\n        if state is _TaskState.CANCELLED:\n            raise cast(\"CancelledError\", self._outcome)\n        elif state is _TaskState.FINISHED:\n            return None\n        elif state is _TaskState.ERRORED:\n            return cast(\"BaseException\", self._outcome)\n        else:\n            raise InvalidStateError(\"result is not yet available\")\n\n    def _add_done_callback(self, callback: Callable[[Task[ResultType]], None]) -> None:\n        \"\"\"Add *callback* to the list of callbacks to be run once the Task becomes \"done\".\n\n        Args:\n            callback: The callback to run once \"done\".\n\n        .. note::\n            If the task is already done, calling this function will call the callback immediately.\n        \"\"\"\n        if self.done():\n            callback(self)\n        self._done_callbacks.append(callback)\n\n    def __await__(self) -> Generator[Trigger, None, ResultType]:\n        if not self.done():\n            self._ensure_started()\n            yield self.complete\n        return self.result()\n\n\n_current_task: Task[Any] | None = None\n\n\ndef current_task() -> Task[object]:\n    \"\"\"Return the currently running Task.\n\n    Raises:\n        RuntimeError: If no Task is running.\n    \"\"\"\n    if _current_task is None:\n        raise RuntimeError(\"No currently running Task\")\n    return _current_task\n\n\nclass TaskComplete(Trigger, Generic[ResultType]):\n    r\"\"\"Fires when a :class:`~cocotb.task.Task` completes.\n\n    Unlike :class:`~cocotb.task.Join`, this Trigger does not return the result of the Task when :keyword:`await`\\ ed.\n    See :attr:`.Task.complete` for more information.\n\n    .. warning::\n        This class cannot be instantiated in the normal way.\n        You must use :attr:`.Task.complete`.\n\n    .. versionadded:: 2.0\n    \"\"\"\n\n    _task: Task[ResultType]\n\n    def __new__(cls, task: Task[ResultType]) -> TaskComplete[ResultType]:\n        raise NotImplementedError(\n            \"TaskComplete cannot be instantiated in this way. Use the `task.complete` attribute.\"\n        )\n\n    @classmethod\n    def _make(cls, task: Task[ResultType]) -> Self:\n        self = super().__new__(cls)\n        super().__init__(self)\n        self._task = task\n        return self\n\n    def _prime(self) -> None:\n        if self._task.done():\n            self._react()\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}({self._task!s})\"\n\n    @property\n    def task(self) -> Task[ResultType]:\n        \"\"\"The :class:`.Task` associated with this completion event.\"\"\"\n        return self._task\n\n\nclass Join(TaskComplete[ResultType]):\n    r\"\"\"Fires when a :class:`~cocotb.task.Task` completes and returns the Task's result.\n\n    Equivalent to calling :meth:`task.join() <cocotb.task.Task.join>`.\n\n    .. code-block:: python\n\n        async def coro_inner():\n            await Timer(1, unit=\"ns\")\n            return \"Hello world\"\n\n\n        task = cocotb.start_soon(coro_inner())\n        result = await Join(task)\n        assert result == \"Hello world\"\n\n    Args:\n        task: The Task upon which to wait for completion.\n\n    Returns:\n        Object that can be :keyword:`await`\\ ed or passed into :class:`~cocotb.triggers.First` or :class:`~cocotb.triggers.Combine`;\n        the result of which will be the result of the Task.\n\n    .. deprecated:: 2.0\n        Using ``task`` directly is preferred to ``Join(task)`` in all situations where the latter could be used.\n    \"\"\"\n\n    @deprecated(\n        \"Using `task` directly is preferred to `Join(task)` in all situations where the latter could be used.\"\n    )\n    def __new__(cls, task: Task[ResultType]) -> Join[ResultType]:\n        return task._join\n\n    def __init__(self, task: Task[ResultType]) -> None:\n        pass\n\n    def __await__(self) -> Generator[Self, None, ResultType]:  # type: ignore[override]\n        yield self\n        return self._task.result()\n"
  },
  {
    "path": "src/cocotb/triggers.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport warnings\n\nfrom cocotb._base_triggers import Event, Lock, NullTrigger, Trigger\nfrom cocotb._concurrent_waiters import gather, select, wait\nfrom cocotb._extended_awaitables import (\n    ClockCycles,\n    Combine,\n    First,\n    SimTimeoutError,\n    Waitable,\n    with_timeout,\n)\nfrom cocotb._gpi_triggers import (\n    Edge,\n    FallingEdge,\n    GPITrigger,\n    NextTimeStep,\n    ReadOnly,\n    ReadWrite,\n    RisingEdge,\n    Timer,\n    ValueChange,\n    current_gpi_trigger,\n)\nfrom cocotb._task_manager import TaskManager\n\n__all__ = (\n    \"ClockCycles\",\n    \"Combine\",\n    \"Edge\",\n    \"Event\",\n    \"FallingEdge\",\n    \"First\",\n    \"GPITrigger\",\n    \"Lock\",\n    \"NextTimeStep\",\n    \"NullTrigger\",\n    \"ReadOnly\",\n    \"ReadWrite\",\n    \"RisingEdge\",\n    \"SimTimeoutError\",\n    \"TaskManager\",\n    \"Timer\",\n    \"Trigger\",\n    \"ValueChange\",\n    \"Waitable\",\n    \"current_gpi_trigger\",\n    \"gather\",\n    \"select\",\n    \"wait\",\n    \"with_timeout\",\n)\n\n# Set __module__ on re-exports\nfor name in __all__:\n    obj = globals()[name]\n    obj.__module__ = __name__\n\n\ndef __getattr__(name: str) -> object:\n    if name == \"Join\":\n        warnings.warn(\n            \"Join has been moved to `cocotb.task`.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        from cocotb.task import Join  # noqa: PLC0415\n\n        return Join\n    raise AttributeError(f\"module {__name__!r} has no attribute {name!r}\")\n"
  },
  {
    "path": "src/cocotb/types/__init__.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom ._abstract_array import AbstractArray, AbstractMutableArray\nfrom ._array import Array\nfrom ._indexing import IndexingChangedWarning\nfrom ._logic import Bit, Logic\nfrom ._logic_array import LogicArray\nfrom ._range import Range\n\n__all__ = (\n    \"AbstractArray\",\n    \"AbstractMutableArray\",\n    \"Array\",\n    \"Bit\",\n    \"IndexingChangedWarning\",\n    \"Logic\",\n    \"LogicArray\",\n    \"Range\",\n)\n\n# Set __module__ on re-exports\nfor name in __all__:\n    obj = globals()[name]\n    obj.__module__ = __name__\n"
  },
  {
    "path": "src/cocotb/types/_abstract_array.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom abc import abstractmethod\nfrom collections.abc import Iterable, Iterator\nfrom typing import Generic, TypeVar, overload\n\nfrom cocotb.types._range import Range\n\nT_co = TypeVar(\"T_co\", covariant=True)\nT = TypeVar(\"T\")\n\n\nclass AbstractArray(Generic[T_co]):\n    r\"\"\"Abstract base class for non-mutating Array-like collections.\n\n    Arrays are similar to :class:`~collections.abc.Sequence`\\ s,\n    but their size cannot change after creation and they support arbitrary indexing schemes.\n\n    Abstract methods\n    ^^^^^^^^^^^^^^^^\n\n    * :attr:`range`\n    * :meth:`!__getitem__`\n\n    Mixin methods\n    ^^^^^^^^^^^^^\n\n    * :attr:`left`, :attr:`right`, and :attr:`direction`\n    * :meth:`!__len__`\n    * :meth:`!__iter__` and :meth:`!__reversed__`\n    * :meth:`!__contains__`\n    * :meth:`index` and :meth:`count`\n    \"\"\"\n\n    @property\n    def left(self) -> int:\n        \"\"\"Leftmost index of the array.\"\"\"\n        return self.range.left\n\n    @property\n    def direction(self) -> str:\n        \"\"\"``\"to\"`` if indexes are ascending, ``\"downto\"`` otherwise.\"\"\"\n        return self.range.direction\n\n    @property\n    def right(self) -> int:\n        \"\"\"Rightmost index of the array.\"\"\"\n        return self.range.right\n\n    @property\n    @abstractmethod\n    def range(self) -> Range:\n        \"\"\":class:`Range` of the indexes of the array.\"\"\"\n\n    @range.setter\n    @abstractmethod\n    def range(self, new_range: Range) -> None:\n        \"\"\"Set a new indexing scheme on the array.\n\n        Must be the same size.\n        \"\"\"\n\n    def __len__(self) -> int:\n        return len(self.range)\n\n    def __iter__(self) -> Iterator[T_co]:\n        for i in self.range:\n            yield self[i]\n\n    def __reversed__(self) -> Iterator[T_co]:\n        for i in reversed(self.range):\n            yield self[i]\n\n    def __contains__(self, item: object) -> bool:\n        return any(v == item for v in self)\n\n    @overload\n    def __getitem__(self, item: int) -> T_co: ...\n\n    @overload\n    def __getitem__(self, item: slice) -> AbstractArray[T_co]: ...\n\n    @abstractmethod\n    def __getitem__(self, item: int | slice) -> T_co | AbstractArray[T_co]: ...\n\n    def index(\n        self,\n        value: object,\n        start: int | None = None,\n        stop: int | None = None,\n    ) -> int:\n        \"\"\"Find first occurrence of value.\n\n        Args:\n            value: Value to search for.\n            start: Index to start search at.\n            stop: Index to stop search at.\n\n        Returns:\n            Index of first occurrence of *value*.\n\n        Raises:\n            ValueError: If the value is not present.\n        \"\"\"\n        if start is None:\n            start = self.left\n        if stop is None:\n            stop = self.right\n        for i in Range(start, self.direction, stop):\n            if self[i] == value:\n                return i\n        raise ValueError(f\"{value!r} not in array\")\n\n    def count(self, value: object) -> int:\n        \"\"\"Return number of occurrences of value.\n\n        Args:\n            value: Value to search for.\n\n        Returns:\n            Number of occurrences of *value*.\n        \"\"\"\n        count: int = 0\n        for v in self:\n            if v == value:\n                count += 1\n        return count\n\n\nclass AbstractMutableArray(AbstractArray[T]):\n    \"\"\"Abstract base class for mutating Array-like collections.\n\n    See :class:`.AbstractArray` for more details.\n\n    Additional abstract methods:\n\n    * :meth:`!__setitem__`\n    \"\"\"\n\n    @overload\n    def __setitem__(self, item: int, value: T) -> None: ...\n\n    @overload\n    def __setitem__(self, item: slice, value: Iterable[T]) -> None: ...\n\n    @abstractmethod\n    def __setitem__(self, item: int | slice, value: T | Iterable[T]) -> None: ...\n"
  },
  {
    "path": "src/cocotb/types/_array.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport copy\nimport warnings\nfrom collections.abc import Iterable, Iterator\nfrom typing import Any, TypeVar, cast, overload\n\nfrom cocotb.types._abstract_array import AbstractMutableArray\nfrom cocotb.types._indexing import IndexingChangedWarning\nfrom cocotb.types._range import Range\n\nT = TypeVar(\"T\")\n\n\nclass Array(AbstractMutableArray[T]):\n    r\"\"\"Fixed-size, arbitrarily-indexed, homogeneous collection type.\n\n    Arrays are similar to, but different from Python :class:`list`\\ s.\n    An array can store values of any type or values of multiple types at a time, just like a :class:`!list`.\n    Array constructor values can be any Iterable.\n\n    .. code-block:: pycon3\n\n        >>> Array([1, False, \"example\", None])\n        Array([1, False, 'example', None], Range(0, 'to', 3))\n\n        >>> Array(\"Hello!\")\n        Array(['H', 'e', 'l', 'l', 'o', '!'], Range(0, 'to', 5))\n\n    Unlike :class:`!list`\\ s, an array's size cannot change.\n    This means they do not support methods like :meth:`~list.append` or :meth:`~list.insert`.\n\n    The indexes of an Array can start or end at any integer value, they are not limited to 0-based indexing.\n    Indexing schemes are selected using :class:`Range` objects.\n    If *range* is not given, the range ``Range(0, \"to\", len(value)-1)`` is used.\n    If an :class:`int` is passed for *range*, the range ``Range(0, \"to\", range-1)`` is used.\n\n    .. code-block:: pycon3\n\n        >>> a = Array([0, 1, 2, 3], Range(-1, \"downto\", -4))\n        >>> a[-1]\n        0\n        >>> a[-4]\n        3\n\n    Arrays can also have 0 length using \"null\" :class:`Range`\\ s.\n\n    .. code-block:: pycon3\n\n        >>> Array([], Range(1, \"to\", 0))  # 1 to 0 is a null Range\n        Array([], Range(1, 'to', 0))\n\n    Indexing and slicing is very similar to :class:`!list`\\ s, but it uses the indexing scheme specified with the *range*.\n    Unlike :class:`!list`, slicing uses an inclusive right bound, which is common in HDLs.\n    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.\n    Slicing an Array returns a new :class:`~cocotb.types.Array` object, whose bounds are the slice indexes.\n\n    .. code-block:: pycon3\n\n        >>> a = Array(\"1234abcd\")\n        >>> a[7]\n        'd'\n        >>> a[2:5]\n        Array(['3', '4', 'a', 'b'], Range(2, 'to', 5))\n        >>> a[2:5] = reversed(a[2:5])\n        >>> \"\".join(a)\n        '12ba43cd'\n\n        >>> b = Array(\"1234\", Range(0, -3))\n        >>> b[-2]\n        '3'\n        >>> b[-1:]\n        Array(['2', '3', '4'], Range(-1, 'downto', -3))\n        >>> b[:] = reversed(b)\n        >>> b\n        Array(['4', '3', '2', '1'], Range(0, 'downto', -3))\n\n    .. warning::\n        Arrays behave differently in certain situations than Python's built-in sequence types (:class:`list`, :class:`tuple`, etc.).\n\n        - Arrays are not necessarily 0-based and slices use inclusive right bounds,\n          so many functions that work on Python sequences by index (like :mod:`bisect`) may not work on arrays.\n        - Slice indexes must be specified in the same direction as the array and do not support specifying a \"step\".\n        - When setting a slice, the new value must be an iterable of the same size as the slice.\n        - Negative indexes are *not* treated as an offset from the end of the array, but are treated literally.\n\n    Arrays are equal to other arrays of the same length with the same values (structural equality).\n    Bounds do not matter for equality.\n\n    .. code-block:: pycon3\n\n        >>> a = Array([1, 1, 2, 3, 5], Range(4, \"downto\", 0))\n        >>> b = Array([1, 1, 2, 3, 5], Range(-2, \"to\", 2))\n        >>> a == b\n        True\n\n    You can change the bounds of an array by setting the :attr:`range` to a new value.\n    The new bounds must be the same length of the array.\n\n    .. code-block:: pycon3\n\n        >>> a = Array(\"1234\")\n        >>> a.range\n        Range(0, 'to', 3)\n        >>> a.range = Range(3, \"downto\", 0)\n        >>> a.range\n        Range(3, 'downto', 0)\n\n    Arrays support many of the methods and semantics defined by :class:`collections.abc.Sequence`.\n\n    .. code-block:: pycon3\n\n        >>> a = Array(\"stuff\", Range(2, \"downto\", -2))\n        >>> len(a)\n        5\n        >>> \"t\" in a\n        True\n        >>> a.index(\"u\")\n        0\n        >>> for c in a:\n        ...     print(c)\n        s\n        t\n        u\n        f\n        f\n\n    Args:\n        value: Initial value for the Array.\n        range: The indexing scheme of the Array.\n\n    Raises:\n        ValueError: When argument values cannot be used to construct an Array.\n        TypeError: When invalid argument types are used.\n    \"\"\"\n\n    __slots__ = (\"_value\", \"_range\", \"_warn_indexing\")\n\n    def __init__(self, value: Iterable[T], range: Range | int | None = None) -> None:\n        self._warn_indexing = False\n        self._value = list(value)\n        if range is None:\n            self._range = Range(0, \"to\", len(self._value) - 1)\n        else:\n            if isinstance(range, int):\n                self._range = Range(0, \"to\", range - 1)\n            elif isinstance(range, Range):\n                self._range = range\n            else:\n                raise TypeError(\n                    f\"Expected Range or int for parameter 'range', not {type(range).__qualname__}\"\n                )\n\n            if len(self._value) != len(self._range):\n                raise ValueError(\n                    f\"Value of length {len(self._value)!r} does not fit in {self._range!r}\"\n                )\n\n    @classmethod\n    def _from_handle(\n        cls, value: list[T], range: Range, warn_indexing: bool\n    ) -> Array[T]:\n        self = cls.__new__(cls)\n        self._warn_indexing = warn_indexing\n        self._value = value\n        self._range = range\n        return self\n\n    @property\n    def range(self) -> Range:\n        \"\"\":class:`Range` of the indexes of the array.\"\"\"\n        return self._range\n\n    @range.setter\n    def range(self, new_range: Range) -> None:\n        \"\"\"Sets a new indexing scheme on the array, must be the same size\"\"\"\n        if not isinstance(new_range, Range):\n            raise TypeError(\"range argument must be of type 'Range'\")\n        if len(new_range) != len(self):\n            raise ValueError(\n                f\"{new_range!r} not the same length as old range ({self._range!r}).\"\n            )\n        self._range = new_range\n\n    def __iter__(self) -> Iterator[T]:\n        return iter(self._value)\n\n    def __reversed__(self) -> Iterator[T]:\n        return reversed(self._value)\n\n    def __contains__(self, item: object) -> bool:\n        return item in self._value\n\n    def __eq__(self, other: object) -> bool:\n        if isinstance(other, Array):\n            return self._value == other._value\n        elif isinstance(other, list):\n            return self._value == other\n        elif isinstance(other, tuple):\n            return tuple(self._value) == other\n        else:\n            return NotImplemented\n\n    @overload\n    def __getitem__(self, item: int) -> T: ...\n\n    @overload\n    def __getitem__(self, item: slice) -> Array[T]: ...\n\n    def __getitem__(self, item: int | slice) -> T | Array[T]:\n        if isinstance(item, int):\n            if self._warn_indexing:\n                warnings.warn(\n                    f\"Update index {item} to {self.range[item]}\",\n                    IndexingChangedWarning,\n                    stacklevel=2,\n                )\n            idx = self._translate_index(item)\n            return self._value[idx]\n        elif isinstance(item, slice):\n            if self._warn_indexing:\n                start = item.start if item.start is not None else 0\n                stop = item.stop if item.stop is not None else len(self) - 1\n                warnings.warn(\n                    f\"Update slice {start}:{stop} to {self.range[start]}:{self.range[stop]}\",\n                    IndexingChangedWarning,\n                    stacklevel=2,\n                )\n            start = item.start if item.start is not None else self.left\n            stop = item.stop if item.stop is not None else self.right\n            if item.step is not None:\n                raise IndexError(\"do not specify step\")\n            start_i = self._translate_index(start)\n            stop_i = self._translate_index(stop)\n            if start_i > stop_i:\n                raise IndexError(\n                    f\"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]\"\n                )\n            value = self._value[start_i : stop_i + 1]\n            range = Range(start, self.direction, stop)\n            return Array(value=value, range=range)\n        raise TypeError(f\"indexes must be ints or slices, not {type(item).__name__}\")\n\n    @overload\n    def __setitem__(self, item: int, value: T) -> None: ...\n\n    @overload\n    def __setitem__(self, item: slice, value: Iterable[T]) -> None: ...\n\n    def __setitem__(self, item: int | slice, value: T | Iterable[T]) -> None:\n        if isinstance(item, int):\n            idx = self._translate_index(item)\n            self._value[idx] = cast(\"T\", value)\n        elif isinstance(item, slice):\n            start = item.start if item.start is not None else self.left\n            stop = item.stop if item.stop is not None else self.right\n            if item.step is not None:\n                raise IndexError(\"do not specify step\")\n            start_i = self._translate_index(start)\n            stop_i = self._translate_index(stop)\n            if start_i > stop_i:\n                raise IndexError(\n                    f\"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]\"\n                )\n            value = list(cast(\"Iterable[T]\", value))\n            if len(value) != (stop_i - start_i + 1):\n                raise ValueError(\n                    f\"value of length {len(value)!r} will not fit in slice [{start}:{stop}]\"\n                )\n            self._value[start_i : stop_i + 1] = value\n        else:\n            raise TypeError(\n                f\"indexes must be ints or slices, not {type(item).__name__}\"\n            )\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__name__}({self._value!r}, {self._range!r})\"\n\n    def _translate_index(self, item: int) -> int:\n        try:\n            return self._range.index(item)\n        except ValueError:\n            raise IndexError(f\"index {item} out of range\") from None\n\n    def __copy__(self) -> Array:\n        return Array(self._value, self._range)\n\n    def __deepcopy__(self, memo: dict[int, Any]) -> Array:\n        res = Array.__new__(Array)\n        res._value = copy.deepcopy(self._value, memo=memo)\n        res._range = copy.deepcopy(self._range, memo=memo)\n        res._warn_indexing = self._warn_indexing\n        return res\n"
  },
  {
    "path": "src/cocotb/types/_indexing.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom cocotb.types._range import Range\nfrom cocotb_tools import _env\n\ndo_indexing_changed_warning: bool = _env.as_bool(\"COCOTB_INDEXING_CHANGED_WARNING\")\n\n\ndef indexing_changed(range: Range) -> bool:\n    return not (range.left == 0 and range.direction == \"to\")\n\n\nclass IndexingChangedWarning(UserWarning):\n    \"\"\"Warning issued when a value is indexed in a way that is different between cocotb 1.x and 2.x.\"\"\"\n"
  },
  {
    "path": "src/cocotb/types/_logic.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport sys\nfrom functools import cache\nfrom typing import Union\n\nfrom cocotb.types._resolve import RESOLVE_X, ResolverLiteral, get_str_resolver\n\nif sys.version_info >= (3, 10):\n    from typing import TypeAlias\n\nif sys.version_info >= (3, 11):\n    from typing import Self\n\nLogicLiteralT: TypeAlias = Union[str, int, bool]\nLogicConstructibleT: TypeAlias = Union[LogicLiteralT, \"Logic\"]\n\n\n_U = 0\n_X = 1\n_0 = 2\n_1 = 3\n_Z = 4\n_W = 5\n_L = 6\n_H = 7\n_D = 8\n\n_literal_repr: dict[LogicLiteralT, int] = {\n    # unassigned\n    \"U\": _U,\n    \"u\": _U,\n    # unknown\n    \"X\": _X,\n    \"x\": _X,\n    # 0\n    0: _0,  # Also `False`\n    \"0\": _0,\n    # 1\n    1: _1,  # Also `True`\n    \"1\": _1,\n    # high impedance\n    \"Z\": _Z,\n    \"z\": _Z,\n    # weak unknown\n    \"W\": _W,\n    \"w\": _W,\n    # weak 0\n    \"L\": _L,\n    \"l\": _L,\n    # weak 1\n    \"H\": _H,\n    \"h\": _H,\n    # don't care\n    \"-\": _D,\n}\n\n\nclass Logic:\n    r\"\"\"9-state digital signal value type.\n\n    This type is modeled after VHDL's ``std_ulogic`` type.\n    It can represent the values (``U``, ``X``, ``0``, ``1``, ``Z``, ``W``, ``L``, ``H``, ``-``).\n    (System)Verilog's 4-state ``logic`` type is a subset which only utilizes the ``X``, ``0``, ``1``, and ``Z`` values.\n\n    :class:`!Logic` can be converted to and from :class:`int`, :class:`str`, :class:`bool` and :class:`Bit`.\n    String literals include ``\"U\"``, ``\"X\"``, ``\"0\"``, ``\"1\"``, ``\"Z\"``, ``\"W\"``, ``\"L\"``, ``\"H\"``, ``\"-\"``, and their lowercase values.\n\n    .. code-block:: pycon3\n\n        >>> Logic(\"X\")\n        Logic('X')\n        >>> Logic(True)\n        Logic('1')\n        >>> Logic(1)\n        Logic('1')\n\n        >>> str(Logic(\"Z\"))\n        'Z'\n        >>> bool(Logic(0))\n        False\n        >>> int(Logic(1))\n        1\n\n    .. note::\n\n        The :class:`int` and :class:`bool` conversions will raise :exc:`ValueError` if the value is not ``0``, ``1``, ``L``, or ``H``.\n\n    :class:`Logic` supports the common logic operations ``&``, ``|``, ``^``, and ``~``.\n\n    .. code-block:: pycon3\n\n        >>> def full_adder(a: Logic, b: Logic, carry: Logic) -> tuple[Logic, Logic]:\n        ...     res = a ^ b ^ carry\n        ...     carry_out = (a & b) | (b & carry) | (a & carry)\n        ...     return res, carry_out\n\n        >>> full_adder(a=Logic(\"0\"), b=Logic(\"1\"), carry=Logic(\"1\"))\n        (Logic('0'), Logic('1'))\n\n    Args:\n        value: value to construct into a :class:`!Logic`.\n\n    Raises:\n        ValueError: If the value if of the correct type, but cannot be constructed into a :class:`!Logic`.\n        TypeError: If the value is of a type that can't be constructed into a :class:`!Logic`.\n    \"\"\"\n\n    _values = {_U, _X, _0, _1, _Z, _W, _L, _H, _D}\n\n    _repr: int\n\n    __slots__ = (\"_repr\",)\n\n    @classmethod\n    @cache\n    def _singleton(cls, _repr: int) -> Self:\n        \"\"\"Return the Logic object associated with the repr, enforcing singleton.\"\"\"\n        self = object.__new__(cls)\n        self._repr = _repr\n        return self\n\n    def __new__(\n        cls,\n        value: LogicConstructibleT,\n    ) -> Self:\n        if isinstance(value, Logic):\n            _repr = value._repr\n        elif isinstance(value, (str, int)):\n            try:\n                _repr = _literal_repr[value]\n            except KeyError:\n                raise ValueError(\n                    f\"{value!r} is not convertible to {cls.__qualname__}\"\n                ) from None\n        else:\n            raise TypeError(\n                f\"Expected str, bool, or int, not {type(value).__qualname__}\"\n            )\n\n        if _repr not in cls._values:\n            raise ValueError(f\"{value!r} is not a valid {cls.__qualname__}\")\n\n        return cls._singleton(_repr)\n\n    def __and__(self, other: Self) -> Self:\n        if not isinstance(other, type(self)):\n            return NotImplemented\n        return type(self)(\n            (\n                # -----------------------------------------------------\n                # U    X    0    1    Z    W    L    H    -       |   |\n                # -----------------------------------------------------\n                (\"U\", \"U\", \"0\", \"U\", \"U\", \"U\", \"0\", \"U\", \"U\"),  # | U |\n                (\"U\", \"X\", \"0\", \"X\", \"X\", \"X\", \"0\", \"X\", \"X\"),  # | X |\n                (\"0\", \"0\", \"0\", \"0\", \"0\", \"0\", \"0\", \"0\", \"0\"),  # | 0 |\n                (\"U\", \"X\", \"0\", \"1\", \"X\", \"X\", \"0\", \"1\", \"X\"),  # | 1 |\n                (\"U\", \"X\", \"0\", \"X\", \"X\", \"X\", \"0\", \"X\", \"X\"),  # | Z |\n                (\"U\", \"X\", \"0\", \"X\", \"X\", \"X\", \"0\", \"X\", \"X\"),  # | W |\n                (\"0\", \"0\", \"0\", \"0\", \"0\", \"0\", \"0\", \"0\", \"0\"),  # | L |\n                (\"U\", \"X\", \"0\", \"1\", \"X\", \"X\", \"0\", \"1\", \"X\"),  # | H |\n                (\"U\", \"X\", \"0\", \"X\", \"X\", \"X\", \"0\", \"X\", \"X\"),  # | - |\n            )[self._repr][other._repr]\n        )\n\n    def __rand__(self, other: Self) -> Self:\n        return self & other\n\n    def __or__(self, other: Self) -> Self:\n        if not isinstance(other, type(self)):\n            return NotImplemented\n        return type(self)(\n            (\n                # -----------------------------------------------------\n                # U    X    0    1    Z    W    L    H    -       |   |\n                # -----------------------------------------------------\n                (\"U\", \"U\", \"U\", \"1\", \"U\", \"U\", \"U\", \"1\", \"U\"),  # | U |\n                (\"U\", \"X\", \"X\", \"1\", \"X\", \"X\", \"X\", \"1\", \"X\"),  # | X |\n                (\"U\", \"X\", \"0\", \"1\", \"X\", \"X\", \"0\", \"1\", \"X\"),  # | 0 |\n                (\"1\", \"1\", \"1\", \"1\", \"1\", \"1\", \"1\", \"1\", \"1\"),  # | 1 |\n                (\"U\", \"X\", \"X\", \"1\", \"X\", \"X\", \"X\", \"1\", \"X\"),  # | Z |\n                (\"U\", \"X\", \"X\", \"1\", \"X\", \"X\", \"X\", \"1\", \"X\"),  # | W |\n                (\"U\", \"X\", \"0\", \"1\", \"X\", \"X\", \"0\", \"1\", \"X\"),  # | L |\n                (\"1\", \"1\", \"1\", \"1\", \"1\", \"1\", \"1\", \"1\", \"1\"),  # | H |\n                (\"U\", \"X\", \"X\", \"1\", \"X\", \"X\", \"X\", \"1\", \"X\"),  # | - |\n            )[self._repr][other._repr]\n        )\n\n    def __ror__(self, other: Self) -> Self:\n        return self | other\n\n    def __xor__(self, other: Self) -> Self:\n        if not isinstance(other, type(self)):\n            return NotImplemented\n        return type(self)(\n            (\n                # -----------------------------------------------------\n                # U    X    0    1    Z    W    L    H    -       |   |\n                # -----------------------------------------------------\n                (\"U\", \"U\", \"U\", \"U\", \"U\", \"U\", \"U\", \"U\", \"U\"),  # | U |\n                (\"U\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\"),  # | X |\n                (\"U\", \"X\", \"0\", \"1\", \"X\", \"X\", \"0\", \"1\", \"X\"),  # | 0 |\n                (\"U\", \"X\", \"1\", \"0\", \"X\", \"X\", \"1\", \"0\", \"X\"),  # | 1 |\n                (\"U\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\"),  # | Z |\n                (\"U\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\"),  # | W |\n                (\"U\", \"X\", \"0\", \"1\", \"X\", \"X\", \"0\", \"1\", \"X\"),  # | L |\n                (\"U\", \"X\", \"1\", \"0\", \"X\", \"X\", \"1\", \"0\", \"X\"),  # | H |\n                (\"U\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\", \"X\"),  # | - |\n            )[self._repr][other._repr]\n        )\n\n    def __rxor__(self, other: Self) -> Self:\n        return self ^ other\n\n    def __invert__(self) -> Self:\n        return type(self)((\"U\", \"X\", \"1\", \"0\", \"X\", \"X\", \"1\", \"0\", \"X\")[self._repr])\n\n    def __eq__(self, other: object) -> bool:\n        if isinstance(other, Logic):\n            return self._repr == other._repr\n        elif isinstance(other, (int, str, bool)):\n            try:\n                other = Logic(other)\n            except ValueError:\n                return False\n            return self == other\n        else:\n            return NotImplemented\n\n    __hash__: None  # type: ignore[assignment]\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}({str(self)!r})\"\n\n    def __str__(self) -> str:\n        return (\"U\", \"X\", \"0\", \"1\", \"Z\", \"W\", \"L\", \"H\", \"-\")[self._repr]\n\n    if RESOLVE_X is None:\n\n        def __bool__(self) -> bool:\n            if self._repr in (_0, _L):\n                return False\n            elif self._repr in (_1, _H):\n                return True\n            raise ValueError(f\"Cannot convert {self!r} to bool\")\n\n        def __int__(self) -> int:\n            if self._repr in (_0, _L):\n                return 0\n            elif self._repr in (_1, _H):\n                return 1\n            raise ValueError(f\"Cannot convert {self!r} to int\")\n\n    else:\n\n        def __bool__(self) -> bool:\n            return self._repr in (_1, _H)\n\n        def __int__(self) -> int:\n            s = str(self)\n            s = RESOLVE_X(s)\n            return int(s, 2)\n\n    def __index__(self) -> int:\n        return int(self)\n\n    def resolve(self, resolver: ResolverLiteral) -> Self:\n        \"\"\"Resolve non-``0``/``1`` values to ``0``/``1``.\n\n        The possible values of the *resolver* argument are:\n\n        * ``\"weak\"``:\n            Weak values are resolved to their strong-valued equivalents.\n\n        * ``\"zeros\"``:\n            ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively.\n            Remaining non-``0``/``1`` values are resolved to ``0``.\n\n        * ``\"ones\"``:\n            ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively.\n            Remaining non-``0``/``1`` values are resolved to ``1``.\n\n        * ``\"random\"``:\n            ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively.\n            Remaining non-``0``/``1`` values are randomly resolved to either ``0`` or ``1``.\n\n        Args:\n            resolver: How to resolve non-``0``/``1`` values. See possible values above.\n\n        Returns:\n            The resolved Logic.\n\n        Raises:\n            ValueError: Invalid *resolver* value.\n            TypeError: Unsupported *value* type.\n        \"\"\"\n        return type(self)(get_str_resolver(resolver)(str(self)))\n\n    def __len__(self) -> int:\n        return 1\n\n    @property\n    def is_resolvable(self) -> bool:\n        \"\"\"``True`` if value is ``0``, ``1``, ``L``, ``H``.\n\n        .. versionadded:: 2.0\n        \"\"\"\n        return (False, False, True, True, False, False, True, True, False)[self._repr]\n\n    def __copy__(self) -> Logic:\n        return self\n\n    def __deepcopy__(self, memo: dict[int, object]) -> Logic:\n        return self\n\n\nclass Bit(Logic):\n    \"\"\"2-state digital signal value type.\n\n    This is modeled after (System)Verilog's and VHDL's ``bit`` type.\n    It can represent only the values ``0`` and ``1``.\n    It can be converted to and from :class:`int`, :class:`str`, :class:`bool`, or :class:`Logic` values.\n\n    As a subtype of :class:`!Logic`, it supports all of the same operations\n    and can be used in operations interchangeably with :class:`!Logic`.\n\n    Args:\n        value: value to construct into a :class:`!Bit`.\n\n    Raises:\n        ValueError: If the value if of the correct type, but cannot be constructed into a :class:`!Bit`.\n        TypeError: If the value is of a type that can't be constructed into a :class:`!Bit`.\n    \"\"\"\n\n    _values = {_0, _1}\n"
  },
  {
    "path": "src/cocotb/types/_logic_array.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport copy\nimport sys\nimport warnings\nfrom collections.abc import Iterable, Iterator\nfrom math import ceil\nfrom typing import (\n    Any,\n    Literal,\n    cast,\n    overload,\n)\n\nfrom cocotb._deprecation import deprecated\nfrom cocotb.types._abstract_array import AbstractMutableArray\nfrom cocotb.types._indexing import IndexingChangedWarning\nfrom cocotb.types._logic import Logic, LogicConstructibleT\nfrom cocotb.types._range import Range\nfrom cocotb.types._resolve import RESOLVE_X, ResolverLiteral, get_str_resolver\n\nif sys.version_info >= (3, 10):\n    from typing import TypeAlias\n\n_resolve_lh_table = str.maketrans({\"L\": \"0\", \"H\": \"1\"})\n_str_literals = frozenset(\"UX01ZWLH-\")\n\n\nByteOrder: TypeAlias = Literal[\"big\", \"little\"]\n\n\nclass LogicArray(AbstractMutableArray[Logic]):\n    r\"\"\"Fixed-sized, arbitrarily-indexed, :class:`.Array` of :class:`.Logic`\\ s.\n\n    An :class:`!Array`, where all elements are enforced to be :class:`!Logic`.\n    Additionally, this type supports bit-wise logical operators, conversions to integers and bytes,\n    and ``X`` testing and mapping.\n\n    :class:`!LogicArray`\\ s can be constructed from an iterable of :class:`!Logic`\\ s,\n    or values constructible into :class:`!Logic`, like :class:`bool`, :class:`str`, or :class:`int`.\n    Alternatively, they can be constructed from :class:`!str` or :class:`!int` literals.\n\n    Like :class:`!Array`, if *range* is not given, the range ``Range(len(value)-1, \"downto\", 0)`` is used;\n    and if an :class:`int` is passed for *range*, the range ``Range(range-1, \"downto\", 0)`` is used.\n\n    .. code-block:: pycon3\n\n        >>> LogicArray(0b0111, 4)\n        LogicArray('0111', Range(3, 'downto', 0))\n\n        >>> LogicArray(\"01XZ\", Range(0, \"to\", 3))\n        LogicArray('01XZ', Range(0, 'to', 3))\n\n        >>> LogicArray([0, True, \"X\", Logic(\"-\")])\n        LogicArray('01X-', Range(3, 'downto', 0))\n\n    .. note::\n        If constructing from an unsigned :class:`!int` literal, *range* `must` be given.\n\n    :class:`!LogicArray`\\ s can be constructed from :class:`int`\\ s using :meth:`from_unsigned` or :meth:`from_signed`.\n\n    .. code-block:: pycon3\n\n        >>> LogicArray.from_unsigned(0xA, 4)\n        LogicArray('1010', Range(3, 'downto', 0))\n\n        >>> LogicArray.from_signed(-4, Range(0, \"to\", 3))  # will sign-extend\n        LogicArray('1100', Range(0, 'to', 3))\n\n    :class:`!LogicArray`\\ s can be constructed from :class:`bytes` or :class:`bytearray` using :meth:`from_bytes`.\n    Use the *byteorder* argument to control endianness.\n\n    .. code-block:: pycon3\n\n        >>> LogicArray.from_bytes(b\"1n\", byteorder=\"big\")\n        LogicArray('0011000101101110', Range(15, 'downto', 0))\n\n        >>> LogicArray.from_bytes(b\"1n\", byteorder=\"little\")\n        LogicArray('0110111000110001', Range(15, 'downto', 0))\n\n    :class:`!LogicArray`\\ s support the same :class:`list`-like operations as :class:`!Array`;\n    however, it enforces the condition that all elements must be a :class:`!Logic`.\n\n    .. code-block:: pycon3\n\n        >>> array = LogicArray(\"1010\")\n        >>> array[0]  # is indexable\n        Logic('0')\n\n        >>> array[1:]  # is slice-able\n        LogicArray('10', Range(1, 'downto', 0))\n\n        >>> Logic(\"0\") in array  # is a collection\n        True\n\n        >>> list(array)  # is an iterable\n        [Logic('1'), Logic('0'), Logic('1'), Logic('0')]\n\n    When setting an element or slice, the *value* is first constructed into a :class:`!Logic`.\n\n    .. code-block:: pycon3\n\n        >>> array = LogicArray(\"1010\")\n        >>> array[3] = \"Z\"\n        >>> array[3]\n        Logic('Z')\n\n        >>> array[2:] = [\"X\", True, 0]\n        >>> array\n        LogicArray('ZX10', Range(3, 'downto', 0))\n\n        >>> array[:] = 0b0101\n        >>> array\n        LogicArray('0101', Range(3, 'downto', 0))\n\n    :class:`!LogicArray`\\ s can be converted into their :class:`str` or :class:`int` literal values using casts.\n    They can also be used in conditionals.\n\n    .. code-block:: pycon3\n\n        >>> value = LogicArray(\"1010\")\n        >>> str(value)\n        '1010'\n\n        >>> int(value)\n        10\n        >>> if value:\n        ...     print(\"Not 0!\")\n        Not 0!\n\n    .. warning::\n        The :class:`int` cast, :class:`bool` cast, and use in conditionals assumes the\n        value is entirely ``0``, ``1``, ``L``, or ``H``, and will raise an exception otherwise.\n\n    The :meth:`to_unsigned`, :meth:`to_signed`, and :meth:`to_bytes` methods can be used to convert\n    the value into an unsigned or signed integer, or bytes, respectively.\n\n    .. code-block:: pycon3\n\n        >>> value = LogicArray(\"1010\")\n        >>> value.to_unsigned()\n        10\n\n        >>> value.to_signed()\n        -6\n\n        >>> value.to_bytes(byteorder=\"big\")\n        b'\\n'\n\n    .. warning::\n        These operations assume the value is entirely ``0``, ``1``, ``L``, or ``H``, and will raise an exception otherwise.\n\n    You can also convert :class:`!LogicArray`\\ s to hexadecimal or binary strings using\n    the built-ins :func:`hex` and :func:`bin`, respectively.\n\n    .. code-block:: pycon3\n\n        >>> value = LogicArray(\"01111010\")\n        >>> hex(value)\n        '0x7a'\n\n        >>> bin(value)\n        '0b1111010'\n\n    .. warning::\n        Using :func:`hex` or :func:`bin` first turns the :class:`!LogicArray` into an :class:`int`.\n        This means the exact length of the :class:`!LogicArray` is lost.\n        It also means that these expressions will raise an exception if the value is not entirely ``0``, ``1``, ``L``, or ``H``.\n\n    :class:`!LogicArray`\\ s also support element-wise logical operations: ``&``, ``|``,\n    ``^``, and ``~``.\n\n    .. code-block:: pycon3\n\n        >>> def big_mux(a: LogicArray, b: LogicArray, sel: Logic) -> LogicArray:\n        ...     s = LogicArray([sel] * len(a))\n        ...     return (a & ~s) | (b & s)\n\n        >>> a = LogicArray(\"0110\")\n        >>> b = LogicArray(\"1110\")\n        >>> sel = Logic(\"1\")  # choose second option\n        >>> big_mux(a, b, sel)\n        LogicArray('1110', Range(3, 'downto', 0))\n\n    :class:`!LogicArray`\\ s support formatting in f-strings and the :func:`format` built-in.\n    All resulting strings are zero-padded to the length of the :class:`!LogicArray`.\n    For specifiers other than ``\"\"``, if the value contains non-``0``/``1`` values, a :exc:`!ValueError` will be raised.\n    The supported format specifiers are:\n\n    * ``\"\"``: Binary (same as :class:`str` cast).\n    * ``\"b\"``: 0-padded unsigned binary.\n    * ``\"o\"``: 0-padded unsigned octal.\n    * ``\"d\"``: 0-padded unsigned decimal integer.\n    * ``\"x\"``: 0-padded unsigned hexadecimal (lowercase).\n    * ``\"X\"``: 0-padded unsigned hexadecimal (uppercase).\n\n    The  ``\"#\"`` \"alternate\" format specifier and the ``\"_\"`` and ``\",\"`` grouping modifiers are also supported.\n    These behave the same way as in standard Python formatting of integers.\n\n    .. code-block:: pycon3\n\n        >>> value = LogicArray(\"00101011\")\n        >>> f\"{value}\"\n        '00101011'\n        >>> f\"{value:#_b}\"\n        '0b0010_1011'\n        >>> format(value, \"x\")\n        '2b'\n\n    Args:\n        value: Initial value for the :class:`!LogicArray`.\n        range: The indexing scheme of the :class:`!LogicArray`.\n\n    Raises:\n        TypeError: When invalid argument types are used.\n        ValueError: When *value* will not fit in a :class:`!LogicArray` of the given *range*.\n    \"\"\"\n\n    # These three attribute contain the current value of the array in one or more of\n    # three different implementations. This is done for performance reasons, as certain\n    # implementations are faster for particular operations.\n    # Each implementation can be present, or None if the implementation has not been\n    # computed or has been invalidated by a mutating operation.\n    _value_as_array: list[Logic] | None\n    _value_as_int: int | None\n    _value_as_str: str | None\n    _range: Range\n    _warn_indexing: bool\n\n    __slots__ = (\n        \"_value_as_array\",\n        \"_value_as_int\",\n        \"_value_as_str\",\n        \"_range\",\n        \"_warn_indexing\",\n    )\n\n    def __init__(\n        self,\n        value: int | str | Iterable[LogicConstructibleT],\n        range: Range | int | None = None,\n    ) -> None:\n        self._value_as_array = None\n        self._value_as_int = None\n        self._value_as_str = None\n        self._warn_indexing = False\n\n        if isinstance(range, int):\n            range = Range(range - 1, \"downto\", 0)\n        elif range is not None and not isinstance(range, Range):\n            raise TypeError(\n                f\"Expected Range or int for parameter 'range', not {type(range).__qualname__}\"\n            )\n\n        if isinstance(value, str):\n            value = value.replace(\"_\", \"\")  # remove visual separators\n            value = value.upper()  # normalize to uppercase\n            nonliterals = set(value) - _str_literals\n            if nonliterals:\n                nonliteral_str = \", \".join(repr(c) for c in sorted(nonliterals))\n                raise ValueError(\n                    f\"String literal contains invalid logic values: {nonliteral_str}\"\n                )\n            self._value_as_str = value\n            if range is not None:\n                if len(value) != len(range):\n                    raise ValueError(\n                        f\"String literal of length {len(value)} does not match length of {range!r}\"\n                    )\n                self._range = range\n            else:\n                self._range = Range(len(self._value_as_str) - 1, \"downto\", 0)\n        elif isinstance(value, int):\n            value = int(value)  # force bool to int\n            if range is None:\n                raise TypeError(\"Missing required arguments: 'range'\")\n            if len(range) == 0:\n                raise ValueError(\n                    f\"{value!r} is too large to fit in LogicArray with {range!r}\"\n                )\n            value_ = value\n            if value_ < 0:\n                if value_ < -(1 << (len(range) - 1)):\n                    raise ValueError(\n                        f\"{value!r} is too small to fit in LogicArray with {range!r}\"\n                    )\n                value_ += 1 << len(range)\n            elif value_ >= 1 << len(range):\n                raise ValueError(\n                    f\"{value!r} is too large to fit in LogicArray with {range!r}\"\n                )\n            self._value_as_int = value_\n            self._range = range\n        elif isinstance(value, LogicArray):\n            array = value._value_as_array\n            self._value_as_array = list(array) if array is not None else None\n            self._value_as_int = value._value_as_int\n            self._value_as_str = value._value_as_str\n            if range is None:\n                self._range = value._range\n            else:\n                if len(range) != len(value):\n                    raise ValueError(f\"Length of {value!r} does not match {range!r}\")\n                self._range = range\n        else:\n            self._value_as_array = [Logic(v) for v in value]\n            if range is not None:\n                if len(self._value_as_array) != len(range):\n                    raise ValueError(\n                        f\"Value of length {len(self._value_as_array)} does not match range: {range!r}\"\n                    )\n                self._range = range\n            else:\n                self._range = Range(len(self._value_as_array) - 1, \"downto\", 0)\n\n    def _get_array(self) -> list[Logic]:\n        if self._value_as_array is None:\n            # May convert int to str before to converting to array.\n            self._value_as_array = [Logic(v) for v in self._get_str()]\n        return self._value_as_array\n\n    def _get_str(self) -> str:\n        if self._value_as_str is None:\n            if self._value_as_int is not None:\n                self._value_as_str = format(self._value_as_int, f\"0{len(self)}b\")\n            else:\n                self._value_as_str = \"\".join(\n                    str(v) for v in cast(\"list[Logic]\", self._value_as_array)\n                )\n        return self._value_as_str\n\n    def _get_int(self) -> int:\n        if self._value_as_int is None:\n            # May convert list to str before converting to int.\n            value_as_str = self._get_str()\n\n            # always resolve L and H to 0 and 1\n            value_as_str = value_as_str.translate(_resolve_lh_table)\n\n            try:\n                self._value_as_int = int(value_as_str, 2)\n            except ValueError:\n                if RESOLVE_X is None:\n                    raise ValueError(\n                        f\"Can't convert {type(self).__qualname__} to int: it contains non-0/1 values\"\n                    ) from None\n                else:\n                    value_as_str = RESOLVE_X(value_as_str)\n                    return int(value_as_str, 2)\n\n        return self._value_as_int\n\n    @classmethod\n    def from_unsigned(\n        cls,\n        value: int,\n        range: Range | int,\n        *,\n        on_overflow: Literal[\"error\", \"wrap\"] = \"error\",\n    ) -> LogicArray:\n        \"\"\"Construct a :class:`!LogicArray` from an :class:`int` with unsigned representation.\n\n        The :class:`int` is treated as an arbitrary-length bit vector with unsigned representation where the left-most bit is the most significant bit.\n        This bit vector is then constructed into a :class:`!LogicArray`.\n\n        The *on_overflow* parameter can be set to ``\"wrap\"`` to allow truncating excessive significant bits so the *value* fits into the *range*.\n\n        .. code-block:: python\n\n            >>> LogicArray.from_unsigned(0b10011101, 4, on_overflow=\"wrap\")\n            LogicArray('1101', Range(3, 'downto', 0))\n\n        Args:\n            value: The integer to convert.\n            range: Indexing scheme for the :class:`!LogicArray`.\n            on_overflow: If ``\"wrap\"``, the *value* will have excessive significant bits truncated so that it fits into the *range*.\n                If ``\"error\"`` (default), a :class:`ValueError` is raised when the *value* does not fit.\n\n        Returns:\n            A :class:`!LogicArray` equivalent to the *value*.\n\n        Raises:\n            TypeError: When invalid argument types are used.\n            ValueError: When a :class:`!LogicArray` of the given *range* can't hold the *value*, or *value* is negative.\n\n        .. versionadded:: 2.1\n            The *on_overflow* parameter.\n        \"\"\"\n        # input type checking and normalization\n        if isinstance(range, int):\n            range = Range(range - 1, \"downto\", 0)\n        elif not isinstance(range, Range):\n            raise TypeError(\n                f\"Expected Range or int for parameter 'range', not {type(range).__qualname__}\"\n            )\n        if not isinstance(value, int):\n            raise TypeError(\n                f\"Expected int for parameter 'value', not {type(value).__qualname__}\"\n            )\n\n        if value < 0:\n            raise ValueError(\"Expected unsigned integer, got negative value\")\n\n        if len(range) == 0:\n            raise ValueError(\n                f\"Unsigned integer {value!r} will not fit in a LogicArray with bounds: {range!r}\"\n            )\n\n        if on_overflow == \"wrap\":\n            value %= 1 << len(range)\n        elif on_overflow == \"error\":\n            if value >= (1 << len(range)):\n                raise ValueError(\n                    f\"Unsigned integer {value!r} will not fit in a LogicArray with bounds: {range!r}\"\n                )\n        else:\n            raise ValueError(\n                f\"Invalid value for on_overflow: {on_overflow!r}. \"\n                f\"Expected 'error' or 'wrap'.\"\n            )\n\n        # construct the LogicArray\n        self = cls.__new__(cls)\n        self._value_as_array = None\n        self._value_as_int = value\n        self._value_as_str = None\n        self._range = range\n        self._warn_indexing = False\n        return self\n\n    @classmethod\n    def from_signed(\n        cls,\n        value: int,\n        range: Range | int,\n        *,\n        on_overflow: Literal[\"error\", \"wrap\"] = \"error\",\n    ) -> LogicArray:\n        \"\"\"Construct a :class:`!LogicArray` from an :class:`int` with two's complement representation.\n\n        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.\n        This bit vector is then constructed into a :class:`!LogicArray`.\n\n        The *on_overflow* parameter can be set to ``\"wrap\"`` to allow truncating excessive significant bits so the *value* fits into the *range*.\n\n        .. code-block:: python\n\n            >>> LogicArray.from_signed(-12345, 16)\n            LogicArray('1100111111000111', Range(15, 'downto', 0))\n\n            >>> LogicArray.from_signed(-12345, 4, on_overflow=\"wrap\")\n            LogicArray('0111', Range(3, 'downto', 0))\n\n        Args:\n            value: The integer to convert.\n            range: Indexing scheme for the :class:`!LogicArray`.\n            on_overflow: If ``\"wrap\"``, the *value* will have excessive significant bits truncated so that it fits into the *range*.\n                If ``\"error\"`` (default), a :class:`ValueError` is raised when the *value* does not fit.\n\n        Returns:\n            A :class:`!LogicArray` equivalent to the *value*.\n\n        Raises:\n            TypeError: When invalid argument types are used.\n            ValueError: When a :class:`!LogicArray` of the given *range* can't hold the *value*.\n\n        .. versionadded:: 2.1\n            The *on_overflow* parameter.\n        \"\"\"\n        # input type checking and normalization\n        if isinstance(range, int):\n            range = Range(range - 1, \"downto\", 0)\n        elif not isinstance(range, Range):\n            raise TypeError(\n                f\"Expected Range or int for parameter 'range', not {type(range).__qualname__}\"\n            )\n        if not isinstance(value, int):\n            raise TypeError(\n                f\"Expected int for parameter 'value', not {type(value).__qualname__}\"\n            )\n\n        # Prevent null range from blowing up the below code.\n        if len(range) == 0:\n            raise ValueError(\n                f\"Signed integer {value!r} will not fit in a LogicArray with bounds: {range!r}\"\n            )\n\n        if on_overflow == \"wrap\":\n            value %= 1 << len(range)\n        elif on_overflow == \"error\":\n            limit = 1 << (len(range) - 1)\n            if value < -limit or limit <= value:\n                raise ValueError(\n                    f\"Signed integer {value!r} will not fit in a LogicArray with bounds: {range!r}\"\n                )\n            value %= 2 * limit\n        else:\n            raise ValueError(\n                f\"Invalid value for on_overflow: {on_overflow!r}. \"\n                f\"Expected 'error' or 'wrap'.\"\n            )\n\n        # construct the LogicArray\n        self = cls.__new__(cls)\n        self._value_as_array = None\n        self._value_as_int = value\n        self._value_as_str = None\n        self._range = range\n        self._warn_indexing = False\n        return self\n\n    @classmethod\n    def from_bytes(\n        cls,\n        value: bytes | bytearray,\n        range: Range | int | None = None,\n        *,\n        byteorder: ByteOrder,\n    ) -> LogicArray:\n        \"\"\"Construct a :class:`!LogicArray` from :class:`bytes`.\n\n        The :class:`bytes` is first converted to an unsigned integer using *byteorder*-endian representation,\n        then is converted to a :class:`!LogicArray` as in :meth:`from_unsigned`.\n\n        Args:\n            value: The bytes to convert.\n            range: Indexing scheme for the :class:`!LogicArray`.\n            byteorder: The endianness used to construct the intermediate integer, either ``\"big\"`` or ``\"little\"``.\n\n        Returns:\n            A :class:`!LogicArray` equivalent to the *value*.\n\n        Raises:\n            ValueError: When a :class:`!LogicArray` of the given *range* can't hold the *value*.\n        \"\"\"\n        if range is None:\n            range = Range(len(value) * 8 - 1, \"downto\", 0)\n        else:\n            if isinstance(range, int):\n                range = Range(range - 1, \"downto\", 0)\n            if len(value) * 8 != len(range):\n                raise ValueError(\n                    f\"Value of length {len(value)} will not fit in a LogicArray with bounds: {range!r}\"\n                )\n        value_as_int = int.from_bytes(value, byteorder=byteorder, signed=False)\n        return LogicArray(value_as_int, range)\n\n    @classmethod\n    def _from_handle(cls, value: str, warn_indexing: bool) -> LogicArray:\n        # Used by cocotb.handle classes to make LogicArray from values gotten from the\n        # simulator which we expect to be well-formed.\n        # Values are required to be uppercase.\n        self = cls.__new__(cls)\n        self._value_as_array = None\n        self._value_as_int = None\n        self._value_as_str = value\n        self._range = Range(len(value) - 1, \"downto\", 0)\n        self._warn_indexing = warn_indexing\n        return self\n\n    @property\n    def range(self) -> Range:\n        \"\"\":class:`Range` of the indexes of the array.\"\"\"\n        return self._range\n\n    @range.setter\n    def range(self, new_range: Range) -> None:\n        \"\"\"Set a new indexing scheme on the array. Must be the same size.\"\"\"\n        if not isinstance(new_range, Range):\n            raise TypeError(\"range argument must be of type 'Range'\")\n        if len(new_range) != len(self):\n            raise ValueError(\n                f\"{new_range!r} not the same length as old range: {self._range!r}\"\n            )\n        self._range = new_range\n\n    def __iter__(self) -> Iterator[Logic]:\n        return iter(self._get_array())\n\n    def __reversed__(self) -> Iterator[Logic]:\n        return reversed(self._get_array())\n\n    def __contains__(self, item: object) -> bool:\n        return item in self._get_array()\n\n    def __eq__(\n        self,\n        other: object,\n    ) -> bool:\n        if isinstance(other, int):\n            if len(self) == 0:\n                # Null arrays don't have a value and thus always compare False.\n                return False\n            try:\n                if other < 0:\n                    return self.to_signed() == other\n                else:\n                    return self.to_unsigned() == other\n            except ValueError:\n                return False\n        elif isinstance(other, str):\n            return str(self) == other.upper()\n        elif isinstance(other, LogicArray):\n            if len(self) != len(other):\n                return False\n            # Complex, but efficient chain of checking logic.\n            # Avoid conversions if it can help it at first.\n            # Prefers checking against str vs any type since that is going to be the\n            #   most common type and also the \"middle\" type for conversions.\n            # Always converts away from ints to prevent issues with non-0/1 data.\n            if self._value_as_str is not None and other._value_as_str is not None:\n                # (STR, STR)\n                return self._value_as_str == other._value_as_str\n            elif self._value_as_array is not None and other._value_as_array is not None:\n                # (ARRAY, ARRAY)\n                return self._value_as_array == other._value_as_array\n            elif self._value_as_int is not None and other._value_as_int is not None:\n                # (INT, INT)\n                return self._value_as_int == other._value_as_int\n            elif self._value_as_str is not None:\n                # (STR, INT)\n                # (STR, ARRAY)\n                return self._value_as_str == other._get_str()\n            elif other._value_as_str is not None:\n                # (INT, STR)\n                # (ARRAY, STR)\n                return self._get_str() == other._value_as_str\n            elif self._value_as_array is not None:\n                # (ARRAY, INT)\n                return self._value_as_array == other._get_array()\n            else:\n                # (INT, ARRAY)\n                return self._get_array() == other._value_as_array\n        elif isinstance(other, (list, tuple)):\n            try:\n                other = LogicArray(other)\n            except ValueError:\n                return False\n            return self == other\n        else:\n            return NotImplemented\n\n    @property\n    @deprecated(\n        \"`logic_array.binstr` getter is deprecated. Use `str(logic_array)` instead.\"\n    )\n    def binstr(self) -> str:\n        \"\"\"The :class:`!LogicArray`'s value in :class:`str` literal representation.\n\n        :getter:\n            Return the :class:`!LogicArray`'s value in :class:`str` literal representation.\n\n            .. deprecated:: 2.0\n                Use ``str(logic_array)`` instead.\n\n        :setter:\n            Set the :class:`!LogicArray`'s value using a :class:`str` literal representation.\n\n            .. deprecated:: 2.0\n                Use ``logic_array[:] = value`` instead.\n        \"\"\"\n        return str(self)\n\n    @binstr.setter\n    @deprecated(\n        \"`logic_array.binstr = value` setter is deprecated. Use `logic_array[:] = value` instead.\"\n    )\n    def binstr(self, value: str) -> None:\n        self[:] = value\n\n    @property\n    def is_resolvable(self) -> bool:\n        \"\"\"``True`` if all elements are ``0``, ``1``, ``L``, ``H``.\"\"\"\n        return all(bit.is_resolvable for bit in self)\n\n    @property\n    @deprecated(\n        \"`logic_array.integer` getter is deprecated. Use `logic_array.to_unsigned()` instead.\"\n    )\n    def integer(self) -> int:\n        \"\"\"The :class:`!LogicArray`'s value as an unsigned :class:`int`.\n\n        The :class:`!LogicArray` is treated as an arbitrary-length vector of bits\n        with the left-most bit being the most significant bit in the integer value.\n        The bit vector is then interpreted as an integer using unsigned representation.\n\n        :getter:\n            Return the :class:`!LogicArray`'s value as an unsigned integer.\n\n            .. deprecated:: 2.0\n                Use :meth:`logic_array.to_unsigned() <cocotb.types.LogicArray.to_unsigned>` instead.\n\n        :setter:\n            Set the :class:`!LogicArray`'s value using an unsigned integer.\n\n            .. deprecated:: 2.0\n                Use ``logic_array[:] = value`` instead.\n        \"\"\"\n        return self.to_unsigned()\n\n    @integer.setter\n    @deprecated(\n        \"`logic_array.integer = value` setter is deprecated. Use `logic_array[:] = value` instead.\"\n    )\n    def integer(self, value: int) -> None:\n        self[:] = LogicArray.from_unsigned(value, len(self))\n\n    @property\n    @deprecated(\n        \"`logic_array.signed_integer` getter is deprecated. Use `logic_array.to_signed()` instead.\"\n    )\n    def signed_integer(self) -> int:\n        \"\"\"The :class:`!LogicArray`'s value as a signed :class:`int`.\n\n        The :class:`!LogicArray` is treated as an arbitrary-length vector of bits\n        with the left-most bit being the most significant bit in the integer value.\n        The bit vector is then interpreted as an integer using two's complement representation.\n\n        :getter:\n            Return the :class:`!LogicArray`'s value as a signed integer.\n\n            .. deprecated:: 2.0\n                Use :meth:`logic_array.to_signed() <cocotb.types.LogicArray.to_signed>` instead.\n\n        :setter:\n            Set the :class:`!LogicArray`'s value using a signed integer.\n\n            .. deprecated:: 2.0\n                Use ``logic_array[:] = LogicArray.from_signed(value, len(logic_array))`` instead.\n        \"\"\"\n        return self.to_signed()\n\n    @signed_integer.setter\n    @deprecated(\n        \"`logic_array.signed_integer = value` setter is deprecated. \"\n        \"Use `logic_array[:] = LogicArray.from_signed(value, len(logic_array))` instead.\"\n    )\n    def signed_integer(self, value: int) -> None:\n        self[:] = LogicArray.from_signed(value, len(self))\n\n    @property\n    @deprecated(\n        \"`logic_array.buff` getter is deprecated. \"\n        'Use `logic_array.to_bytes(byteorder=\"big\")` instead.'\n    )\n    def buff(self) -> bytes:\n        \"\"\"The :class:`!LogicArray`'s value as :class:`bytes`.\n\n        The object is first converted to an :class:`int` as in :meth:`to_unsigned`.\n        Then the object is converted to :class:`bytes` by converting the resulting integer value as in :meth:`int.to_bytes`.\n        This assumes big-endian byte order and the minimal number of bytes necessary to hold any value of the current object.\n\n        :getter:\n            Return the :class:`!LogicArray`'s value as :class:`bytes`.\n\n            .. deprecated:: 2.0\n                Use :meth:`logic_array.to_bytes(byteorder=\"big\") <cocotb.types.LogicArray.to_bytes>` instead.\n\n        :setter:\n            Set the :class:`!LogicArray`'s value using :class:`bytes`.\n\n            .. deprecated:: 2.0\n                Use ``logic_array[:] = LogicArray.from_bytes(value, len(logic_array), byteorder=\"big\")`` instead.\n        \"\"\"\n        return self.to_bytes(byteorder=\"big\")\n\n    @buff.setter\n    @deprecated(\n        \"`logic_array.buff = value` setter is deprecated. \"\n        'Use `logic_array[:] = LogicArray.from_bytes(value, len(logic_array), byteorder=\"big\")` instead.'\n    )\n    def buff(self, value: bytes) -> None:\n        self[:] = LogicArray.from_bytes(value, len(self), byteorder=\"big\")\n\n    def to_unsigned(self) -> int:\n        \"\"\"Convert the value to an integer by interpreting it using unsigned representation.\n\n        The :class:`!LogicArray` is treated as an arbitrary-length vector of bits\n        with the left-most bit being the most significant bit in the integer value.\n        The bit vector is then interpreted as an integer using unsigned representation.\n\n        Returns:\n            An integer equivalent to the value by interpreting it using unsigned representation.\n        \"\"\"\n        if len(self) == 0:\n            raise ValueError(\"Cannot convert null vector to integer\")\n        return self._get_int()\n\n    def to_signed(self) -> int:\n        \"\"\"Convert the value to an integer by interpreting it using two's complement representation.\n\n        The :class:`!LogicArray` is treated as an arbitrary-length vector of bits\n        with the left-most bit being the most significant bit in the integer value.\n        The bit vector is then interpreted as an integer using two's complement representation.\n\n        Returns:\n            An integer equivalent to the value by interpreting it using two's complement representation.\n        \"\"\"\n        if len(self) == 0:\n            raise ValueError(\"Cannot convert null vector to integer\")\n        value = self._get_int()\n        limit = 1 << (len(self) - 1)\n        if value >= limit:\n            value -= 2 * limit\n        return value\n\n    def to_bytes(\n        self,\n        *,\n        byteorder: ByteOrder,\n    ) -> bytes:\n        \"\"\"Convert the value to bytes.\n\n        The :class:`!LogicArray` is converted to an unsigned integer as in :meth:`to_unsigned`,\n        then is converted to :class:`bytes` using *byteorder*-endian representation\n        with the minimum number of bytes which can store all the bits in the original :class:`!LogicArray`.\n\n        Args:\n            byteorder: The endianness used to construct the intermediate integer, either ``\"big\"`` or ``\"little\"``.\n\n        Returns:\n            :class:`bytes` equivalent to the value.\n        \"\"\"\n        return self.to_unsigned().to_bytes(ceil(len(self) / 8), byteorder=byteorder)\n\n    @overload\n    def __getitem__(self, item: int) -> Logic: ...\n\n    @overload\n    def __getitem__(self, item: slice) -> LogicArray: ...\n\n    def __getitem__(self, item: int | slice) -> Logic | LogicArray:\n        array = self._get_array()\n        if isinstance(item, int):\n            if self._warn_indexing:\n                warnings.warn(\n                    f\"Update index {item} to {self.range[item]}\",\n                    IndexingChangedWarning,\n                    stacklevel=2,\n                )\n            idx = self._translate_index(item)\n            return array[idx]\n        elif isinstance(item, slice):\n            if self._warn_indexing:\n                start = item.start if item.start is not None else 0\n                stop = item.stop if item.stop is not None else len(self) - 1\n                warnings.warn(\n                    f\"Update slice {start}:{stop} to {self.range[start]}:{self.range[stop]}\",\n                    IndexingChangedWarning,\n                    stacklevel=2,\n                )\n            start = item.start if item.start is not None else self.left\n            stop = item.stop if item.stop is not None else self.right\n            if item.step is not None:\n                raise IndexError(\"do not specify step\")\n            start_i = self._translate_index(start)\n            stop_i = self._translate_index(stop)\n            if start_i > stop_i:\n                raise IndexError(\n                    f\"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]\"\n                )\n            value = array[start_i : stop_i + 1]\n            range = Range(start, self.direction, stop)\n            return LogicArray(value=value, range=range)\n        raise TypeError(f\"indexes must be ints or slices, not {type(item).__name__}\")\n\n    @overload\n    def __setitem__(self, item: int, value: LogicConstructibleT) -> None: ...\n\n    @overload\n    def __setitem__(\n        self, item: slice, value: str | Iterable[LogicConstructibleT] | int\n    ) -> None: ...\n\n    def __setitem__(\n        self,\n        item: int | slice,\n        value: LogicConstructibleT | Iterable[LogicConstructibleT],\n    ) -> None:\n        array = self._get_array()\n        # invalid other impls\n        self._value_as_str = None\n        self._value_as_int = None\n        if isinstance(item, int):\n            idx = self._translate_index(item)\n            array[idx] = Logic(cast(\"LogicConstructibleT\", value))\n        elif isinstance(item, slice):\n            start = item.start if item.start is not None else self.left\n            stop = item.stop if item.stop is not None else self.right\n            if item.step is not None:\n                raise IndexError(\"do not specify step\")\n            start_i = self._translate_index(start)\n            stop_i = self._translate_index(stop)\n            if start_i > stop_i:\n                raise IndexError(\n                    f\"slice [{start}:{stop}] direction does not match array direction [{self.left}:{self.right}]\"\n                )\n            value = cast(\"str | int | Iterable[LogicConstructibleT]\", value)\n            value_as_logics = LogicArray(value, stop_i - start_i + 1)\n            array[start_i : stop_i + 1] = value_as_logics\n        else:\n            raise TypeError(\n                f\"indexes must be ints or slices, not {type(item).__name__}\"\n            )\n\n    def _translate_index(self, item: int) -> int:\n        try:\n            return self._range.index(item)\n        except ValueError:\n            raise IndexError(f\"index {item} out of range\") from None\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}({str(self)!r}, {self.range!r})\"\n\n    def __str__(self) -> str:\n        return self._get_str()\n\n    def __int__(self) -> int:\n        return self.to_unsigned()\n\n    def __index__(self) -> int:\n        return int(self)\n\n    def __and__(self, other: LogicArray) -> LogicArray:\n        if not isinstance(other, LogicArray):\n            return NotImplemented\n        if len(self) != len(other):\n            raise ValueError(\n                f\"cannot perform bitwise & \"\n                f\"between {type(self).__qualname__} of length {len(self)} \"\n                f\"and {type(other).__qualname__} of length {len(other)}\"\n            )\n        return LogicArray(a & b for a, b in zip(self, other))\n\n    def __or__(self, other: LogicArray) -> LogicArray:\n        if not isinstance(other, LogicArray):\n            return NotImplemented\n        if len(self) != len(other):\n            raise ValueError(\n                f\"cannot perform bitwise | \"\n                f\"between {type(self).__qualname__} of length {len(self)} \"\n                f\"and {type(other).__qualname__} of length {len(other)}\"\n            )\n        return LogicArray(a | b for a, b in zip(self, other))\n\n    def __xor__(self, other: LogicArray) -> LogicArray:\n        if not isinstance(other, LogicArray):\n            return NotImplemented\n        if len(self) != len(other):\n            raise ValueError(\n                f\"cannot perform bitwise ^ \"\n                f\"between {type(self).__qualname__} of length {len(self)} \"\n                f\"and {type(other).__qualname__} of length {len(other)}\"\n            )\n        return LogicArray(a ^ b for a, b in zip(self, other))\n\n    def __invert__(self) -> LogicArray:\n        return LogicArray(~v for v in self)\n\n    if RESOLVE_X is None:\n\n        def __bool__(self) -> bool:\n            if len(self) == 0:\n                return False\n            return bool(int(self))\n\n    else:\n\n        def __bool__(self) -> bool:\n            if len(self) == 0:\n                return False\n            return any(bool(bit) for bit in self)\n\n    def resolve(self, resolver: ResolverLiteral) -> LogicArray:\n        \"\"\"Resolves non-0/1 values to 0/1.\n\n        The possible values of the *resolver* argument are:\n\n        * ``\"weak\"``:\n            Weak values are resolved to their strong-valued equivalents.\n\n        * ``\"zeros\"``:\n            ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively.\n            Remaining non-``0``/``1`` values are resolved to ``0``.\n\n        * ``\"ones\"``:\n            ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively.\n            Remaining non-``0``/``1`` values are resolved to ``1``.\n\n        * ``\"random\"``:\n            ``L`` and ``H`` are resolved to ``0`` and ``1``, respectively.\n            Remaining non-``0``/``1`` values are randomly resolved to either ``0`` or ``1``.\n\n        Args:\n            resolver: How to resolve non-``0``/``1`` values. See possible values above.\n\n        Returns:\n            The resolved Logic.\n\n        Raises:\n            ValueError: Invalid *resolver* value.\n            TypeError: Unsupported *value* type.\n        \"\"\"\n        return LogicArray(get_str_resolver(resolver)(str(self)), self.range)\n\n    def __copy__(self) -> LogicArray:\n        raise NotImplementedError(\"`copy.copy` on LogicArray is not supported\")\n\n    def __deepcopy__(self, memo: dict[int, Any]) -> LogicArray:\n        res = LogicArray.__new__(LogicArray)\n        res._value_as_array = copy.deepcopy(self._value_as_array, memo=memo)\n        res._value_as_int = self._value_as_int\n        res._value_as_str = self._value_as_str\n        res._range = copy.deepcopy(self._range, memo=memo)\n        res._warn_indexing = self._warn_indexing\n        return res\n\n    def __format__(self, spec: str, /) -> str:\n        if not spec:\n            return str(self)\n\n        base_len = 0\n        alternate = \"\"\n        if spec.startswith(\"#\"):\n            alternate, spec = spec[0], spec[1:]\n            # length operator doesn't take alternate format's effect on overall length into account\n            base_len = 2\n\n        grouping = \"\"\n        if spec.startswith((\"_\", \",\")):\n            grouping, spec = spec[0], spec[1:]\n\n        if spec == \"b\":\n            bin_len = len(self)\n            # length operator doesn't take grouping's effect on overall length into account\n            if grouping:\n                bin_len += (bin_len - 1) // 4\n            bin_len += base_len\n            # length operator doesn't take alternate format's and grouping's effect on overall length into account\n            return f\"{int(self):{alternate}0{bin_len}{grouping}b}\"\n        elif spec in {\"x\", \"X\"}:\n            # fast ceil(len(self) / 4)\n            hex_len = (len(self) + 3) // 4\n            # length operator doesn't take grouping's affect on overall length into account\n            if grouping:\n                hex_len += (hex_len - 1) // 4\n            hex_len += base_len\n            return f\"{int(self):{alternate}0{hex_len}{grouping}{spec}}\"\n        elif spec == \"d\":\n            # fast ceil(len(self) / 10)\n            dec_len = (len(self) + 9) // 10\n            # length operator doesn't take grouping's effect on overall length into account\n            if grouping:\n                dec_len += (dec_len - 1) // 3\n            dec_len += base_len\n            # integer alternate form for \"d\" doesn't add any prefix, but we need it to\n            # ensure people know it isn't hex or octal.\n            if alternate:\n                alternate = \"0d\"\n            return f\"{alternate}{int(self):0{dec_len}{grouping}d}\"\n        elif spec == \"o\":\n            # fast ceil(len(self) / 8)\n            oct_len = (len(self) + 2) // 3\n            oct_len += base_len\n            # length operator doesn't take grouping's effect on overall length into account\n            if grouping:\n                oct_len += (oct_len - 1) // 4\n            return f\"{int(self):{alternate}0{oct_len}{grouping}o}\"\n        else:\n            raise ValueError(f\"Unsupported format specifier: {spec!r}\")\n"
  },
  {
    "path": "src/cocotb/types/_range.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport copy\nfrom collections.abc import Iterator, Sequence\nfrom functools import cache\nfrom typing import Any, overload\n\n\nclass Range(Sequence[int]):\n    r\"\"\"\n    Variant of :class:`range` with inclusive right bound.\n\n    In Python, :class:`range` and :class:`slice` have a non-inclusive right bound.\n    In both Verilog and VHDL, ranges and arrays have an inclusive right bound.\n    This type mimics Python's :class:`range` type, but implements HDL-like inclusive right bounds,\n    using the names :attr:`left` and :attr:`right` as replacements for ``start`` and ``stop`` to\n    match VHDL.\n    Range directionality can be specified using ``'to'`` or ``'downto'`` between the\n    left and right bounds.\n    Not specifying directionality will cause the directionality to be inferred.\n\n    .. code-block:: pycon3\n\n        >>> r = Range(-2, 3)\n        >>> r.left, r.right, len(r)\n        (-2, 3, 6)\n\n        >>> s = Range(8, \"downto\", 1)\n        >>> s.left, s.right, len(s)\n        (8, 1, 8)\n\n    :meth:`from_range` and :meth:`to_range` can be used to convert from and to :class:`range`.\n\n    .. code-block:: pycon3\n\n        >>> r = Range(-2, 3)\n        >>> r.to_range()\n        range(-2, 4)\n\n    :class:`Range` supports \"null\" ranges as seen in VHDL.\n    \"null\" ranges occur when a left bound cannot reach a right bound with the given direction.\n    They have a length of ``0``, but the :attr:`left`, :attr:`right`, and :attr:`direction` values remain as given.\n\n    .. code-block:: pycon3\n\n        >>> r = Range(1, \"to\", 0)  # no way to count from 1 'to' 0\n        >>> r.left, r.direction, r.right\n        (1, 'to', 0)\n        >>> len(r)\n        0\n\n    .. note::\n        This is only possible when specifying the direction.\n\n    Ranges also support all the features of :class:`range` including, but not limited to:\n\n    - ``value in range`` to see if a value is in the range,\n    - ``range.index(value)`` to see what position in the range the value is,\n\n    The typical use case of this type is in conjunction with :class:`~cocotb.types.Array`.\n\n    Args:\n        left: Leftmost bound of range.\n        direction: ``'to'`` if values are ascending, ``'downto'`` if descending.\n        right: Rightmost bound of range (inclusive).\n    \"\"\"\n\n    @overload\n    def __init__(self, left: int, direction: int) -> None: ...\n\n    @overload\n    def __init__(self, left: int, direction: str, right: int) -> None: ...\n\n    @overload\n    def __init__(self, left: int, *, right: int) -> None: ...\n\n    def __init__(\n        self,\n        left: int,\n        direction: int | str | None = None,\n        right: int | None = None,\n    ) -> None:\n        start = left\n        stop: int\n        step: int\n        if isinstance(direction, int) and right is None:\n            step = _guess_step(left, direction)\n            stop = direction + step\n        elif isinstance(direction, str) and isinstance(right, int):\n            step = _direction_to_step(direction)\n            stop = right + step\n        elif direction is None and isinstance(right, int):\n            step = _guess_step(left, right)\n            stop = right + step\n        else:\n            raise TypeError(\"invalid arguments\")\n        self._range = range(start, stop, step)\n\n    @classmethod\n    def from_range(cls, range: range) -> Range:\n        \"\"\"Convert :class:`range` to :class:`Range`.\"\"\"\n        return cls(\n            left=range.start,\n            direction=_step_to_direction(range.step),\n            right=(range.stop - range.step),\n        )\n\n    def to_range(self) -> range:\n        \"\"\"Convert Range to :class:`range`.\"\"\"\n        return self._range\n\n    @property\n    def left(self) -> int:\n        \"\"\"Leftmost value in a Range.\"\"\"\n        return self._range.start\n\n    @property\n    def direction(self) -> str:\n        \"\"\"``'to'`` if Range is ascending, ``'downto'`` otherwise.\"\"\"\n        return _step_to_direction(self._range.step)\n\n    @property\n    def right(self) -> int:\n        \"\"\"Rightmost value in a Range.\"\"\"\n        return self._range.stop - self._range.step\n\n    def __len__(self) -> int:\n        return len(self._range)\n\n    @overload\n    def __getitem__(self, item: int) -> int: ...\n\n    @overload\n    def __getitem__(self, item: slice) -> Range: ...\n\n    def __getitem__(self, item: int | slice) -> int | Range:\n        if isinstance(item, int):\n            return self._range[item]\n        elif isinstance(item, slice):\n            return type(self).from_range(self._range[item])\n        raise TypeError(\n            f\"indices must be integers or slices, not {type(item).__name__}\"\n        )\n\n    def __contains__(self, item: object) -> bool:\n        return item in self._range\n\n    def __iter__(self) -> Iterator[int]:\n        return iter(self._range)\n\n    def __reversed__(self) -> Iterator[int]:\n        return reversed(self._range)\n\n    def __eq__(self, other: object) -> bool:\n        if isinstance(other, type(self)):\n            return self._range == other._range\n        return NotImplemented  # must not be in a type narrowing context to be ignored properly\n\n    def __hash__(self) -> int:\n        return hash(self._range)\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}({self.left!r}, {self.direction!r}, {self.right!r})\"\n\n    def index(\n        self, value: Any, start: int | None = None, stop: int | None = None, /\n    ) -> int:\n        if start is not None or stop is not None:\n            if start is None:\n                start = self._range.start\n            if stop is None:\n                stop = self._range.stop\n            return super().index(value, start, stop)\n        return self._range.index(value)\n\n    def __copy__(self) -> Range:\n        return Range.from_range(self._range)\n\n    def __deepcopy__(self, memo: dict[int, Any]) -> Range:\n        return Range.from_range(copy.deepcopy(self._range, memo=memo))\n\n\ndef _guess_step(left: int, right: int) -> int:\n    if left <= right:\n        return 1\n    return -1\n\n\n@cache\ndef _direction_to_step(direction: str) -> int:\n    direction = direction.lower()\n    if direction == \"to\":\n        return 1\n    elif direction == \"downto\":\n        return -1\n    raise ValueError(\"direction must be 'to' or 'downto'\")\n\n\ndef _step_to_direction(step: int) -> str:\n    if step == 1:\n        return \"to\"\n    elif step == -1:\n        return \"downto\"\n    raise ValueError(\"step must be 1 or -1\")\n"
  },
  {
    "path": "src/cocotb/types/_resolve.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport sys\nfrom functools import cache\nfrom random import Random\nfrom typing import Callable, Final, Literal, cast\n\nfrom cocotb_tools import _env\n\nif sys.version_info >= (3, 10):\n    from typing import TypeAlias\n\nResolverLiteral: TypeAlias = Literal[\"weak\", \"zeros\", \"ones\", \"random\"]\n\n\n_randomResolveRng = Random()\n\n_01lookup = (\"0\", \"1\")\n\n\nclass _random_resolve_table(dict[str, str]):\n    def __init__(self) -> None:\n        self[\"0\"] = \"0\"\n        self[\"1\"] = \"1\"\n        self[\"L\"] = \"0\"\n        self[\"H\"] = \"1\"\n\n    def __missing__(self, _: str) -> str:\n        return _01lookup[_randomResolveRng.getrandbits(1)]\n\n\n_rnd_table = _random_resolve_table()\n\n\n_resolve_tables: dict[str, dict[int, int]] = {\n    \"error\": {},\n    \"weak\": str.maketrans(\"LHW\", \"01X\"),\n    \"zeros\": str.maketrans(\"LHUXZW-\", \"0100000\"),\n    \"ones\": str.maketrans(\"LHUXZW-\", \"0111111\"),\n}\n\n_VALID_RESOLVERS = (\"error\", \"weak\", \"zeros\", \"ones\", \"random\")\n_VALID_RESOLVERS_ERR_MSG = (\n    \"Valid values are 'error', 'weak', 'zeros', 'ones', or 'random'\"\n)\n\n\n@cache\ndef get_str_resolver(resolver: ResolverLiteral) -> Callable[[str], str]:\n    if resolver not in _VALID_RESOLVERS:\n        raise ValueError(f\"Invalid resolver: {resolver!r}. {_VALID_RESOLVERS_ERR_MSG}\")\n\n    if resolver == \"random\":\n        # Can't use str.translate for random resolving as it assumes that the mapping\n        # will not change over the course of the call.\n        def resolve_func(value: str) -> str:\n            return \"\".join(map(_rnd_table.__getitem__, value))\n\n    else:\n        resolve_table = _resolve_tables[resolver]\n\n        def resolve_func(value: str) -> str:\n            return value.translate(resolve_table)\n\n    return resolve_func\n\n\ndef _init() -> Callable[[str], str] | None:\n    resolver = _env.as_str(\"COCOTB_RESOLVE_X\").lower()\n\n    # no resolver\n    if not resolver:\n        return None\n\n    # backwards compatibility\n    if resolver == \"value_error\":\n        resolver = \"error\"\n\n    # get resolver\n    try:\n        return get_str_resolver(cast(\"ResolverLiteral\", resolver))\n    except ValueError:\n        raise ValueError(\n            f\"Invalid COCOTB_RESOLVE_X value: {resolver!r}. {_VALID_RESOLVERS_ERR_MSG}\"\n        ) from None\n\n\nRESOLVE_X: Final = _init()\n"
  },
  {
    "path": "src/cocotb/utils.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Tools for dealing with simulated time.\"\"\"\n\nfrom __future__ import annotations\n\nimport warnings\nfrom decimal import Decimal\nfrom fractions import Fraction\n\nfrom cocotb.simtime import (\n    RoundMode,\n    TimeUnit,\n    _get_sim_steps,\n    _get_time_from_sim_steps,\n    get_sim_time,\n)\n\n__all__ = (\n    \"get_sim_steps\",\n    \"get_sim_time\",\n    \"get_time_from_sim_steps\",\n)\n\n\ndef get_time_from_sim_steps(\n    steps: int,\n    unit: TimeUnit | None = None,\n    *,\n    units: None = None,\n) -> float:\n    \"\"\"Calculate simulation time in the specified *unit* from the *steps* based\n    on the simulator precision.\n\n    Args:\n        steps: Number of simulation steps.\n        unit: String specifying the unit of the result\n            (one of ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).\n\n            .. versionchanged:: 2.0\n                Renamed from ``units``.\n\n    Raises:\n        ValueError: If *unit* is not a valid unit.\n\n    Returns:\n        The simulation time in the specified unit.\n    \"\"\"\n    if units is not None:\n        warnings.warn(\n            \"The 'units' argument has been renamed to 'unit'.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        unit = units\n    if unit is None:\n        raise TypeError(\"Missing required argument 'unit'\")\n    return _get_time_from_sim_steps(steps, unit)\n\n\ndef get_sim_steps(\n    time: float | Fraction | Decimal,\n    unit: TimeUnit = \"step\",\n    *,\n    round_mode: RoundMode = \"error\",\n    units: None = None,\n) -> int:\n    \"\"\"Calculates the number of simulation time steps for a given amount of *time*.\n\n    When *round_mode* is ``\"error\"``, a :exc:`ValueError` is thrown if the value cannot\n    be accurately represented in terms of simulator time steps.\n    When *round_mode* is ``\"round\"``, ``\"ceil\"``, or ``\"floor\"``, the corresponding\n    rounding function from the standard library will be used to round to a simulator\n    time step.\n\n    Args:\n        time: The value to convert to simulation time steps.\n        unit: String specifying the unit of the result\n            (one of ``'step'``, ``'fs'``, ``'ps'``, ``'ns'``, ``'us'``, ``'ms'``, ``'sec'``).\n            ``'step'`` means *time* is already in simulation time steps.\n\n            .. versionchanged:: 2.0\n                Renamed from ``units``.\n\n        round_mode: String specifying how to handle time values that sit between time steps\n            (one of ``'error'``, ``'round'``, ``'ceil'``, ``'floor'``).\n\n    Returns:\n        The number of simulation time steps.\n\n    Raises:\n        ValueError: if the value cannot be represented accurately in terms of simulator\n            time steps when *round_mode* is ``\"error\"``.\n\n    .. versionchanged:: 1.5\n        Support ``'step'`` as the *unit* argument to mean \"simulator time step\".\n\n    .. versionchanged:: 1.6\n        Support rounding modes.\n    \"\"\"\n    if units is not None:\n        warnings.warn(\n            \"The 'units' argument has been renamed to 'unit'.\",\n            DeprecationWarning,\n            stacklevel=2,\n        )\n        unit = units\n    return _get_sim_steps(time, unit, round_mode=round_mode)\n"
  },
  {
    "path": "src/cocotb_tools/__init__.py",
    "content": ""
  },
  {
    "path": "src/cocotb_tools/_coverage.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom cocotb_tools import _env\n\n\ndef start_cocotb_library_coverage() -> None:  # pragma: no cover\n    if not _env.as_bool(\"COCOTB_LIBRARY_COVERAGE\"):\n        return\n    try:\n        import coverage  # noqa: PLC0415\n    except (ImportError, ModuleNotFoundError):\n        raise RuntimeError(\n            \"cocotb library coverage collection requested but coverage package not available. Install it using `pip install coverage`.\"\n        ) from None\n    else:\n        library_coverage = coverage.coverage(\n            data_file=\".coverage.cocotb\",\n            config_file=False,\n            branch=True,\n            source=[\"cocotb\"],\n        )\n        library_coverage.load()\n        library_coverage.start()\n\n        def stop_library_coverage() -> None:\n            library_coverage.stop()\n            library_coverage.save()  # pragma: no cover\n\n        # This must come after `library_coverage.start()` to ensure coverage is being\n        # collected on the cocotb library before importing from it.\n        import cocotb._shutdown  # noqa: PLC0415\n\n        cocotb._shutdown.register(stop_library_coverage)\n"
  },
  {
    "path": "src/cocotb_tools/_env.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Handling environment variables in a consistent and unified way.\"\"\"\n\nfrom __future__ import annotations\n\nimport os\nimport shlex\nfrom collections.abc import Iterable\nfrom pathlib import Path\n\nTRUE: tuple[str, ...] = (\"1\", \"yes\", \"y\", \"on\", \"true\", \"enable\")\n\"\"\"List of expected values for environment variable to be evaluated as True.\"\"\"\n\nFALSE: tuple[str, ...] = (\"0\", \"no\", \"n\", \"off\", \"false\", \"disable\")\n\"\"\"List of expected values for environment variable to be evaluated as False.\"\"\"\n\n\ndef exists(name: str) -> bool:\n    \"\"\"Check if environment variable was defined.\n\n    Args:\n        name: Name of environment variable.\n\n    Returns:\n        True if environment variable was defined. Otherwise False.\n    \"\"\"\n    return name in os.environ\n\n\ndef as_str(name: str, default: str | None = None) -> str:\n    \"\"\"Convert value of environment variable to Python string type.\n\n    Args:\n        name: Name of environment variable.\n        default: Default value of environment variable.\n\n    Returns:\n        Stripped string of environment variable.\n    \"\"\"\n    return os.environ.get(name, \"\").strip() or default or \"\"\n\n\ndef as_bool(name: str, default: bool | None = None) -> bool:\n    \"\"\"Convert value of environment variable to Python boolean type.\n\n    Function is case-insensitive.\n\n    Args:\n        name: Name of environment variable.\n        default: Default value of environment variable.\n\n    Returns:\n        :data:`True` if the environment variable is ``1``, ``yes``, ``y``, ``on``, ``true`` or ``enable``.\n        :data:`False` if the environment variable is ``0``, ``no``, ``n``, ``off``, ``false`` or ``disable``.\n        Default value if environment variable was not set or is empty.\n\n    Raises:\n        :exc:`ValueError` in case of an unexpected value.\n    \"\"\"\n    envvar: str = as_str(name)  # Keep original case for ValueError\n    value: str = envvar.lower()\n\n    if not value:\n        return default or False\n\n    if value in TRUE:\n        return True\n\n    if value in FALSE:\n        return False\n\n    raise ValueError(\n        f\"Unexpected value {envvar!r} for environment variable: {name!r}. \"\n        f\"Expecting one of {(*TRUE,)} or {(*FALSE,)} (case-insensitive)\"\n    )\n\n\ndef as_list(\n    name: str, default: Iterable[str] | None = None, separator: str = \",\"\n) -> list[str]:\n    \"\"\"Convert value of environment variable to Python list of strings type.\n\n    Values by default are comma (``,``) separated.\n\n    Args:\n        name: Name of environment variable.\n        default: Default value of environment variable.\n        separator: Used separator between values.\n\n    Returns:\n        List of stripped and non-empty strings.\n    \"\"\"\n    items: list[str] = list(filter(None, map(str.strip, as_str(name).split(separator))))\n\n    return list(items or default or ())\n\n\ndef as_int(name: str, default: int | None = None) -> int:\n    \"\"\"Convert value of environment variable to Python integer type.\n\n    Args:\n        name: Name of environment variable.\n        default: Default value of environment variable.\n\n    Returns:\n        Integer. If value was not set, it will return zero (0).\n    \"\"\"\n    return int(as_str(name) or default or 0)\n\n\ndef as_path(name: str, default: Path | str | None = None) -> Path:\n    \"\"\"Convert value of environment variable to Python path type.\n\n    Args:\n        name: Name of environment variable.\n        default: Default value of environment variable.\n\n    Returns:\n        The resolved path. If not set, the current working directory will be returned.\n    \"\"\"\n    return Path(as_str(name) or default or \"\").resolve()\n\n\ndef as_args(name: str, default: str | None = None) -> list[str]:\n    \"\"\"Convert value of environment variable to list of arguments respecting shell syntax.\n\n    Args:\n        name: Name of environment variable.\n        default: Default value of environment variable.\n\n    Returns:\n        List of arguments split based on shell syntax.\n    \"\"\"\n    return shlex.split(as_str(name) or default or \"\")\n"
  },
  {
    "path": "src/cocotb_tools/_vendor/README.md",
    "content": "# Vendored libraries to support cocotb_tools\n\n### distutils_version.py\n\nOriginally from distutils.py from CPython, vendored in on 2021-09-23.\nNeeded to support `cocotb_tools.sim_versions`.\nUpstream CPython removed `distutils.py`.\n"
  },
  {
    "path": "src/cocotb_tools/_vendor/__init__.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n"
  },
  {
    "path": "src/cocotb_tools/_vendor/distutils_version.py",
    "content": "# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,\n# 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation;\n# All Rights Reserved\n# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n#\n# distutils/version.py\n#\n# Implements multiple version numbering conventions for the\n# Python Module Distribution Utilities.\n#\n# $Id$\n#\n\n\"\"\"Provides classes to represent module version numbers (one class for\neach style of version numbering).  There are currently two such classes\nimplemented: StrictVersion and LooseVersion.\nEvery version number class implements the following interface:\n  * the 'parse' method takes a string and parses it to some internal\n    representation; if the string is an invalid version number,\n    'parse' raises a ValueError exception\n  * the class constructor takes an optional string argument which,\n    if supplied, is passed to 'parse'\n  * __str__ reconstructs the string that was passed to 'parse' (or\n    an equivalent string -- ie. one that will generate an equivalent\n    version number instance)\n  * __repr__ generates Python code to recreate the version number instance\n  * _cmp compares the current instance with either another instance\n    of the same class or a string (which will be parsed to an instance\n    of the same class, thus must follow the same rules)\n\"\"\"\n\nimport re\n\nclass Version:\n    \"\"\"Abstract base class for version numbering classes.  Just provides\n    constructor (__init__) and reproducer (__repr__), because those\n    seem to be the same for all version numbering classes; and route\n    rich comparisons to _cmp.\n    \"\"\"\n\n    def __init__ (self, vstring=None):\n        if vstring:\n            self.parse(vstring)\n\n    def __repr__ (self):\n        return \"%s ('%s')\" % (self.__class__.__name__, str(self))\n\n    def __eq__(self, other):\n        c = self._cmp(other)\n        if c is NotImplemented:\n            return c\n        return c == 0\n\n    def __lt__(self, other):\n        c = self._cmp(other)\n        if c is NotImplemented:\n            return c\n        return c < 0\n\n    def __le__(self, other):\n        c = self._cmp(other)\n        if c is NotImplemented:\n            return c\n        return c <= 0\n\n    def __gt__(self, other):\n        c = self._cmp(other)\n        if c is NotImplemented:\n            return c\n        return c > 0\n\n    def __ge__(self, other):\n        c = self._cmp(other)\n        if c is NotImplemented:\n            return c\n        return c >= 0\n\n\n# Interface for version-number classes -- must be implemented\n# by the following classes (the concrete ones -- Version should\n# be treated as an abstract class).\n#    __init__ (string) - create and take same action as 'parse'\n#                        (string parameter is optional)\n#    parse (string)    - convert a string representation to whatever\n#                        internal representation is appropriate for\n#                        this style of version numbering\n#    __str__ (self)    - convert back to a string; should be very similar\n#                        (if not identical to) the string supplied to parse\n#    __repr__ (self)   - generate Python code to recreate\n#                        the instance\n#    _cmp (self, other) - compare two version numbers ('other' may\n#                        be an unparsed version string, or another\n#                        instance of your version class)\n\n\nclass StrictVersion (Version):\n\n    \"\"\"Version numbering for anal retentives and software idealists.\n    Implements the standard interface for version number classes as\n    described above.  A version number consists of two or three\n    dot-separated numeric components, with an optional \"pre-release\" tag\n    on the end.  The pre-release tag consists of the letter 'a' or 'b'\n    followed by a number.  If the numeric components of two version\n    numbers are equal, then one with a pre-release tag will always\n    be deemed earlier (lesser) than one without.\n    The following are valid version numbers (shown in the order that\n    would be obtained by sorting according to the supplied cmp function):\n        0.4       0.4.0  (these two are equivalent)\n        0.4.1\n        0.5a1\n        0.5b3\n        0.5\n        0.9.6\n        1.0\n        1.0.4a3\n        1.0.4b1\n        1.0.4\n    The following are examples of invalid version numbers:\n        1\n        2.7.2.2\n        1.3.a4\n        1.3pl1\n        1.3c4\n    The rationale for this version numbering system will be explained\n    in the distutils documentation.\n    \"\"\"\n\n    version_re = re.compile(r'^(\\d+) \\. (\\d+) (\\. (\\d+))? ([ab](\\d+))?$',\n                            re.VERBOSE | re.ASCII)\n\n\n    def parse (self, vstring):\n        match = self.version_re.match(vstring)\n        if not match:\n            raise ValueError(\"invalid version number '%s'\" % vstring)\n\n        (major, minor, patch, prerelease, prerelease_num) = \\\n            match.group(1, 2, 4, 5, 6)\n\n        if patch:\n            self.version = tuple(map(int, [major, minor, patch]))\n        else:\n            self.version = tuple(map(int, [major, minor])) + (0,)\n\n        if prerelease:\n            self.prerelease = (prerelease[0], int(prerelease_num))\n        else:\n            self.prerelease = None\n\n\n    def __str__ (self):\n\n        if self.version[2] == 0:\n            vstring = '.'.join(map(str, self.version[0:2]))\n        else:\n            vstring = '.'.join(map(str, self.version))\n\n        if self.prerelease:\n            vstring = vstring + self.prerelease[0] + str(self.prerelease[1])\n\n        return vstring\n\n\n    def _cmp (self, other):\n        if isinstance(other, str):\n            other = StrictVersion(other)\n        elif not isinstance(other, StrictVersion):\n            return NotImplemented\n\n        if self.version != other.version:\n            # numeric versions don't match\n            # prerelease stuff doesn't matter\n            if self.version < other.version:\n                return -1\n            else:\n                return 1\n\n        # have to compare prerelease\n        # case 1: neither has prerelease; they're equal\n        # case 2: self has prerelease, other doesn't; other is greater\n        # case 3: self doesn't have prerelease, other does: self is greater\n        # case 4: both have prerelease: must compare them!\n\n        if (not self.prerelease and not other.prerelease):\n            return 0\n        elif (self.prerelease and not other.prerelease):\n            return -1\n        elif (not self.prerelease and other.prerelease):\n            return 1\n        elif (self.prerelease and other.prerelease):\n            if self.prerelease == other.prerelease:\n                return 0\n            elif self.prerelease < other.prerelease:\n                return -1\n            else:\n                return 1\n        else:\n            assert False, \"never get here\"\n\n# end class StrictVersion\n\n\n# The rules according to Greg Stein:\n# 1) a version number has 1 or more numbers separated by a period or by\n#    sequences of letters. If only periods, then these are compared\n#    left-to-right to determine an ordering.\n# 2) sequences of letters are part of the tuple for comparison and are\n#    compared lexicographically\n# 3) recognize the numeric components may have leading zeroes\n#\n# The LooseVersion class below implements these rules: a version number\n# string is split up into a tuple of integer and string components, and\n# comparison is a simple tuple comparison.  This means that version\n# numbers behave in a predictable and obvious way, but a way that might\n# not necessarily be how people *want* version numbers to behave.  There\n# wouldn't be a problem if people could stick to purely numeric version\n# numbers: just split on period and compare the numbers as tuples.\n# However, people insist on putting letters into their version numbers;\n# the most common purpose seems to be:\n#   - indicating a \"pre-release\" version\n#     ('alpha', 'beta', 'a', 'b', 'pre', 'p')\n#   - indicating a post-release patch ('p', 'pl', 'patch')\n# but of course this can't cover all version number schemes, and there's\n# no way to know what a programmer means without asking him.\n#\n# The problem is what to do with letters (and other non-numeric\n# characters) in a version number.  The current implementation does the\n# obvious and predictable thing: keep them as strings and compare\n# lexically within a tuple comparison.  This has the desired effect if\n# an appended letter sequence implies something \"post-release\":\n# eg. \"0.99\" < \"0.99pl14\" < \"1.0\", and \"5.001\" < \"5.001m\" < \"5.002\".\n#\n# However, if letters in a version number imply a pre-release version,\n# the \"obvious\" thing isn't correct.  Eg. you would expect that\n# \"1.5.1\" < \"1.5.2a2\" < \"1.5.2\", but under the tuple/lexical comparison\n# implemented here, this just isn't so.\n#\n# Two possible solutions come to mind.  The first is to tie the\n# comparison algorithm to a particular set of semantic rules, as has\n# been done in the StrictVersion class above.  This works great as long\n# as everyone can go along with bondage and discipline.  Hopefully a\n# (large) subset of Python module programmers will agree that the\n# particular flavour of bondage and discipline provided by StrictVersion\n# provides enough benefit to be worth using, and will submit their\n# version numbering scheme to its domination.  The free-thinking\n# anarchists in the lot will never give in, though, and something needs\n# to be done to accommodate them.\n#\n# Perhaps a \"moderately strict\" version class could be implemented that\n# lets almost anything slide (syntactically), and makes some heuristic\n# assumptions about non-digits in version number strings.  This could\n# sink into special-case-hell, though; if I was as talented and\n# idiosyncratic as Larry Wall, I'd go ahead and implement a class that\n# somehow knows that \"1.2.1\" < \"1.2.2a2\" < \"1.2.2\" < \"1.2.2pl3\", and is\n# just as happy dealing with things like \"2g6\" and \"1.13++\".  I don't\n# think I'm smart enough to do it right though.\n#\n# In any case, I've coded the test suite for this module (see\n# ../test/test_version.py) specifically to fail on things like comparing\n# \"1.2a2\" and \"1.2\".  That's not because the *code* is doing anything\n# wrong, it's because the simple, obvious design doesn't match my\n# complicated, hairy expectations for real-world version numbers.  It\n# would be a snap to fix the test suite to say, \"Yep, LooseVersion does\n# the Right Thing\" (ie. the code matches the conception).  But I'd rather\n# have a conception that matches common notions about version numbers.\n\nclass LooseVersion (Version):\n\n    \"\"\"Version numbering for anarchists and software realists.\n    Implements the standard interface for version number classes as\n    described above.  A version number consists of a series of numbers,\n    separated by either periods or strings of letters.  When comparing\n    version numbers, the numeric components will be compared\n    numerically, and the alphabetic components lexically.  The following\n    are all valid version numbers, in no particular order:\n        1.5.1\n        1.5.2b2\n        161\n        3.10a\n        8.02\n        3.4j\n        1996.07.12\n        3.2.pl0\n        3.1.1.6\n        2g6\n        11g\n        0.960923\n        2.2beta29\n        1.13++\n        5.5.kw\n        2.0b1pl0\n    In fact, there is no such thing as an invalid version number under\n    this scheme; the rules for comparison are simple and predictable,\n    but may not always give the results you want (for some definition\n    of \"want\").\n    \"\"\"\n\n    component_re = re.compile(r'(\\d+ | [a-z]+ | \\.)', re.VERBOSE)\n\n    def __init__ (self, vstring=None):\n        if vstring:\n            self.parse(vstring)\n\n\n    def parse (self, vstring):\n        # I've given up on thinking I can reconstruct the version string\n        # from the parsed tuple -- so I just store the string here for\n        # use by __str__\n        self.vstring = vstring\n        components = [x for x in self.component_re.split(vstring)\n                              if x and x != '.']\n        for i, obj in enumerate(components):\n            try:\n                components[i] = int(obj)\n            except ValueError:\n                pass\n\n        self.version = components\n\n\n    def __str__ (self):\n        return self.vstring\n\n\n    def __repr__ (self):\n        return \"LooseVersion ('%s')\" % str(self)\n\n\n    def _cmp (self, other):\n        if isinstance(other, str):\n            other = LooseVersion(other)\n        elif not isinstance(other, LooseVersion):\n            return NotImplemented\n\n        if self.version == other.version:\n            return 0\n        if self.version < other.version:\n            return -1\n        if self.version > other.version:\n            return 1\n\n\n# end class LooseVersion\n"
  },
  {
    "path": "src/cocotb_tools/check_results.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"Checks if a JUnit results file exists and whether there was failing tests.\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport sys\nfrom pathlib import Path\nfrom xml.etree import ElementTree\n\n\ndef get_results(results_xml_file: Path) -> tuple[int, int]:\n    \"\"\"Return number of tests and fails in *results_xml_file*.\n\n    Returns:\n        Tuple of number of tests and number of fails.\n\n    Raises:\n        RuntimeError: If *results_xml_file* is non-existent.\n    \"\"\"\n\n    __tracebackhide__ = True  # Hide the traceback when using PyTest.\n\n    if not results_xml_file.is_file():\n        raise RuntimeError(\n            f\"ERROR: Simulation terminated abnormally. Results file {results_xml_file} not found.\"\n        )\n\n    # pytest --junit-xml=<file> is generating proper JUnit XML report file\n    # It is using errors attribute as indicator for failed tests without execution but\n    # also as indicator for failed pytest (invalid arguments, configuration, setup, ...)\n    num_tests = 0\n    num_failed = 0  # Failed tests during execution (including setup and call)\n    num_errors = 0  # Errors in pytest configuration, fixtures, setup, tests\n\n    tree = ElementTree.parse(results_xml_file)\n    for ts in tree.iter(\"testsuite\"):\n        if \"tests\" in ts.attrib:  # pytest, compatible with JUnit XML specification\n            num_tests += int(ts.attrib.get(\"tests\", 0))\n            num_failed += int(ts.attrib.get(\"failures\", 0))\n            num_errors += int(ts.attrib.get(\"errors\", 0))\n\n        else:  # cocotb, non-compatible with Junit XML specification\n            # TODO: Remove that when XUnitReporter will be aligned with XUnit schema\n            for tc in ts.iter(\"testcase\"):\n                num_tests += 1\n                for _ in tc.iter(\"failure\"):\n                    num_failed += 1\n\n    return (num_tests, num_failed + num_errors)\n\n\ndef _get_parser() -> argparse.ArgumentParser:\n    \"\"\"Return the cmdline parser\"\"\"\n    parser = argparse.ArgumentParser(description=__doc__)\n    parser.add_argument(\n        \"results_file\", help=\"Path to XML file holding JUnit test results.\", type=Path\n    )\n    return parser\n\n\ndef main() -> int:\n    parser = _get_parser()\n    args = parser.parse_args()\n\n    try:\n        (_, num_failed) = get_results(args.results_file)\n    except RuntimeError:\n        return 1\n    return num_failed\n\n\nif __name__ == \"__main__\":\n    rc = main()\n    sys.exit(rc)\n"
  },
  {
    "path": "src/cocotb_tools/combine_results.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n#!/usr/bin/env python\n\"\"\"\nSimple script to combine JUnit test results into a single XML file.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport os\nimport re\nimport sys\nfrom collections.abc import Iterable\nfrom pathlib import Path\nfrom re import Pattern\nfrom xml.etree import ElementTree as ET\n\n\ndef _find_all(name: Pattern, path: Path) -> Iterable[Path]:\n    for obj in path.iterdir():\n        if obj.is_file() and re.match(name, obj.name):\n            yield obj\n        elif obj.is_dir():\n            yield from _find_all(name, obj)\n\n\ndef _existing_path(path_str: str) -> Path:\n    path = Path(path_str)\n    if not path.exists():\n        raise argparse.ArgumentTypeError(f\"Path '{path_str}' does not exist.\")\n    return path\n\n\ndef _get_parser() -> argparse.ArgumentParser:\n    \"\"\"Return the cmdline parser\"\"\"\n    parser = argparse.ArgumentParser(\n        description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter\n    )\n    parser.add_argument(\n        \"directories\",\n        nargs=\"*\",\n        type=_existing_path,\n        default=[Path()],\n        help=\"Directories to search for input files.\",\n    )\n    parser.add_argument(\n        \"-i\",\n        \"--input-filename\",\n        default=r\"results.*\\.xml\",\n        help=\"A regular expression to match input filenames.\",\n    )\n    parser.add_argument(\n        \"-o\",\n        \"--output-file\",\n        default=\"combined_results.xml\",\n        help=\"Path of output XML file.\",\n    )\n    parser.add_argument(\n        \"--output-testsuites-name\",\n        default=\"results\",\n        help=\"Name of 'testsuites' element in output XML file.\",\n    )\n    parser.add_argument(\n        \"--verbose\",\n        action=\"store_true\",\n        help=\"Enables verbose output.\",\n    )\n    parser.add_argument(\n        \"--repo-root\",\n        type=Path,\n        help=\"Specify root of cocotb repo the regression is run from (CI only).\",\n    )\n    return parser\n\n\ndef main() -> int:\n    parser = _get_parser()\n    args = parser.parse_args()\n    rc = 0\n\n    result = ET.Element(\"testsuites\", name=args.output_testsuites_name)\n\n    input_pattern = re.compile(args.input_filename)\n\n    for directory in args.directories:\n        if args.verbose:\n            print(f\"Searching in {directory} for results.xml files.\")\n        for fname in _find_all(input_pattern, directory):\n            if args.verbose:\n                print(f\"Reading file {fname}.\")\n            tree = ET.parse(fname)\n            for ts in tree.iter(\"testsuite\"):\n                if args.verbose:\n                    print(\n                        \"Testsuite name: {!r}, package: {!r}\".format(\n                            ts.get(\"name\"), ts.get(\"package\")\n                        )\n                    )\n                for existing in result:\n                    if (existing.get(\"name\") == ts.get(\"name\")) and (\n                        existing.get(\"package\") == ts.get(\"package\")\n                    ):\n                        if args.verbose:\n                            print(\n                                \"Testsuite already exists in combined results. Extending it.\"\n                            )\n                        existing.extend(list(ts))\n                        break\n                else:\n                    if args.verbose:\n                        print(\n                            \"Testsuite does not already exist in combined results. Adding it.\"\n                        )\n                    result.append(ts)\n\n    testsuite_count = 0\n    testcase_count = 0\n    for testsuite in result.iter(\"testsuite\"):\n        testsuite_count += 1\n        for testcase in testsuite.iter(\"testcase\"):\n            testcase_count += 1\n            for _ in testcase.iter(\"failure\"):\n                rc = 1\n                print(\n                    \"Failure in testsuite: '{}' classname: '{}' testcase: '{}' with parameters '{}'\".format(\n                        testsuite.get(\"name\"),\n                        testcase.get(\"classname\"),\n                        testcase.get(\"name\"),\n                        testsuite.get(\"package\"),\n                    )\n                )\n                if (\n                    os.getenv(\"GITHUB_ACTIONS\") is not None\n                    and args.repo_root is not None\n                ):\n                    # Get test file relative to root of repo\n                    file = testcase.get(\"file\")\n                    # if this file was output by cocotb, it has this attribute\n                    assert file is not None\n                    relative_file = Path(file).relative_to(args.repo_root)\n                    print(\n                        \"::error file={},line={}::Test {}:{} failed\".format(\n                            relative_file,\n                            testcase.get(\"lineno\"),\n                            testcase.get(\"classname\"),\n                            testcase.get(\"name\"),\n                        )\n                    )\n\n    print(f\"Ran a total of {testsuite_count} TestSuites and {testcase_count} TestCases\")\n\n    if args.verbose:\n        print(f\"Writing combined results to {args.output_file}\")\n    ET.ElementTree(result).write(args.output_file, encoding=\"UTF-8\")\n    return rc\n\n\nif __name__ == \"__main__\":\n    rc = main()\n    sys.exit(rc)\n"
  },
  {
    "path": "src/cocotb_tools/config.py",
    "content": "#!/usr/bin/env python\n# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"\nModule for querying the cocotb configuration\n\nThis module provides information in module global variables and through a\n``main()`` function that is used in the cocotb-config script.\n\nGlobal variables:\n    share_dir: str, path where the cocotb data is stored\n    makefiles_dir: str, path where the cocotb makefiles are installed\n    libs_dir: str, path where the cocotb interface libraries are located\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport os\nimport sys\nimport textwrap\nfrom pathlib import Path\n\nimport find_libpython\n\nimport cocotb_tools\n\nbase_tools_dir = Path(cocotb_tools.__file__).parent.resolve()\nbase_cocotb_dir = (base_tools_dir.parent / \"cocotb\").resolve()\nif not (base_cocotb_dir.exists() and (base_cocotb_dir / \"libs\").exists()):\n    import cocotb\n\n    base_cocotb_dir = Path(cocotb.__file__).parent.resolve()\n\nshare_dir = base_cocotb_dir.joinpath(\"share\")\nlibs_dir = base_cocotb_dir.joinpath(\"libs\")\nmakefiles_dir = base_tools_dir.joinpath(\"makefiles\")\n\n\ndef _get_version() -> str:\n    import cocotb  # noqa: PLC0415\n\n    return cocotb.__version__\n\n\ndef _help_vars_text() -> str:\n    if \"dev\" in _get_version():\n        doclink = \"https://docs.cocotb.org/en/development/library_reference.html\"\n    else:\n        doclink = f\"https://docs.cocotb.org/en/v{_get_version()}/library_reference.html\"\n\n    # NOTE: make sure to keep \"helpmsg\" aligned with docs/source/library_reference.rst\n    helpmsg = textwrap.dedent(\n        \"\"\"\\\n        The following variables are environment variables:\n\n        cocotb\n        ------\n        COCOTB_TOPLEVEL          Instance in the hierarchy to use as the DUT\n        COCOTB_RANDOM_SEED       Random seed, to recreate a previous test stimulus\n        COCOTB_ANSI_OUTPUT       Force cocotb to print or not print in color\n        COCOTB_REDUCED_LOG_FMT   Display log lines shorter\n        COCOTB_LOG_PREFIX        Set custom log prefix (f-string format)\n        COCOTB_ATTACH            Pause time value in seconds before the simulator start\n        COCOTB_ENABLE_PROFILING  Performance analysis of the Python portion of cocotb\n        COCOTB_LOG_LEVEL         Default logging level (default INFO)\n        COCOTB_RESOLVE_X         How to resolve X, Z, U, W, - on integer conversion\n\n        Regression Manager\n        ------------------\n        COCOTB_PDB_ON_EXCEPTION  Drop into the Python debugger (pdb) on exception\n        COCOTB_TEST_MODULES      Module(s) to search for test functions (comma-separated)\n        COCOTB_TESTCASE          Test function(s) to run (Deprecated: Use COCOTB_TEST_FILTER)\n        COCOTB_TEST_FILTER       Regex used to match test function names\n        COCOTB_RESULTS_FILE      File name for xUnit XML tests results (default results.xml)\n        COCOTB_USER_COVERAGE     Collect Python user coverage (HDL for some simulators)\n        COVERAGE_RCFILE          Configuration for user code coverage\n        COCOTB_REWRITE_ASSERTION_FILES\n                                 Files to apply pytest assertion rewrites to (default *.py)\n        COCOTB_MAX_FAILURES      Maximum number of test failures before aborting the regression\n        COCOTB_LIST_TESTS        Prints all tests in the order they would be executed and exits\n        COCOTB_RANDOM_TEST_ORDER Enables randomizing the order of tests within each stage\n\n        Scheduler\n        ---------\n        COCOTB_SCHEDULER_DEBUG   Enable additional output of coroutine scheduler\n        COCOTB_TRUST_INERTIAL_WRITES\n                                 Trust inertial writes rather than mock them using scheduler\n\n        GPI\n        ---\n        GPI_USERS         List of user libraries to load after GPI is initialized\n        GPI_EXTRA         Extra libraries to load as part of GPI initialization\n        GPI_LOG_LEVEL     Default logging level for \"gpi\" loggers (default INFO)\n        GPI_DEBUG         Enable GPI debug features, including TRACE log output\n\n        PYGPI\n        -----\n        PYGPI_USERS       List of Python callables to start test environment\n        PYGPI_PYTHON_BIN  Python binary. Usually set automatically by test runner\n        PYGPI_DEBUG       Enable PyGPI debug features, including TRACE log output\n\n        For details, see {}\"\"\"\n    ).format(doclink)\n    return helpmsg\n\n\ndef pygpi_entry_point() -> str:\n    import cocotb.simulator  # noqa: PLC0415\n\n    return f\"{Path(cocotb.simulator.__file__).resolve()},initialize\"\n\n\ndef lib_name_path(interface: str, simulator: str) -> Path:\n    \"\"\"\n    Return the absolute path of interface library for given interface (VPI/VHPI/FLI) and simulator\n    \"\"\"\n\n    interface_name = interface.lower()\n    supported_interfaces = [\"vpi\", \"vhpi\", \"fli\"]\n    if interface_name not in supported_interfaces:\n        raise ValueError(\n            \"Wrong interface used. Supported: \" + \", \".join(supported_interfaces)\n        )\n\n    simulator_name = simulator.lower()\n    supported_sims = [\n        \"icarus\",\n        \"verilator\",\n        \"questa\",\n        \"modelsim\",\n        \"ius\",\n        \"xcelium\",\n        \"vcs\",\n        \"ghdl\",\n        \"riviera\",\n        \"activehdl\",\n        \"cvc\",\n        \"nvc\",\n        \"dsim\",\n    ]\n    if simulator not in supported_sims:\n        raise ValueError(\n            \"Wrong simulator name. Supported: \" + \", \".join(supported_sims)\n        )\n\n    if simulator_name in [\"questa\", \"cvc\"]:\n        library_name = \"modelsim\"\n    elif simulator_name == \"xcelium\":\n        library_name = \"ius\"\n    elif simulator_name in [\"riviera\", \"activehdl\"]:\n        library_name = \"aldec\"\n    else:\n        library_name = simulator_name\n\n    if os.name == \"nt\":\n        lib_ext = \".dll\"\n    else:\n        lib_ext = \".so\"\n\n    # check if compiled with msvc\n    if (libs_dir / \"gpi.dll\").is_file():\n        lib_prefix = \"\"\n    else:\n        lib_prefix = \"lib\"\n\n    lib_name = f\"{lib_prefix}cocotb{interface_name}_{library_name}{lib_ext}\"\n    return libs_dir / lib_name\n\n\ndef _get_parser() -> argparse.ArgumentParser:\n    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)\n\n    group = parser.add_mutually_exclusive_group()\n    group.add_argument(\n        \"--share\",\n        action=\"store_true\",\n        help=\"Print the path to cocotb's share directory\",\n    )\n    group.add_argument(\n        \"--makefiles\",\n        action=\"store_true\",\n        help=\"Print the path to cocotb's makefile directory\",\n    )\n    group.add_argument(\n        \"--python-bin\",\n        action=\"store_true\",\n        help=\"Print the path to the Python executable associated with the environment that cocotb is installed in.\",\n    )\n    group.add_argument(\n        \"--help-vars\",\n        action=\"store_true\",\n        help=\"Print help about supported environment variables\",\n    )\n    group.add_argument(\n        \"--libpython\",\n        action=\"store_true\",\n        help=\"Print the absolute path to the libpython associated with the current Python installation\",\n    )\n    group.add_argument(\n        \"--lib-dir\",\n        action=\"store_true\",\n        help=\"Print the absolute path to the interface libraries location\",\n    )\n    group.add_argument(\n        \"--lib-name-path\",\n        help=\"Print the absolute path of interface library for given interface (VPI/VHPI/FLI) and simulator\",\n        nargs=2,\n        metavar=(\"INTERFACE\", \"SIMULATOR\"),\n    )\n    group.add_argument(\n        \"--version\",\n        action=\"store_true\",\n        help=\"Print the version of cocotb\",\n    )\n    group.add_argument(\n        \"--pygpi-entry-point\",\n        action=\"store_true\",\n        help=\"Print the PYGPI entry point for use in GPI_USERS\",\n    )\n\n    return parser\n\n\ndef main() -> None:\n    parser = _get_parser()\n    args = parser.parse_args()\n\n    if args.share:\n        print(share_dir.as_posix())\n    elif args.makefiles:\n        print(makefiles_dir.as_posix())\n    elif args.python_bin:\n        print(Path(sys.executable).as_posix())\n    elif args.help_vars:\n        print(_help_vars_text())\n    elif args.libpython:\n        libpython_path = find_libpython.find_libpython()\n        if libpython_path is None:\n            sys.exit(1)\n        print(Path(libpython_path).as_posix())\n    elif args.lib_dir:\n        print(libs_dir.as_posix())\n    elif args.lib_name_path:\n        print(lib_name_path(*args.lib_name_path).as_posix())\n    elif args.pygpi_entry_point:\n        print(pygpi_entry_point())\n    elif args.version:\n        print(_get_version())\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "src/cocotb_tools/ipython_support.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom typing import Any, TypeVar\n\nimport IPython\nfrom IPython.terminal.ipapp import load_default_config\nfrom IPython.terminal.prompts import Prompts\nfrom pygments.token import Token\n\nimport cocotb\nimport cocotb._bridge\nfrom cocotb.task import bridge\nfrom cocotb.utils import get_sim_time\n\nT = TypeVar(\"T\")\n\n\nclass SimTimePrompt(Prompts):\n    \"\"\"custom prompt that shows the sim time after a trigger fires\"\"\"\n\n    _show_time = 1\n\n    def in_prompt_tokens(self):\n        tokens = super().in_prompt_tokens()\n        if self._show_time == self.shell.execution_count:\n            tokens = [\n                (Token.Comment, f\"sim time: {get_sim_time()}\"),\n                (Token.Text, \"\\n\"),\n                *tokens,\n            ]\n        return tokens\n\n\nasync def embed(user_ns: dict[str, Any] = {}) -> None:\n    \"\"\"\n    Start an IPython shell in the current coroutine.\n\n    Unlike using :func:`IPython.embed` directly, the :keyword:`await` keyword\n    can be used directly from the shell to wait for triggers.\n    The :keyword:`yield` keyword from the legacy :ref:`yield-syntax` is not supported.\n\n    This coroutine will complete only when the user exits the interactive session.\n\n    Args:\n        user_ns:\n            The variables to have made available in the shell.\n            Passing ``locals()`` is often a good idea.\n            ``cocotb`` will automatically be included.\n\n    .. note::\n        If your simulator does not provide an appropriate ``stdin``, you may\n        find you cannot type in the resulting shell. Using simulators in batch\n        or non-GUI mode may resolve this. This feature is experimental, and\n        not all simulators are supported.\n    \"\"\"\n    # ensure cocotb is in the namespace, for convenience\n    default_ns = {\"cocotb\": cocotb}\n    default_ns.update(user_ns)\n\n    def _runner(x):\n        \"\"\"Handler for async functions\"\"\"\n        nonlocal shell\n        ret = cocotb._bridge.queue_function(x)\n        shell.prompts._show_time = shell.execution_count\n        return ret\n\n    # build the config to enable `await`\n    c = load_default_config()\n    c.TerminalInteractiveShell.loop_runner = _runner\n    c.TerminalInteractiveShell.autoawait = True\n    # Python3 checks SQLite DB accesses to ensure process ID matches the one that opened the DB and is not propagated\n    # because we launch IPython in a different process, this will cause unnecessary warnings, so disable the PID check\n    c.HistoryAccessor.connection_options = {\"check_same_thread\": False}\n    # create a shell with access to the dut, and cocotb pre-imported\n    shell = IPython.terminal.embed.InteractiveShellEmbed(\n        user_ns=default_ns,\n        config=c,\n    )\n\n    # add our custom prompts\n    shell.prompts = SimTimePrompt(shell)\n\n    # start the shell in a background thread\n    @bridge\n    def run_shell() -> None:\n        shell()\n\n    await run_shell()\n\n\n@cocotb.test()\nasync def run_ipython(dut: Any) -> None:\n    \"\"\"A test that launches an interactive Python shell.\n\n    Do not call this directly - use this as ``make COCOTB_TEST_MODULES=cocotb.ipython_support``.\n\n    Within the shell, a global ``dut`` variable pointing to the design will be present.\n    \"\"\"\n    await embed(user_ns={\"dut\": dut})\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/Makefile.deprecations",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifdef VERILATOR_TRACE\n    $(warning VERILATOR_TRACE is deprecated, see the \"Simulator Support\" section in the documentation.)\nendif\n\nifeq ($(SIM_LOWERCASE),aldec)\n    $(warning Using SIM=aldec is deprecated, please use SIM=riviera instead.)\n    SIM_LOWERCASE := riviera\nendif\n\n# Use this function to warn users about deprecated environment variables\ndeprecate = $(if $($(1)),$(if $(filter $($(2)),$($(1))),$($(2)),$(warning Using $(1) is deprecated, please use $(2) instead.)$($(1))),$($(2)))\n\nifneq ($(COCOTB_TOPLEVEL),$(TOPLEVEL))\nifneq ($(TOPLEVEL),)\n    COCOTB_TOPLEVEL := $(TOPLEVEL)\nendif\nendif\n\nifneq ($(COCOTB_USER_COVERAGE),$(COVERAGE))\nifneq ($(COVERAGE),)\n    COCOTB_USER_COVERAGE := $(COVERAGE)\nendif\nendif\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/Makefile.inc",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Common makefile included by everything\n\nifndef COCOTB_MAKEFILE_INC_INCLUDED # Protect against multiple includes\nCOCOTB_MAKEFILE_INC_INCLUDED = 1\n\n# Default sim rule will force a re-run of the simulation (though the cocotb library\n# and RTL compilation phases are still evaluated by makefile dependencies)\n.PHONY: sim, _rm_results\n_rm_results:\n\t$(RM) $(COCOTB_RESULTS_FILE)\nsim: _rm_results regression\n\n# Make sure to use bash for the pipefail option used in many simulator Makefiles\nSHELL := bash\n\nOS=$(shell uname)\nifneq (, $(findstring MINGW, $(OS)))\n    OS := Msys\nelse ifneq (, $(findstring MSYS, $(OS)))\n    OS := Msys\nendif\nexport OS\n\nexport PYGPI_PYTHON_BIN := $(shell $(PYTHON_BIN) -m cocotb_tools.config --python-bin)\n\n# Directory containing the cocotb Makefiles\nCOCOTB_MAKEFILES_DIR := $(shell $(PYTHON_BIN) -m cocotb_tools.config --makefiles)\n\ninclude $(COCOTB_MAKEFILES_DIR)/Makefile.deprecations\n\nPYTHON_ARCH := $(shell $(PYTHON_BIN) -c 'from platform import architecture; print(architecture()[0])')\nifeq ($(filter $(PYTHON_ARCH),64bit 32bit),)\n    $(error Unknown Python architecture: $(PYTHON_ARCH))\nendif\n\nifeq ($(OS),Msys)\n    to_tcl_path = $(shell cygpath -m $(1) )\nelse\n    to_tcl_path = $(1)\nendif\n\n# Check that the COCOTB_RESULTS_FILE was created, since we can't set an exit code from cocotb.\ndefine check_for_results_file\n    @test -f $(COCOTB_RESULTS_FILE) || (echo \"ERROR: $(COCOTB_RESULTS_FILE) was not written by the simulation!\" >&2 && exit 1)\nendef\n\n# Check that the COCOTB_RESULTS_FILE was created and has no failures\ndefine check_results\n    @$(PYTHON_BIN) -m cocotb_tools.check_results $(COCOTB_RESULTS_FILE)\nendef\n\n# Find an executable or fail if it can't be found.\ndefine find_command\n    $(or $(shell :; command -v $(1) 2>/dev/null),$(error Unable to locate command '$(1)'))\nendef\n\nSIM_BUILD ?= sim_build\nexport SIM_BUILD\n\nCOCOTB_RESULTS_FILE ?= results.xml\nCOCOTB_HDL_TIMEUNIT ?= 1ns\nCOCOTB_HDL_TIMEPRECISION ?= 1ps\n\nexport COCOTB_RESULTS_FILE\n\n\n$(SIM_BUILD):\n\tmkdir -p $@\n\n# Regression rule uses Make dependencies to determine whether to run the simulation\n.PHONY: regression\nregression: $(COCOTB_RESULTS_FILE)\n\n# Attempt to detect TOPLEVEL_LANG based on available sources if not set\nifeq ($(TOPLEVEL_LANG),)\n\nifneq ($(VHDL_SOURCES),)\nifeq ($(VERILOG_SOURCES),)\n    TOPLEVEL_LANG := vhdl\nendif\nelse ifneq ($(VERILOG_SOURCES),)\nifeq ($(VHDL_SOURCES),)\n    TOPLEVEL_LANG := verilog\nendif\nendif\n\nendif\n\ndefine find_libpython_errmsg =\n\n\nfind_libpython was not able to find a libpython in the current Python environment. Ensure\nthe Python development packages are installed. If they are installed and find_libpython\nis not finding the path to libpython, file an upstream bug in find_libpython; then\nmanually override the LIBPYTHON_LOC make variable with the absolute path to libpython.so\n(or python.dll on Windows).\n\nendef\n\nifndef GPI_USERS\nifndef LIBPYTHON_LOC\n\n# get the path to libpython and the return code from the script\n# adapted from https://stackoverflow.com/a/24658961/6614127\nFIND_LIBPYTHON_RES := $(shell $(PYTHON_BIN) -m cocotb_tools.config --libpython; echo $$?)\nFIND_LIBPYTHON_RC := $(lastword $(FIND_LIBPYTHON_RES))\nLIBPYTHON_LOC := $(strip $(subst $(FIND_LIBPYTHON_RC)QQQQ,,$(FIND_LIBPYTHON_RES)QQQQ))\n\n# complain if libpython isn't found\nifneq ($(FIND_LIBPYTHON_RC),0)\n    $(error $(find_libpython_errmsg))\nendif\nendif\nGPI_USERS := $(LIBPYTHON_LOC);$(shell $(PYTHON_BIN) -m cocotb_tools.config --pygpi-entry-point)\nendif\nexport GPI_USERS\n\ndefine check_vhdl_sources\nif [ \"$(VHDL_SOURCES_$(LIB))\" == \"\" ]; then \\\n  >&2 echo \"ERROR: VHDL_SOURCES_$(LIB) is empty or undefined, but '$(LIB)' is present in VHDL_LIB_ORDER.\"; \\\n  exit 1; \\\nfi;\nendef\n\ndefine check_lib_order\n  if [ \"$(filter $(SOURCES_VAR:VHDL_SOURCES_%=%), $(VHDL_LIB_ORDER))\" == \"\" ]; then \\\n    >&2 echo \"ERROR: $(SOURCES_VAR) defined, but library $(SOURCES_VAR:VHDL_SOURCES_%=%) not present in VHDL_LIB_ORDER.\"; \\\n    exit 1; \\\n  fi;\nendef\n\n# NOTE: if the following simulator list is modified, update the sentence\n# \"This flag is enabled by default for the GHDL, NVC and Verilator simulators.\"\n# in docs/source/building.rst accordingly.\nifneq ($(filter $(SIM),nvc ghdl verilator),)\n  COCOTB_TRUST_INERTIAL_WRITES ?= 1\nelse\n  COCOTB_TRUST_INERTIAL_WRITES ?= 0\nendif\n\nexport COCOTB_TRUST_INERTIAL_WRITES\n\n\n# Universal\nclean::\n\t@$(RM) -rf $(SIM_BUILD)\n\t@$(RM) -f $(COCOTB_RESULTS_FILE)\n\n\n# Active-HDL\nclean::\n\t@$(RM) -rf work\n\t@$(RM) -rf wave.asdb\n\n# IUS\nclean::\n\t@$(RM) -rf irun.*\n\t@$(RM) -rf ncsim.*\n\t@$(RM) -rf gdb_cmd_ncsim\n\n# VCS\nclean::\n\t@$(RM) -rf simv.daidir\n\t@$(RM) -rf cm.log\n\t@$(RM) -rf ucli.key\n\n# Riviera\nclean::\n\t@$(RM) -rf compile\n\t@$(RM) -rf library.cfg\n\t@$(RM) -rf dataset.asdb\n\n# Verilator\nclean::\n\t@$(RM) -f dump.vcd\n\t@$(RM) -f dump.fst\n\n# Xcelium\nclean::\n\t@$(RM) -rf xrun.*\n\t@$(RM) -rf xmsim.*\n\t@$(RM) -rf gdb_cmd_xmsim\n\t@$(RM) -f qrun*\n\t@$(RM) -f visualizer.log\n\t@$(RM) -f design.bin\n\t@$(RM) -f qwave.db\n\t@$(RM) -f transcript\n\n\n# DSim\nclean::\n\t@$(RM) -rf dsim.*\n\t@$(RM) -rf metrics.db\n\t@$(RM) -rf file.vcd\n\nelse\n    $(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.)\nendif # COCOTB_MAKEFILE_INC_INCLUDED\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/Makefile.sim",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# This file includes an appropriate makefile depending on the SIM variable.\n\n.PHONY: all\nall: sim\n\n# NOTE: keep this at 80 chars.\ndefine help_targets =\nTargets\n=======\nsim                       Unconditionally re-run the simulator (default)\nregression                Run simulator when dependencies have changes\nclean                     Remove build and simulation artefacts\nhelp                      This help text\n\nendef\n\n# NOTE: keep this at 80 chars.\ndefine help_makevars =\nVariables\n=========\n\nThe following variables are makefile variables:\n\nMakefile-based Test Scripts\n---------------------------\nGUI                       Set this to 1 to enable the GUI mode in the simulator\nSIM                       Selects which simulator Makefile to use\nWAVES                     Enable wave traces dump for Riviera-PRO and Questa\nVERILOG_SOURCES           A list of the Verilog source files to include\nVHDL_SOURCES              A list of the VHDL source files to include\nVHDL_SOURCES_<lib>        VHDL source files to include in *lib* (GHDL/NVC/ModelSim/Questa/Xcelium/Incisive/Riviera-PRO only)\nVHDL_LIB_ORDER            Compilation order of VHDL libraries (needed for NVC/ModelSim/Questa/Xcelium/Incisive/Riviera-PRO)\nSIM_CMD_PREFIX            Prefix for simulation command invocations\nCOMPILE_ARGS              Arguments to pass to compile (analysis) stage of simulation\nSIM_ARGS                  Arguments to pass to execution of compiled simulation\nEXTRA_ARGS                Arguments for compile and execute phases\nCOCOTB_PLUSARGS           Plusargs to pass to the simulator\nCOCOTB_HDL_TIMEUNIT       Default time unit for simulation\nCOCOTB_HDL_TIMEPRECISION  Default time precision for simulation\nCUSTOM_COMPILE_DEPS       Add additional dependencies to the compilation target\nCUSTOM_SIM_DEPS           Add additional dependencies to the simulation target\nSIM_BUILD                 Define a scratch directory for use by the simulator\nSCRIPT_FILE               Simulator script to run (for e.g. wave traces)\n\nendef\n\n\n# NOTE: keep *two* empty lines between \"define\" and \"endef\":\ndefine newline\n\n\nendef\n\n# this ensures we use the same python as the one cocotb was installed into\n# attempts to use cocotb_config entry script to get that info, falls back to \"python\"\nPYTHON_BIN_RES := $(shell cocotb-config --python-bin 2>>/dev/null; echo $$?)\nPYTHON_BIN_RC := $(lastword $(PYTHON_BIN_RES))\nPYTHON_BIN := $(strip $(subst $(PYTHON_BIN_RC)QQQQ,,$(PYTHON_BIN_RES)QQQQ))\nifneq ($(PYTHON_BIN_RC),0)\n    PYTHON_BIN := python3\nendif\n\n# this cannot be a regular target because of the way Makefile.$(SIM) is included\nifeq ($(MAKECMDGOALS),help)\n    $(info $(help_targets))\n    $(info $(help_makevars))\n    # hack to get newlines in output, see https://stackoverflow.com/a/54539610\n    # NOTE: the output of the command must not include a '%' sign, otherwise the formatting will break\n    help_envvars := $(subst %,${newline},$(shell $(PYTHON_BIN) -m cocotb.config --help-vars | tr \\\\n %))\n    $(info ${help_envvars})\n    # is there a cleaner way to exit here?\n    $(error Stopping after printing help)\nendif\n\ninclude $(shell $(PYTHON_BIN) -m cocotb_tools.config --makefiles)/Makefile.inc\n\n# Default to Icarus if no simulator is defined\nSIM ?= icarus\n\n# Maintain backwards compatibility by supporting upper and lower case SIM variable\nSIM_LOWERCASE := $(shell echo $(SIM) | tr A-Z a-z)\n\nHAVE_SIMULATOR = $(shell if [ -f $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.$(SIM_LOWERCASE) ]; then echo 1; else echo 0; fi;)\nAVAILABLE_SIMULATORS = $(patsubst .%,%,$(suffix $(wildcard $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.*)))\n\nifeq ($(HAVE_SIMULATOR),0)\n    $(error Couldn't find makefile for simulator: \"$(SIM_LOWERCASE)\"! Available simulators: $(AVAILABLE_SIMULATORS))\nendif\n\ninclude $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.$(SIM_LOWERCASE)\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.activehdl",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Common Makefile for the Aldec Active-HDL simulator\n\nCMD_BIN := vsimsa\n\nifdef ACTIVEHDL_BIN_DIR\n    CMD := $(call find_command,$(ACTIVEHDL_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n    ACTIVEHDL_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nALOG_ARGS += -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION)\n\n# below allows for maintaining legacy syntax as well as enables using cross-simulator vars COMPILE_ARGS/SIM_ARGS\nALOG_ARGS += $(COMPILE_ARGS)\nACOM_ARGS += $(COMPILE_ARGS)\nASIM_ARGS += $(SIM_ARGS)\n\nifdef RTL_LIBRARY\n    $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.)\n    TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY)\nelse\n    TOPLEVEL_LIBRARY ?= work\nendif\n\nALOG_ARGS += -dbg\nACOM_ARGS += -dbg\n\nGPI_EXTRA:=\nifeq ($(TOPLEVEL_LANG),verilog)\n    # backslashes needed because we embed in `echo` below\n    GPI_ARGS = -pli \\\"$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi activehdl)\\\"\nifneq ($(VHDL_SOURCES),)\n    GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi activehdl):cocotbvhpi_entry_point\nendif\n\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    # backslashes needed because we embed in `echo` below\n    GPI_ARGS = -loadvhpi \\\"$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi activehdl):vhpi_startup_routines_bootstrap\\\"\nifneq ($(VERILOG_SOURCES),)\n    GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi activehdl):cocotbvpi_entry_point\nendif\nelse\n   $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\n# Create a DO script (Tcl-like but not fully compatible) based on the list of $(VERILOG_SOURCES)\n$(SIM_BUILD)/runsim.do : $(VERILOG_SOURCES) $(VHDL_SOURCES) | $(SIM_BUILD)\n\t@echo \"alib $(TOPLEVEL_LIBRARY)\" > $@\n\t@echo \"set worklib $(TOPLEVEL_LIBRARY)\" >> $@\nifneq ($(VHDL_SOURCES),)\n\t@echo \"acom $(ACOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES))\" >> $@\nendif\nifneq ($(VERILOG_SOURCES),)\n\t@echo \"alog $(ALOG_ARGS) $(call to_tcl_path,$(VERILOG_SOURCES))\" >> $@\nendif\n\t@echo \"asim $(ASIM_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) +access +w_nets -interceptcoutput $(GPI_ARGS) $(COCOTB_TOPLEVEL) $(EXTRA_TOPS)\" >> $@\n\t@echo \"run -all\" >> $@\n\t@echo \"endsim\" >> $@\n\n$(COCOTB_RESULTS_FILE): $(SIM_BUILD)/runsim.do $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\tset -o pipefail; GPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \\\n\tCOCOTB_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)\n\n\t$(call check_results)\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.cvc",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2014 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifneq ($(VHDL_SOURCES),)\n\n$(COCOTB_RESULTS_FILE):\n\t@echo \"Skipping simulation as VHDL is not supported on simulator=$(SIM)\"\ndebug: $(COCOTB_RESULTS_FILE)\n\nelse\n\nCMD_BIN := cvc64\n\nifdef CVC_BIN_DIR\n    CMD := $(call find_command,$(CVC_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n    CVC_BIN_DIR := $(shell dirname $(CMD))\nendif\n\n#only interpreted mode works for the moment\nCVC_ITERP ?= 1\n\nifeq ($(CVC_ITERP),1)\n    CVC_ARGS    += +interp\nendif\n\n# Compilation phase\n$(SIM_BUILD)/sim.vvp: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) | $(SIM_BUILD)\n\tCOCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \\\n\tCOCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \\\n        $(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)\n\n# Execution phase\nifeq ($(CVC_ITERP),1)\n    $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/sim.vvp\nelse\n    $(COCOTB_RESULTS_FILE): $(SIM_BUILD)/sim.vvp $(CUSTOM_SIM_DEPS)\n\tCOCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \\\n        COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \\\n        $(SIM_CMD_PREFIX) $(SIM_BUILD)/sim.vvp $(SIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX)\nendif\n\n# Execution phase\nifeq ($(CVC_ITERP),1)\n    debug:  $(CUSTOM_SIM_DEPS)\n\tCOCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \\\n        COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \\\n        $(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)\nelse\n    debug: $(SIM_BUILD)/sim.vvp $(CUSTOM_SIM_DEPS)\n\tCOCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \\\n        COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \\\n        gdb --args $(SIM_BUILD)/sim.vvp $(SIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS)\nendif\n\n\nendif\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.dsim",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCMD_BIN := dsim\n\nifdef DSIM_BIN_DIR\n    CMD := $(call find_command,$(DSIM_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\nendif\n\nifeq ($(WAVES), 1)\n    WAVE_ARG := -waves file.vcd\nelse\n    WAVE_ARG :=\nendif\n\nTOPMODULE_ARG = -top $(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL)\n\nDSIM_ARGS = -work $(SIM_BUILD) -pli_lib $(shell cocotb-config --lib-name-path vpi dsim) +acc+rwcbfsWF\nCOMP_ARGS = $(DSIM_ARGS) -genimage image -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION)\nRUN_ARGS = $(DSIM_ARGS) -image image $(WAVE_ARG)\n\n$(SIM_BUILD)/image.so: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS)\n\t$(SIM_CMD_PREFIX) $(CMD) $(COMP_ARGS) $(TOPMODULE_ARG) $(EXTRA_ARGS) $(VERILOG_SOURCES)\n\n$(COCOTB_RESULTS_FILE): $(SIM_BUILD)/image.so $(CUSTOM_SIM_DEPS)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\tCOCOTB_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) \\\n\tGPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \\\n\t$(SIM_CMD_PREFIX) $(CMD) $(RUN_ARGS) $(TOPMODULE_ARG) $(EXTRA_ARGS) $(VERILOG_SOURCES)\n\n\t$(call check_results)\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.ghdl",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2014 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= vhdl\n\nifneq ($(or $(filter-out $(TOPLEVEL_LANG),vhdl),$(VERILOG_SOURCES)),)\n\n$(COCOTB_RESULTS_FILE):\n\t@echo \"Skipping simulation as only VHDL is supported on simulator=$(SIM)\"\n\nelse\n\nCMD_BIN := ghdl\n\nifdef GHDL_BIN_DIR\n    CMD := $(call find_command,$(GHDL_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n    GHDL_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nifdef RTL_LIBRARY\n    $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.)\n    TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY)\nelse\n    TOPLEVEL_LIBRARY ?= work\nendif\nGHDL_ARGS ?=\nGHDL_ARGS += $(EXTRA_ARGS)\n\n# On Windows add GHDL lib folder to PATH to find libraries\nifeq ($(OS),Msys)\n    export PATH := $(GHDL_BIN_DIR)/../lib:$(PATH)\nendif\n\nGHDL_RUN_ARGS ?=\n\nifeq ($(shell $(CMD) --version | grep -q mcode; echo $$?),0)\n    ifneq ($(COCOTB_HDL_TIMEPRECISION),)\n        # Convert the time precision to a format string supported by GHDL, if\n        # possible.\n        # GHDL only supports setting the time precision if the mcode backend is\n        # used, using the --time-resolution argument causes GHDL to error out\n        # otherwise.\n        # https://ghdl.github.io/ghdl/using/InvokingGHDL.html#cmdoption-ghdl-time-resolution\n        ifeq ($(COCOTB_HDL_TIMEPRECISION),1fs)\n            GHDL_TIME_RESOLUTION=fs\n        else ifeq ($(COCOTB_HDL_TIMEPRECISION),1ps)\n            GHDL_TIME_RESOLUTION=ps\n        else ifeq ($(COCOTB_HDL_TIMEPRECISION),1ns)\n            GHDL_TIME_RESOLUTION=ns\n        else ifeq ($(COCOTB_HDL_TIMEPRECISION),1us)\n            GHDL_TIME_RESOLUTION=us\n        else ifeq ($(COCOTB_HDL_TIMEPRECISION),1ms)\n            GHDL_TIME_RESOLUTION=ms\n        else ifeq ($(COCOTB_HDL_TIMEPRECISION),1s)\n            GHDL_TIME_RESOLUTION=sec\n        else\n            $(error GHDL only supports the following values for COCOTB_HDL_TIMEPRECISION: 1fs, 1ps, 1ns, 1us, 1ms, 1s)\n        endif\n\n        GHDL_RUN_ARGS += --time-resolution=$(GHDL_TIME_RESOLUTION)\n    endif\nendif\n\n.PHONY: analyse\n\n# Compilation phase\nanalyse: $(VHDL_SOURCES) $(CUSTOM_COMPILE_DEPS) | $(SIM_BUILD)\n\t$(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), \\\n\t\t$(CMD) -i $(GHDL_ARGS) $(COMPILE_ARGS) --workdir=$(SIM_BUILD) --work=$(SOURCES_VAR:VHDL_SOURCES_%=%) $($(SOURCES_VAR)) && ) \\\n\t$(CMD) -i $(GHDL_ARGS) $(COMPILE_ARGS) --workdir=$(SIM_BUILD) --work=$(TOPLEVEL_LIBRARY) $(VHDL_SOURCES) && \\\n\t$(CMD) -m $(GHDL_ARGS) $(COMPILE_ARGS) --workdir=$(SIM_BUILD) -P$(SIM_BUILD) --work=$(TOPLEVEL_LIBRARY) $(COCOTB_TOPLEVEL) $(ARCH)\n\n$(COCOTB_RESULTS_FILE): analyse $(CUSTOM_SIM_DEPS)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\tCOCOTB_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) \\\n\t$(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)\n\n\t$(call check_results)\n\nendif\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.icarus",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nifneq ($(or $(filter-out $(TOPLEVEL_LANG),verilog),$(VHDL_SOURCES)),)\n\n$(COCOTB_RESULTS_FILE):\n\t@echo \"Skipping simulation as only Verilog is supported on simulator=$(SIM)\"\ndebug: $(COCOTB_RESULTS_FILE)\n\nelse\n\nCMD_BIN := iverilog\n\nifdef ICARUS_BIN_DIR\n    CMD := $(call find_command,$(ICARUS_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n    ICARUS_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nifdef COCOTB_TOPLEVEL\n  TOPMODULE_ARG := -s $(COCOTB_TOPLEVEL)\nelse\n  TOPMODULE_ARG :=\nendif\n\nCOMPILE_ARGS += -f $(SIM_BUILD)/cmds.f\n\nifdef VERILOG_INCLUDE_DIRS\n    COMPILE_ARGS += $(addprefix -I, $(VERILOG_INCLUDE_DIRS))\nendif\n\n# Compilation phase\n\nifeq ($(WAVES),1)\n    VERILOG_SOURCES += $(SIM_BUILD)/cocotb_iverilog_dump.v\n    COMPILE_ARGS += -s cocotb_iverilog_dump\n    FST = -fst\nelse ifeq ($(WAVES),0)\n    # Disable waveform output\n    FST = -none\nendif\n\n$(SIM_BUILD)/sim.vvp: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) | $(SIM_BUILD)\n\t@echo \"+timescale+$(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION)\" > $(SIM_BUILD)/cmds.f\n\t$(CMD) -o $(SIM_BUILD)/sim.vvp $(TOPMODULE_ARG) -g2012 $(COMPILE_ARGS) $(EXTRA_ARGS) $(VERILOG_SOURCES)\n\n$(SIM_BUILD)/cocotb_iverilog_dump.v: | $(SIM_BUILD)\n\t@echo 'module cocotb_iverilog_dump();' > $@\n\t@echo 'initial begin' >> $@\n\t@echo '    $$dumpfile(\"$(SIM_BUILD)/$(COCOTB_TOPLEVEL).fst\");' >> $@\n\t@echo '    $$dumpvars(0, $(COCOTB_TOPLEVEL));' >> $@\n\t@echo 'end' >> $@\n\t@echo 'endmodule' >> $@\n\n# Execution phase\n\n$(COCOTB_RESULTS_FILE): $(SIM_BUILD)/sim.vvp $(CUSTOM_SIM_DEPS)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\tCOCOTB_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) \\\n        $(SIM_CMD_PREFIX) $(ICARUS_BIN_DIR)/vvp -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)\n\n\t$(call check_results)\n\ndebug: $(SIM_BUILD)/sim.vvp $(CUSTOM_SIM_DEPS)\n\t$(RM) -r $(COCOTB_RESULTS_FILE)\n\n\tCOCOTB_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) \\\n        $(SIM_CMD_PREFIX) gdb --args $(ICARUS_BIN_DIR)/vvp -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)\n\n\t$(call check_results)\n\nendif\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.ius",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Common Makefile for Cadence Incisive\n\nCMD_BIN := irun\n\nifdef IUS_BIN_DIR\n    CMD := $(call find_command,$(IUS_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n    IUS_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nifdef VERILOG_INCLUDE_DIRS\n    COMPILE_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS))\nendif\n\nEXTRA_ARGS += $(COMPILE_ARGS)\nEXTRA_ARGS += $(SIM_ARGS)\nEXTRA_ARGS += -licqueue\n\nifeq ($(PYTHON_ARCH),64bit)\n    EXTRA_ARGS += -64\nendif\n\nEXTRA_ARGS += -nclibdirpath $(SIM_BUILD)\nEXTRA_ARGS += -plinowarn\n\nifeq ($(GUI),1)\n    EXTRA_ARGS += -gui\nelse\n    EXTRA_ARGS +=\nendif\n\n# IUS errors out if multiple timescales are specified on the command line.\nifneq (,$(findstring timescale,$(EXTRA_ARGS)))\n    $(error Please use COCOTB_HDL_TIMEUNIT and COCOTB_HDL_TIMEPRECISION to specify timescale.)\nendif\n\n# Loading the VHPI library causes an error, so we always load the VPI library and supply\n# GPI_EXTRA=$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi ius) if needed.\n\n# Xcelium will use default vlog_startup_routines symbol only if vpi library name is libvpi.so\nGPI_ARGS = -loadvpi $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi ius):vlog_startup_routines_bootstrap\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    EXTRA_ARGS += -v93\n    HDL_SOURCES = $(VERILOG_SOURCES)\n    ROOT_LEVEL = $(COCOTB_TOPLEVEL)\nifneq ($(VHDL_SOURCES),)\n    HDL_SOURCES += $(VHDL_SOURCES)\n    GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi ius):cocotbvhpi_entry_point\nendif\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi ius):cocotbvhpi_entry_point\n    EXTRA_ARGS += -v93\n    EXTRA_ARGS += -top $(COCOTB_TOPLEVEL)\nifdef RTL_LIBRARY\n    $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.)\n    TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY)\nelse\n    TOPLEVEL_LIBRARY ?= work\nendif\n    MAKE_LIB = -makelib $(TOPLEVEL_LIBRARY)\n    HDL_SOURCES = $(VHDL_SOURCES)\nifneq ($(VERILOG_SOURCES),)\n    HDL_SOURCES += $(VERILOG_SOURCES)\nendif\nelse\n   $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\n# Builds a list of arguments to support VHDL libraries specified in VHDL_SOURCES_*:\nLIBS := $(foreach LIB, $(VHDL_LIB_ORDER),-makelib $(LIB) $(VHDL_SOURCES_$(LIB)) -endlib)\n\n$(COCOTB_RESULTS_FILE): $(HDL_SOURCES) $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS) | $(SIM_BUILD)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\t# Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa\n\t$(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources))\n\t$(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order))\n\n\tset -o pipefail; \\\n\tCOCOTB_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) \\\n\t$(SIM_CMD_PREFIX) $(CMD) -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) \\\n\t$(EXTRA_ARGS) $(GPI_ARGS) +access+rwc $(LIBS) $(MAKE_LIB) $(HDL_SOURCES) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX)\n\n\t$(call check_results)\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.modelsim",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\n# Identical to Questa with the compat flow.\ninclude $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.questa-compat\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.nvc",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifneq ($(VERILOG_SOURCES),)\n\n$(COCOTB_RESULTS_FILE):\n\t@echo \"Skipping simulation as Verilog is not supported on simulator=$(SIM)\"\n\nelse\n\nCMD_BIN := nvc\n\nifdef NVC_BIN_DIR\n    CMD := $(call find_command,$(NVC_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n\tNVC_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nPRESERVE_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 '')\")\n\nifdef RTL_LIBRARY\n    $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.)\n    TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY)\nelse\n    TOPLEVEL_LIBRARY ?= work\nendif\n\n.PHONY: analyse\n\n# Split SIM_ARGS into those options that need to be passed to -e and\n# those that need to be passed to -r\nNVC_E_FILTER := -g% --cover --cover=%\n\nNVC_E_ARGS := $(filter $(NVC_E_FILTER),$(SIM_ARGS))\nNVC_R_ARGS := $(filter-out $(NVC_E_FILTER),$(SIM_ARGS))\n\n# Compilation phase\nanalyse: $(VHDL_SOURCES) $(SIM_BUILD) $(CUSTOM_COMPILE_DEPS)\n\t# Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa\n\t$(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources))\n\t$(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order))\n\n\t$(foreach LIB_VAR,$(VHDL_LIB_ORDER), \\\n\t\t$(CMD) $(EXTRA_ARGS) --work=$(LIB_VAR):$(SIM_BUILD)/$(LIB_VAR) -L $(SIM_BUILD) -a $(VHDL_SOURCES_$(LIB_VAR)) $(PRESERVE_CASE) $(COMPILE_ARGS) && ) \\\n\t$(CMD) $(EXTRA_ARGS) --work=$(TOPLEVEL_LIBRARY):$(SIM_BUILD)/$(TOPLEVEL_LIBRARY) -L $(SIM_BUILD) -a $(VHDL_SOURCES) $(PRESERVE_CASE) $(COMPILE_ARGS)\n\n$(COCOTB_RESULTS_FILE): analyse $(CUSTOM_SIM_DEPS)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\tCOCOTB_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) \\\n\t  $(SIM_CMD_PREFIX) $(CMD) $(EXTRA_ARGS) --work=$(TOPLEVEL_LIBRARY):$(SIM_BUILD)/$(TOPLEVEL_LIBRARY) -L $(SIM_BUILD) \\\n\t  -e $(COCOTB_TOPLEVEL) --no-save $(NVC_E_ARGS) \\\n\t  -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)\n\n\t$(call check_results)\n\nendif\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.questa",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Detect the version of Questa in use to choose the best flow.\n\nCMD_BIN := vsim\n\nifdef MODELSIM_BIN_DIR\n    CMD := $(call find_command,$(MODELSIM_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\nendif\n\n# Determine the version of Questa being used.\nQUESTA_VERSION := $(shell $(CMD) -version | $(PYTHON_BIN) -c 'import re,sys; print(re.sub(r\".+vsim (\\d+)\\.(\\d).+\", \"\\\\1 \\\\2\", sys.stdin.read()))')\nQUESTA_VERSION_MAJOR := $(firstword $(QUESTA_VERSION))\nQUESTA_VERSION_MINOR := $(lastword $(QUESTA_VERSION))\n\n# Use the QIS/Qrun flow for Questa >= 2025.2 (the first version which fully\n# passes the cocotb regression suite). Use the compat flow otherwise.\nifeq ($(shell test $(QUESTA_VERSION_MAJOR)$(QUESTA_VERSION_MINOR) -lt 20252; echo $$?),0)\n    $(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.)\n    include $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.questa-compat\nelse\n    $(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.)\n    include $(COCOTB_MAKEFILES_DIR)/simulators/Makefile.questa-qisqrun\nendif\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.questa-compat",
    "content": "# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Questa compatibility flow using the vlog and vsim commands with the +acc\n# switch for design access.\n\nCMD_BIN := vsim\n\nifdef MODELSIM_BIN_DIR\n    CMD := $(call find_command,$(MODELSIM_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n\tMODELSIM_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nifdef RTL_LIBRARY\n    $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.)\n    TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY)\nelse\n    TOPLEVEL_LIBRARY ?= work\nendif\nCOCOTB_TOPLEVEL := \"$(TOPLEVEL_LIBRARY).$(COCOTB_TOPLEVEL)\"\n\nifndef VLOG_ARGS\n    VLOG_ARGS = -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) -mfcu\nendif\n\nCOMPILE_ARGS += +acc\n\nifdef VERILOG_INCLUDE_DIRS\n    VLOG_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS))\nendif\n\n# below allows for maintaining legacy syntax as well as enables using cross-simulator vars COMPILE_ARGS/SIM_ARGS\nVLOG_ARGS += $(COMPILE_ARGS)\nVCOM_ARGS += $(COMPILE_ARGS)\nVSIM_ARGS += $(SIM_ARGS)\n\nifeq ($(GUI),1)\n    CMD += -gui\n    VSIM_ARGS += -onfinish stop\nelse\n    CMD += -c\n    VSIM_ARGS += -onfinish exit\nendif\n\nFLI_LIB := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path fli questa)\nVHPI_LIB := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi questa)\n\nGPI_EXTRA :=\n\nVHDL_GPI_INTERFACE ?= fli\n\nifeq ($(filter vhpi fli,$(VHDL_GPI_INTERFACE)),)\n    $(error A valid value (fli or vhpi) was not provided for VHDL_GPI_INTERFACE=$(VHDL_GPI_INTERFACE))\nendif\n\nifeq ($(TOPLEVEL_LANG),vhdl)\n    VSIM_ARGS += -t $(COCOTB_HDL_TIMEPRECISION)\nifeq ($(VHDL_GPI_INTERFACE),fli)\n    CUSTOM_COMPILE_DEPS += $(FLI_LIB)\n    VSIM_ARGS += -foreign \\\"cocotb_init $(FLI_LIB)\\\"\nelse\n    VSIM_ARGS += -voptargs=\"-access=rw+/.\" -foreign \\\"vhpi_startup_routines_bootstrap $(call to_tcl_path,$(VHPI_LIB))\\\"\nendif\nifneq ($(VERILOG_SOURCES),)\n    GPI_EXTRA :=  $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi questa):cocotbvpi_entry_point\nendif\n\nelse ifeq ($(TOPLEVEL_LANG),verilog)\n    VSIM_ARGS += -pli $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi questa)\nifneq ($(VHDL_SOURCES),)\n    GPI_EXTRA := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path $(VHDL_GPI_INTERFACE) questa):cocotb$(VHDL_GPI_INTERFACE)_entry_point\nendif\n\nelse\n   $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\ndefine make_lib\n  echo \"if [file exists $(SIM_BUILD)/$(LIB)] {vdel -lib $(SIM_BUILD)/$(LIB) -all}\" >> $@;\n  echo \"vlib $(SIM_BUILD)/$(LIB)\" >> $@;\n  echo \"vmap $(LIB) $(SIM_BUILD)/$(LIB)\" >> $@;\n  echo \"vcom -work $(LIB) $(VCOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES_$(LIB)))\" >> $@;\nendef\n\n$(SIM_BUILD)/runsim.do : $(VHDL_SOURCES) $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS) | $(SIM_BUILD)\n\t# Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa\n\t$(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources))\n\t$(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order))\n\n\t@echo \"# Autogenerated file\" > $@\n\t@echo \"onerror {\" >> $@\n\t@echo \"\tquit -f -code 1\" >> $@\n\t@echo \"}\" >> $@\n\t@echo \"vmap -c\" >> $@\n\t$(foreach LIB, $(VHDL_LIB_ORDER), $(make_lib))\n\t@echo \"if [file exists $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)] {vdel -lib $(SIM_BUILD)/$(TOPLEVEL_LIBRARY) -all}\" >> $@\n\t@echo \"vlib $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)\" >> $@\n\t@echo \"vmap $(TOPLEVEL_LIBRARY) $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)\" >> $@\nifneq ($(VHDL_SOURCES),)\n\t@echo \"vcom -work $(TOPLEVEL_LIBRARY) $(VCOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES))\" >> $@\nendif\nifneq ($(VERILOG_SOURCES),)\n\t@echo \"vlog -work $(TOPLEVEL_LIBRARY) -sv $(VLOG_ARGS) $(EXTRA_ARGS) $(call to_tcl_path,$(VERILOG_SOURCES))\" >> $@\nendif\nifdef SCRIPT_FILE\n\t@echo \"do $(SCRIPT_FILE)\" >> $@\nendif\n\t@echo \"vsim $(VSIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(COCOTB_TOPLEVEL)\" >> $@\nifeq ($(WAVES),1)\n\t@echo \"log -recursive /*\" >> $@\nendif\nifeq ($(GUI),1)\n\t@echo \"add log -r *\" >> $@\nelse\n\t@echo \"onbreak resume\" >> $@\n\t@echo \"run -all\" >> $@\n\t@echo \"quit\" >> $@\nendif\n\nifeq ($(PYTHON_ARCH),64bit)\n    CMD += -64\nendif\n\n$(COCOTB_RESULTS_FILE): $(SIM_BUILD)/runsim.do\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\tset -o pipefail; \\\n\t  COCOTB_TEST_MODULES=$(call deprecate,MODULE,COCOTB_TEST_MODULES) \\\n\t  COCOTB_TESTCASE=$(call deprecate,TESTCASE,COCOTB_TESTCASE) \\\n\t  COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) \\\n\t  COCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) \\\n\t  GPI_EXTRA=$(GPI_EXTRA) \\\n\t  TOPLEVEL_LANG=$(TOPLEVEL_LANG) \\\n\t  VHDL_GPI_INTERFACE=$(VHDL_GPI_INTERFACE) \\\n\t  COCOTB__QUESTA_MODE=compat \\\n\t$(SIM_CMD_PREFIX) $(CMD) $(RUN_ARGS) -do $(SIM_BUILD)/runsim.do $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX)\n\n\t$(call check_results)\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.questa-qisqrun",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Questa QIS/Qrun flow using the Questa Information System (QIS) for design\n# access and qrun to build and run the simulation.\n\nQRUN_BIN := qrun\nVIS_BIN := vis\n\nifdef MODELSIM_BIN_DIR\n    QRUN_CMD := $(call find_command,$(MODELSIM_BIN_DIR)/$(QRUN_BIN))\n    VIS_CMD := $(call find_command,$(MODELSIM_BIN_DIR)/$(VIS_BIN))\nelse\n    # auto-detect bin dir from system path\n    QRUN_CMD := $(call find_command,$(QRUN_BIN))\n    VIS_CMD := $(call find_command,$(VIS_BIN))\nendif\n\nDESIGNFILE ?= design.bin\nWAVEFILE ?= qwave.db\nTOPLEVEL_LIBRARY ?= work\nCOCOTB_TOPLEVEL := \"$(TOPLEVEL_LIBRARY).$(COCOTB_TOPLEVEL)\"\n\n\nifndef VLOG_ARGS\n    VLOG_ARGS = -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) -mfcu\nendif\n\nifdef VERILOG_INCLUDE_DIRS\n    VLOG_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS))\nendif\n\n# below allows for maintaining legacy syntax as well as enables using cross-simulator vars COMPILE_ARGS/SIM_ARGS\nVLOG_ARGS += $(COMPILE_ARGS)\nVCOM_ARGS +=\nVOPT_ARGS += -access=rw+/.\nVSIM_ARGS += $(SIM_ARGS)\n\nifdef GUI\n    # Run in GUI mode.\n\n    # Two modes are supported:\n    # - GUI=livesim: Open the Visualizer GUI before running the simulation.\n    #   GUI=1 is a backwards-compatible alias for livesim.\n    # - GUI=postsim: Open the Visualizer GUI after the simulation has finished.\n\n    ifeq ($(filter livesim postsim 1,$(GUI)),)\n        $(error A valid value (livesim, postsim, or 1) was not provided for GUI=$(GUI))\n    endif\n\n    # Map GUI=1 to GUI=livesim.\n    ifeq ($(GUI),1)\n        GUI := livesim\n    endif\n\n    VOPT_ARGS += -designfile $(DESIGNFILE)\n    VSIM_ARGS += -onfinish stop -qwavedb=+signal+memory=all+class+assertion+uvm_schematic+msg+wavefile=$(WAVEFILE)\n\n    ifeq ($(GUI),livesim)\n        QRUN_CMD += -gui -visualizer\n        VOPT_ARGS += -debug,livesim\n    endif\n\n    # For GUI=postsim Visualizer is called in the $(COCOTB_RESULTS_FILE) target.\nelse\n    # Run in batch mode (no GUI).\n    QRUN_CMD += -c\n    VSIM_ARGS += -onfinish exit\nendif # ifdef GUI\n\nFLI_LIB := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path fli questa)\nVHPI_LIB := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi questa)\nGPI_EXTRA :=\n\nVHDL_GPI_INTERFACE ?= fli\n\nifeq ($(filter vhpi fli,$(VHDL_GPI_INTERFACE)),)\n    $(error A valid value (fli or vhpi) was not provided for VHDL_GPI_INTERFACE=$(VHDL_GPI_INTERFACE))\nendif\n\nifeq ($(TOPLEVEL_LANG),vhdl)\n    VSIM_ARGS += -t $(COCOTB_HDL_TIMEPRECISION)\nifeq ($(VHDL_GPI_INTERFACE),fli)\n    CUSTOM_COMPILE_DEPS += $(FLI_LIB)\n    VSIM_ARGS += -foreign \"cocotb_init $(FLI_LIB)\"\nelse\n    VSIM_ARGS += -foreign \"vhpi_startup_routines_bootstrap $(call to_tcl_path,$(VHPI_LIB))\"\nendif\nifneq ($(VERILOG_SOURCES),)\n    GPI_EXTRA :=  $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi questa):cocotbvpi_entry_point\nendif\n\nelse ifeq ($(TOPLEVEL_LANG),verilog)\n    VSIM_ARGS += -pli $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi questa)\nifneq ($(VHDL_SOURCES),)\n    GPI_EXTRA := $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path $(VHDL_GPI_INTERFACE) questa):cocotb$(VHDL_GPI_INTERFACE)_entry_point\nendif\n\nelse\n    $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\nifdef SCRIPT_FILE\n    VSIM_ARGS += -do $(SCRIPT_FILE)\nendif\n\nifeq ($(PYTHON_ARCH),64bit)\n    QRUN_CMD += -64\nendif\n\ndefine make_lib\n  -makelib $(LIB) $(VHDL_SOURCES_$(LIB)) -end\nendef\n\n$(COCOTB_RESULTS_FILE):\n\t# Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa\n\t$(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources))\n\t$(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order))\n\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\tmkdir -p $(SIM_BUILD)\n\n\tset -o pipefail; \\\n\t  COCOTB_TEST_MODULES=$(COCOTB_TEST_MODULES) \\\n\t  COCOTB_TESTCASE=$(COCOTB_TESTCASE) \\\n\t  COCOTB_TEST_FILTER=$(COCOTB_TEST_FILTER) \\\n\t  COCOTB_TOPLEVEL=$(COCOTB_TOPLEVEL) \\\n\t  GPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \\\n\t  VHDL_GPI_INTERFACE=$(VHDL_GPI_INTERFACE) \\\n\t  COCOTB__QUESTA_MODE=qisqrun \\\n\t  $(SIM_CMD_PREFIX) $(QRUN_CMD) $(RUN_ARGS) -outdir $(SIM_BUILD) \\\n\t  $(foreach LIB, $(VHDL_LIB_ORDER), $(make_lib)) \\\n\t  -makelib $(TOPLEVEL_LIBRARY) $(VERILOG_SOURCES) $(VHDL_SOURCES) $(VLOG_ARGS) $(VCOM_ARGS) -end \\\n\t  $(VOPT_ARGS) $(VSIM_ARGS) $(EXTRA_ARGS) $(COCOTB_PLUSARGS) -sv \\\n\t  -top $(COCOTB_TOPLEVEL) 2>&1 | tee $(SIM_BUILD)/sim.log\n\nifeq ($(GUI),postsim)\n\t$(VIS_CMD) -designfile $(DESIGNFILE) -wavefile $(WAVEFILE)\nendif\n\n\t$(call check_results)\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.riviera",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Common Makefile for Aldec Riviera-PRO simulator\n\nifeq ($(GUI),1)\n    CMD_BIN := riviera\nelse\n    CMD_BIN := vsimsa\nendif\n\nifdef ALDEC_BIN_DIR\n    CMD := $(call find_command,$(ALDEC_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n\tALDEC_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nifeq ($(GUI),1)\n    CMD += -nosplash\nendif\n\nALOG_ARGS += -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION)\n\nifdef VERILOG_INCLUDE_DIRS\n    ALOG_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS))\nendif\n\n# below allows for maintaining legacy syntax as well as enables using cross-simulator vars COMPILE_ARGS/SIM_ARGS\nALOG_ARGS += $(COMPILE_ARGS)\nACOM_ARGS += $(COMPILE_ARGS)\nASIM_ARGS += $(SIM_ARGS)\n\n# Plusargs need to be passed to ASIM command not vsimsa\nASIM_ARGS += $(call deprecate,PLUSARGS,COCOTB_PLUSARGS)\n\nifdef RTL_LIBRARY\n    $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.)\n    TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY)\nelse\n    TOPLEVEL_LIBRARY ?= work\nendif\n\n# Pass the VPI library to the Verilog compilation to get extended checking.\nALOG_ARGS += -pli $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi riviera)\n\n# Aldec-specific coverage types:\n# - (s)tatement\n# - (b)ranch\n# - (e)xpression\n# - (c)ondition\n# - (a)ssertion\n# - (p)ath\n# - finite state (m)achine\n# Documentation: Riviera Pro 2017.02 Documentation - Page 359\nCOVERAGE_TYPES ?= sb\nifeq ($(COCOTB_USER_COVERAGE),1)\n    ALOG_ARGS += -dbg -coverage $(COVERAGE_TYPES)\n    ACOM_ARGS += -dbg -coverage $(COVERAGE_TYPES)\n\n    ASIM_ARGS += -dbg -acdb -acdb_cov $(COVERAGE_TYPES)\nendif\n\nGPI_EXTRA:=\nifeq ($(TOPLEVEL_LANG),verilog)\n    GPI_ARGS = -pli $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi riviera)\nifneq ($(VHDL_SOURCES),)\n    GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi riviera):cocotbvhpi_entry_point\nendif\n\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    GPI_ARGS = -loadvhpi $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi riviera):vhpi_startup_routines_bootstrap\nifneq ($(VERILOG_SOURCES),)\n    GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi riviera):cocotbvpi_entry_point\nendif\n\nelse\n   $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\ndefine make_lib\n  echo \"if [file exists $(SIM_BUILD)/$(LIB)] {adel -lib $(SIM_BUILD)/$(LIB) -all}\" >> $@;\n  echo \"alib $(SIM_BUILD)/$(LIB)\" >> $@;\n  echo \"amap $(LIB) $(SIM_BUILD)/$(LIB)\" >> $@;\n  echo \"acom -work $(LIB) $(ACOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES_$(LIB)))\" >> $@;\nendef\n\n# Create a TCL script based on the list of $(VERILOG_SOURCES)\n$(SIM_BUILD)/runsim.tcl : $(VERILOG_SOURCES) $(VHDL_SOURCES) | $(SIM_BUILD)\n\t@echo \"onerror {\" > $@\n\t@echo \"\tputs [read [open sim.log r]]\" >> $@\n\t@echo \"\tquit -code 1\" >> $@\n\t@echo \"}\" >> $@\n\t@echo \"amap -c\" >> $@\n\t$(foreach LIB, $(VHDL_LIB_ORDER), $(make_lib))\n\t@echo \"@if [string length [array get env LICENSE_QUEUE]] {\" >> $@\n\t@echo \" set LICENSE_QUEUE $$::env(LICENSE_QUEUE)\" >> $@\n\t@echo \"}\" >> $@\n\t@echo \"if [file exists $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)] {adel -lib $(SIM_BUILD)/$(TOPLEVEL_LIBRARYRTL_LIBRARY) -all}\" >> $@;\n\t@echo \"alib $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)\" >> $@\n\t@echo \"amap $(TOPLEVEL_LIBRARY) $(SIM_BUILD)/$(TOPLEVEL_LIBRARY)\" >> $@;\n\t@echo \"set worklib $(TOPLEVEL_LIBRARY)\" >> $@;\nifneq ($(VHDL_SOURCES),)\n\t@echo \"acom -work $(TOPLEVEL_LIBRARY) $(ACOM_ARGS) $(call to_tcl_path,$(VHDL_SOURCES))\" >> $@\nendif\nifneq ($(VERILOG_SOURCES),)\n\t@echo \"alog -work $(TOPLEVEL_LIBRARY) $(ALOG_ARGS) $(call to_tcl_path,$(VERILOG_SOURCES))\" >> $@\nendif\nifdef SCRIPT_FILE\n\t@echo \"do $(SCRIPT_FILE)\" >> $@\nendif\nifneq ($(CFG_TOPLEVEL),)\n\t@echo \"asim $(ASIM_ARGS) +access +w_nets -interceptcoutput $(GPI_ARGS) $(CFG_TOPLEVEL) $(EXTRA_TOPS)\" >> $@\nelse\n\t@echo \"asim $(ASIM_ARGS) +access +w_nets -interceptcoutput $(GPI_ARGS) $(COCOTB_TOPLEVEL) $(EXTRA_TOPS)\" >> $@\nendif\nifeq ($(WAVES),1)\n\t@echo \"log -recursive *\" >> $@\nendif\nifeq ($(GUI),1)\n\t@echo \"wave -rec *\" >> $@\nelse\n\t@echo \"run -all\" >> $@\n\t@echo \"endsim\" >> $@\nifeq ($(COCOTB_USER_COVERAGE),1)\n\t@echo \"acdb report -cov $(COVERAGE_TYPES) -db $(TOPLEVEL_LIBRARY).acdb -html -o coverage/acdb_report.html\" >> $@\n\t@echo \"acdb report -cov $(COVERAGE_TYPES) -db $(TOPLEVEL_LIBRARY).acdb -txt -o coverage/acdb_report.txt\" >> $@\nendif\n\t@echo \"exit\" >> $@\nendif\n\n# Note it's the redirection of the output rather than the 'do' command\n# that turns on batch mode (i.e. exit on completion/error)\n$(COCOTB_RESULTS_FILE): $(SIM_BUILD)/runsim.tcl $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\tset -o pipefail; GPI_EXTRA=$(GPI_EXTRA) TOPLEVEL_LANG=$(TOPLEVEL_LANG) \\\n\tCOCOTB_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)\n\n\t$(call check_results)\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.vcs",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifneq ($(VHDL_SOURCES),)\n\n$(COCOTB_RESULTS_FILE):\n\t@echo \"Skipping simulation as VHDL is not supported on simulator=$(SIM)\"\n\nelse\n\nCMD_BIN := vcs\n\nifdef VCS_BIN_DIR\n    CMD := $(call find_command,$(VCS_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n    VCS_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nifdef VERILOG_INCLUDE_DIRS\n    COMPILE_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS))\nendif\n\nifeq ($(PYTHON_ARCH),64bit)\n    COMPILE_ARGS += -full64\nendif\n\nifeq ($(GUI),1)\n    EXTRA_ARGS += -gui -kdb\nendif\n\n# Avoid linker \"undefined reference to\" error\nCOMPILE_ARGS += -LDFLAGS -Wl,--no-as-needed\n\n# Enables globally access for read, write, and callback capabilities.\nCOMPILE_ARGS += +acc+3\n\n# Enables globally debug capabilities.\nCOMPILE_ARGS += -debug_access+all\n\n# TODO:\n# investigate +vpi+1 option which reduces memory requirements\n\n# Compilation phase\n$(SIM_BUILD)/simv: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) | $(SIM_BUILD)\n\tcd $(SIM_BUILD) && \\\n\tCOCOTB_TOPLEVEL=$(call deprecate,TOPLEVEL,COCOTB_TOPLEVEL) \\\n\t$(CMD) -top $(COCOTB_TOPLEVEL) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) -sverilog \\\n\t-timescale=$(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) \\\n\t$(EXTRA_ARGS) -load $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi vcs) $(COMPILE_ARGS) $(VERILOG_SOURCES)\n\n# Execution phase\n$(COCOTB_RESULTS_FILE): $(SIM_BUILD)/simv $(CUSTOM_SIM_DEPS)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\tCOCOTB_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) \\\n\t$(SIM_CMD_PREFIX) $(SIM_BUILD)/simv $(SIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX)\n\n\t$(call check_results)\n\nendif\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.verilator",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nifneq ($(or $(filter-out $(TOPLEVEL_LANG),verilog),$(VHDL_SOURCES)),)\n\nresults.xml:\n\t@echo \"Skipping simulation as only Verilog is supported on simulator=$(SIM)\"\ndebug: results.xml\n\nelse\n\nCMD_BIN := verilator\n\nifdef VERILATOR_BIN_DIR\n  CMD := $(call find_command,$(VERILATOR_BIN_DIR)/$(CMD_BIN))\nelse\n  # auto-detect bin dir from system path\n  CMD := $(call find_command,$(CMD_BIN))\n  VERILATOR_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nVLT_MIN := 5.036\nVLT_VERSION := $(shell $(CMD) --version | cut -d \" \" -f 2)\nMIN_VERSION := $(shell printf \"%s\\n%s\\n\" \"$(VLT_MIN)\" \"$(VLT_VERSION)\" | sort -g | head -1)\nifneq ($(MIN_VERSION),$(VLT_MIN))\n  $(error cocotb requires Verilator $(VLT_MIN) or later, but using $(VLT_VERSION))\nendif\n\nifdef COCOTB_TOPLEVEL\n  TOPMODULE_ARG := --top-module $(COCOTB_TOPLEVEL)\nelse\n  TOPMODULE_ARG :=\nendif\n\nifeq ($(VERILATOR_SIM_DEBUG), 1)\n  COMPILE_ARGS += --debug -CFLAGS \"-DVL_DEBUG -DVERILATOR_SIM_DEBUG -g -Og\"\n  DEBUG = +verilator+debug\n  BUILD_ARGS += OPT_FAST=-Og OPT_SLOW=-Og OPT_GLOBAL=-Og\nendif\n\nifeq ($(VERILATOR_TRACE),1)\n  COMPILE_ARGS += --trace --trace-structs\n  SIM_ARGS += --trace\nendif\n\nCOMPILE_ARGS += --timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION)\n\n_COCOTB_LIB_DIR = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-dir)\nCOMPILE_ARGS += --vpi --public-flat-rw --prefix Vtop -o Vtop -LDFLAGS \"-Wl,-rpath,$(_COCOTB_LIB_DIR) -L$(_COCOTB_LIB_DIR) -lcocotbvpi_verilator\"\n\nifdef VERILOG_INCLUDE_DIRS\n  COMPILE_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS))\nendif\n\nVERILATOR_CPP := $(shell $(PYTHON_BIN) -m cocotb_tools.config --share)/lib/verilator/verilator.cpp\n\n$(SIM_BUILD)/Vtop.mk: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) $(VERILATOR_CPP) | $(SIM_BUILD)\n\t$(CMD) -cc --exe -Mdir $(SIM_BUILD) $(TOPMODULE_ARG) $(COMPILE_ARGS) $(EXTRA_ARGS) $(VERILOG_SOURCES) $(VERILATOR_CPP)\n\n# Compilation phase\n$(SIM_BUILD)/Vtop: $(SIM_BUILD)/Vtop.mk\n\t$(MAKE) -C $(SIM_BUILD) $(BUILD_ARGS) -f Vtop.mk\n\n$(COCOTB_RESULTS_FILE): $(SIM_BUILD)/Vtop $(CUSTOM_SIM_DEPS)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\t-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) \\\n        $(SIM_CMD_PREFIX) $< $(SIM_ARGS) $(EXTRA_ARGS) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(DEBUG) $(SIM_CMD_SUFFIX)\n\n\t$(call check_results)\n\ndebug:\n\t$(MAKE) VERILATOR_SIM_DEBUG=1 SIM_CMD_PREFIX=\"gdb --args\" $(COCOTB_RESULTS_FILE)\n\n\nendif\n"
  },
  {
    "path": "src/cocotb_tools/makefiles/simulators/Makefile.xcelium",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Common Makefile for Cadence Xcelium\n\nCMD_BIN := xrun\n\nifdef XCELIUM_BIN_DIR\n    CMD := $(call find_command,$(XCELIUM_BIN_DIR)/$(CMD_BIN))\nelse\n    # auto-detect bin dir from system path\n    CMD := $(call find_command,$(CMD_BIN))\n    XCELIUM_BIN_DIR := $(shell dirname $(CMD))\nendif\n\nifdef VERILOG_INCLUDE_DIRS\n    COMPILE_ARGS += $(addprefix +incdir+, $(VERILOG_INCLUDE_DIRS))\nendif\n\nEXTRA_ARGS += $(COMPILE_ARGS)\nEXTRA_ARGS += $(SIM_ARGS)\nEXTRA_ARGS += -licqueue\n\nifeq ($(PYTHON_ARCH),64bit)\n    EXTRA_ARGS += -64\nendif\n\nEXTRA_ARGS += -xmlibdirpath $(SIM_BUILD)\nifeq ($(DEBUG),1)\n    EXTRA_ARGS += -pliverbose\n    EXTRA_ARGS += -messages\n    EXTRA_ARGS += -plidebug             # Enhance the profile output with PLI info\n    EXTRA_ARGS += -plierr_verbose       # Expand handle info in PLI/VPI/VHPI messages\n    EXTRA_ARGS += -vpicompat 1800v2005  #  <1364v1995|1364v2001|1364v2005|1800v2005> Specify the IEEE VPI\nelse\n    EXTRA_ARGS += -plinowarn\nendif\n\nifeq ($(GUI),1)\n    EXTRA_ARGS += -gui\nelse\n    EXTRA_ARGS +=\nendif\n\n# Xcelium errors out if multiple timescales are specified on the command line.\nifneq (,$(filter -timescale%,$(EXTRA_ARGS)))\n    $(error Please use COCOTB_HDL_TIMEUNIT and COCOTB_HDL_TIMEPRECISION to specify timescale.)\nendif\n\n# Loading the VHPI library causes an error, so we always load the VPI library and supply\n# GPI_EXTRA=$(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi xcelium) if needed.\n\n# Xcelium will use default vlog_startup_routines symbol only if VPI library name is libvpi.so\nGPI_ARGS = -loadvpisim $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vpi xcelium):vlog_startup_routines_bootstrap\nifeq ($(TOPLEVEL_LANG),verilog)\n    HDL_SOURCES = $(VERILOG_SOURCES)\n    ROOT_LEVEL = $(COCOTB_TOPLEVEL)\n    EXTRA_ARGS += -top $(COCOTB_TOPLEVEL)\n    ifneq ($(VHDL_SOURCES),)\n        HDL_SOURCES += $(VHDL_SOURCES)\n        GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi xcelium):cocotbvhpi_entry_point\n    endif\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    GPI_EXTRA = $(shell $(PYTHON_BIN) -m cocotb_tools.config --lib-name-path vhpi xcelium):cocotbvhpi_entry_point\n    EXTRA_ARGS += -top $(COCOTB_TOPLEVEL)\n    # Xcelium 23.09.004 fixes cocotb issue #1076 as long as the following define\n    # is set.\n    EXTRA_ARGS += -NEW_VHPI_PROPAGATE_DELAY\nifdef RTL_LIBRARY\n    $(warning Using RTL_LIBRARY is deprecated, please use TOPLEVEL_LIBRARY instead.)\n    TOPLEVEL_LIBRARY ?= $(RTL_LIBRARY)\nelse\n    TOPLEVEL_LIBRARY ?= work\nendif\n    MAKE_LIB = -makelib $(TOPLEVEL_LIBRARY)\n    END_LIB = -endlib\n    HDL_SOURCES = $(VHDL_SOURCES)\n    ifneq ($(VERILOG_SOURCES),)\n        HDL_SOURCES += $(VERILOG_SOURCES)\n    endif\nelse\n    $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\n# Builds a list of arguments to support VHDL libraries specified in VHDL_SOURCES_*:\nLIBS := $(foreach LIB, $(VHDL_LIB_ORDER),-makelib $(LIB) $(VHDL_SOURCES_$(LIB)) -endlib)\n\n$(COCOTB_RESULTS_FILE): $(HDL_SOURCES) $(CUSTOM_COMPILE_DEPS) $(CUSTOM_SIM_DEPS) | $(SIM_BUILD)\n\t$(RM) $(COCOTB_RESULTS_FILE)\n\n\t# Make sure all libs in SOURCES_VHDL_* are mentioned in VHDL_LIB_ORDER and vice versa\n\t$(foreach LIB, $(VHDL_LIB_ORDER), $(check_vhdl_sources))\n\t$(foreach SOURCES_VAR, $(filter VHDL_SOURCES_%, $(.VARIABLES)), $(check_lib_order))\n\n\tset -o pipefail; \\\n\tCOCOTB_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) \\\n\t$(SIM_CMD_PREFIX) $(CMD) -timescale $(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) \\\n\t-vhdl_time_precision \"$(COCOTB_HDL_TIMEPRECISION)\" \\\n\t$(EXTRA_ARGS) $(GPI_ARGS) $(INCDIRS) -access +rwc -createdebugdb $(LIBS) $(MAKE_LIB) $(HDL_SOURCES) $(END_LIB) $(call deprecate,PLUSARGS,COCOTB_PLUSARGS) $(SIM_CMD_SUFFIX)\n\n\t$(call check_results)\n"
  },
  {
    "path": "src/cocotb_tools/py.typed",
    "content": ""
  },
  {
    "path": "src/cocotb_tools/pytest/__init__.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Plugin to use pytest as regression manager in cocotb.\"\"\"\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_compat.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Compatibility layer between cocotb and pytest. Convert cocotb decorators to pytest markers.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import Iterable, Sequence\nfrom typing import Any\n\nimport pytest\nfrom pytest import Class, Mark, Module, mark\n\nfrom cocotb._decorators import Test, TestGenerator\nfrom cocotb.simtime import TimeUnit\n\n\ndef is_cocotb_decorator(obj: object) -> bool:\n    \"\"\"Check if provided object was decorated with cocotb decorator.\"\"\"\n    return isinstance(obj, (Test, TestGenerator))\n\n\ndef cocotb_decorator_as_pytest_marks(\n    collector: Module | Class, name: str, obj: object\n) -> object:\n    \"\"\"Convert object decorated with cocotb decorator to ``@pytest.mark.*``.\n\n    Args:\n        collector: Pytest collector like Python Class or Module.\n        name: Name of object.\n        obj: Object decorated with cocotb decorator like ``@cocotb.test``.\n\n    Returns:\n        Unwrapped decorated object with added pytest marks.\n    \"\"\"\n    if isinstance(obj, Test):\n        return _as_pytest_marks(\n            collector,\n            name,\n            obj.func,\n            timeout=obj.timeout,\n            expect_fail=obj.expect_fail,\n            expect_error=obj.expect_error,\n            skip=obj.skip,\n            stage=obj.stage,\n        )\n\n    if isinstance(obj, TestGenerator):\n        return _as_pytest_marks(\n            collector,\n            name,\n            obj.func,\n            timeout=obj.timeout,\n            expect_fail=obj.expect_fail,\n            expect_error=obj.expect_error,\n            skip=obj.skip,\n            stage=obj.stage,\n            options=obj.options,\n        )\n\n    return obj\n\n\ndef _as_pytest_marks(\n    collector: Module | Class,\n    name: str,\n    obj: object,\n    timeout: tuple[float, TimeUnit] | None,\n    expect_fail: bool,\n    expect_error: Iterable[\n        type[BaseException] | pytest.RaisesExc[BaseException] | pytest.RaisesGroup[Any]\n    ],\n    skip: bool,\n    stage: int,\n    options: list[\n        tuple[str, Sequence[object]] | tuple[Sequence[str], Sequence[Sequence[object]]]\n    ]\n    | None = None,\n) -> object:\n    if getattr(obj, \"__test__\", False):\n        return obj  # object already unwrapped for pytest, skip it\n\n    markers: list[Mark] = []\n\n    # Replace @cocotb.parametrize(...) decorator with equivalent @pytest.mark.parametrize(...) markers\n    # @cocotb.parametrize(x=[1, 2], y=[3, 4])\n    # vvv\n    # @pytest.parametrize(\"x\", [1, 2])\n    # @pytest.parametrize(\"y\", [3, 4])\n    for names, values in options or ():\n        if isinstance(names, str):\n            markers.append(mark.parametrize(names, values).mark)\n        else:\n            markers.append(mark.parametrize(\",\".join(names), values).mark)\n\n    if stage:\n        # Supported by external plugin: pytest-order\n        markers.append(mark.order(stage).mark)\n\n    if skip:\n        markers.append(mark.skip().mark)\n\n    if expect_fail or expect_error:\n        markers.append(\n            mark.xfail(\n                raises=tuple(expect_error) if expect_error else None,  # type: ignore[arg-type]\n                strict=True,\n            ).mark\n        )\n\n    if timeout:\n        markers.append(mark.cocotb_timeout(duration=timeout[0], unit=timeout[1]).mark)\n\n    markers.append(mark.cocotb_test().mark)\n    markers.extend(getattr(obj, \"pytestmark\", ()))\n\n    # Add pytest marks to object\n    setattr(obj, \"pytestmark\", markers)\n\n    # __test__ will tell pytest to treat this object as test item\n    setattr(obj, \"__test__\", True)\n\n    # This is needed by pytest code inspection mechanism\n    setattr(collector.obj, name, obj)\n\n    return obj\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_controller.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Internal cocotb plugin called ``cocotb_controller`` to run on top of cocotb runners.\n\nThis part of code is executed only from the main pytest parent process and not from\npytest sub-process (simulator).\n\nMain responsibilities for this internal plugin are:\n\n* Binding collected cocotb tests to cocotb runners\n* Handling test reports received from pytest sub-process (simulator) over IPC (Inter-Process Communication)\n* Combining (mangling) identifiers from cocotb runner with cocotb test to generate new unique identifier\n* Attaching additional properties about cocotb tests in JUnit XML tests report\n\"\"\"\n\nfrom __future__ import annotations\n\nimport inspect\nimport os\nimport shlex\nfrom collections.abc import Generator, Iterable\nfrom multiprocessing.connection import Client, Listener\nfrom pathlib import Path\nfrom threading import RLock, Thread\nfrom typing import Any\n\nfrom pytest import (\n    Class,\n    Collector,\n    CollectReport,\n    Config,\n    ExceptionInfo,\n    ExitCode,\n    FixtureDef,\n    Function,\n    Item,\n    Module,\n    Session,\n    TestReport,\n    hookimpl,\n)\n\nimport cocotb\nfrom cocotb_tools import _env\nfrom cocotb_tools.pytest._handle import MockSimHandle\nfrom cocotb_tools.pytest._junitxml import JUnitXML\nfrom cocotb_tools.pytest._runner import Runner\nfrom cocotb_tools.pytest.hdl import _get_simulator\n\n\nclass Controller:\n    \"\"\"Internal cocotb plugin for pytest dedicated for the main pytest parent process.\"\"\"\n\n    def __init__(self, config: Config) -> None:\n        \"\"\"Create new instance of internal cocotb plugin for pytest.\n\n        Args:\n            config: Configuration object.\n        \"\"\"\n        # Pytest configuration object\n        self._config: Config = config\n\n        # Pytest is printing test results in real-time when test finished execution\n        # With default capturing mode (fd), it will print '.', 's', 'x', 'F', 'E' per test\n        # The main pytest process will run test functions that will run HDL simulations (aka runners)\n        # Each HDL simulation will take some time and it will execute N cocotb tests\n        # To print test results in real-time from running cocotb tests,\n        # we need a separate single thread that will run in parallel to running HDL simulation and\n        # receive test reports from it\n        # On top of that, xdist will schedule HDL simulations in separate processes\n        # producing cocotb test reports in parallel and independently to each other\n        self._listener: Listener\n        self._thread: Thread | None = None\n\n        # RLock (Reentrant Lock) is needed to protect resources in other plugins\n        # when the running thread will invoke the pytest_runtest_logreport hook to\n        # notify other plugins about new cocotb test result received from HDL simulator\n        # Pytest hooks can be wrapped and called recursively\n        self._lock = RLock()\n\n        # Create only a single reporter service in the main parent process\n        # In case when plugin is used with xdist, it must be created within xdist dsession to\n        # receive test results from xdist workers\n        if not _env.exists(\"COCOTB_PYTEST_REPORTER_ADDRESS\"):\n            self._listener = Listener()\n            self._thread = Thread(target=self._handle_test_reports)\n            os.environ[\"COCOTB_PYTEST_REPORTER_ADDRESS\"] = str(self._listener.address)\n\n    @hookimpl(tryfirst=True)\n    def pytest_configure(self, config: Config) -> None:\n        \"\"\"Configure environment for the main pytest parent process.\n\n        Args:\n            config: Pytest configuration object.\n        \"\"\"\n        option = config.option\n\n        invocation_dir: Path | str = (\n            option.cocotb_pytest_dir or config.invocation_params.dir or Path.cwd()\n        )\n\n        invocation_args: Iterable[str] = (\n            option.cocotb_pytest_args or config.invocation_params.args or ()\n        )\n\n        # Populate environment variables for cocotb runners that will run HDL simulators\n        os.environ[\"PYGPI_USERS\"] = \",\".join(option.pygpi_users)\n        os.environ[\"COCOTB_RANDOM_SEED\"] = str(option.cocotb_seed)\n        os.environ[\"COCOTB_PYTEST_DIR\"] = str(Path(invocation_dir).resolve())\n        os.environ[\"COCOTB_PYTEST_ARGS\"] = shlex.join(invocation_args)\n\n        if option.cocotb_waveform_viewer:\n            os.environ[\"COCOTB_WAVEFORM_VIEWER\"] = option.cocotb_waveform_viewer\n\n        if option.cocotb_attach:\n            os.environ[\"COCOTB_ATTACH\"] = str(option.cocotb_attach)\n\n        if option.cocotb_resolve_x:\n            os.environ[\"COCOTB_RESOLVE_X\"] = option.cocotb_resolve_x\n\n        if option.cocotb_scheduler_debug:\n            os.environ[\"COCOTB_SCHEDULER_DEBUG\"] = \"1\"\n\n        if option.cocotb_trust_inertial_writes:\n            os.environ[\"COCOTB_TRUST_INERTIAL_WRITES\"] = \"1\"\n\n        # Mock cocotb module for the main pytest parent process\n        # Otherwise pytest can raise an exception when loading Python module\n        #\n        # When invoking pytest with --collect-only option, markers like\n        # @pytest.mark.skip() or @pytest.mark.skipif() are ignored anyway because\n        # test will be skipped during runtime (pytest without --collect-only).\n        #\n        # There is no need for the main pytest process to collect tests from HDL simulators.\n        # Cocotb tests will be properly collected and executed with valid cocotb.top simulation handle by\n        # pytest instance that is running from HDL simulator and report back to the main pytest process.\n        setattr(cocotb, \"SIM_NAME\", _get_simulator(config))\n        setattr(cocotb, \"SIM_VERSION\", \"\")\n        setattr(cocotb, \"top\", MockSimHandle())\n\n    @hookimpl(tryfirst=True, wrapper=True)\n    def pytest_pycollect_makeitem(\n        self, collector: Module | Class, name: str, obj: object\n    ) -> Generator[\n        None,\n        Item | Collector | list[Item | Collector] | None,\n        list[Item | Collector] | None,\n    ]:\n        \"\"\"Collect cocotb runners and cocotb tests from Python modules.\n\n        Args:\n            collector: Python module or class containing cocotb runners or cocotb tests.\n            name: Name of collected item (test function, cocotb runner, cocotb test).\n            obj: Object representation of collected item (test function, cocotb runner, cocotb test).\n\n        Yields:\n            Collected test function, cocotb runner or cocotb test.\n        \"\"\"\n        result: Item | Collector | list[Item | Collector] | None = yield\n\n        if result is None:\n            return None\n\n        items: Iterable[Item | Collector] = (\n            result if isinstance(result, list) else (result,)\n        )\n\n        return list(self._collect(collector, items))\n\n    @hookimpl(tryfirst=True)\n    def pytest_runtest_setup(self, item: Item) -> None:\n        \"\"\"Setup environment for pytest sub-process (simulator)\n        that will be started as test function from the main pytest parent process.\n\n        Args:\n            item: Test function.\n        \"\"\"\n        # Expose cocotb runner nodeid and keywords from the main pytest parent process\n        # to pytest sub-process (simulator) via environment variables\n        os.environ[\"COCOTB_PYTEST_NODEID\"] = item.nodeid\n        os.environ[\"COCOTB_PYTEST_KEYWORDS\"] = \",\".join(item.keywords)\n\n    def _get_mangled_nodeid(self, report: TestReport) -> str:\n        \"\"\"Get mangled address of test node identifier as combination of node identifiers from cocotb runner and test.\n\n        Pytest is always using ``/`` as path separator (compatible with POSIX).\n        Node identifier is mostly represented as: ``<path_to_file>::[<class_name>::]<function_name>``\n\n        To get unique test identifier for cocotb test from various different cocotb runners,\n        we need to combine node identifier from cocotb runner and cocotb test.\n\n        Args:\n            report: Test report from simulator (pytest sub-process).\n\n        Returns:\n            Mangled node identifier.\n        \"\"\"\n        runner_nodeid: str = getattr(report, \"runner_nodeid\", \"\")\n        runner_path, _, runner_function = runner_nodeid.partition(\"::\")\n        item_path, _, item_function = report.nodeid.partition(\"::\")\n\n        if runner_path == item_path:\n            # We don't need to include path from item because it is already present in runner\n            return f\"{runner_nodeid}::{item_function}\"\n\n        # Pytest is always using / as separator regadless of OS environment\n        runner_dir: str = runner_path.rpartition(\"/\")[0]\n        item_dir: str = item_path.rpartition(\"/\")[0]\n\n        if item_dir.startswith(runner_dir):\n            test_module: str = (\n                item_path.removeprefix(runner_dir)\n                .removesuffix(\".py\")\n                .strip(\"/\")\n                .replace(\"/\", \".\")\n            )\n\n            return f\"{runner_nodeid}::{test_module}::{item_function}\"\n\n        return f\"{runner_nodeid}::{report.nodeid}\"\n\n    @hookimpl(tryfirst=True)\n    def pytest_sessionstart(self, session: Session) -> None:\n        \"\"\"Start thread to receive test reports from pytest sub-process (simulator).\"\"\"\n        JUnitXML.register(session.config)\n\n        if self._thread:\n            self._thread.start()\n\n    @hookimpl(tryfirst=True)\n    def pytest_sessionfinish(\n        self, session: Session, exitstatus: int | ExitCode\n    ) -> None:\n        \"\"\"Stop started thread.\"\"\"\n        if self._thread:\n            with Client(address=self._listener.address) as client:\n                client.send(None)  # notify _run thread to exit\n\n            self._thread.join()\n            self._listener.close()\n\n    def _collect(\n        self, collector: Collector, items: Iterable[Item | Collector]\n    ) -> Generator[Item | Collector, None, None]:\n        \"\"\"Collect test items including cocotb runners and cocotb tests.\n\n        It will help to build hierarchy tree of cocotb runners and cocotb tests.\n\n        When invoking ``pytest`` with ``--collect-only`` option::\n\n            <Dir tests>\n                <Module test_sample_module.py>\n                    <Runner test_sample_module>\n                        <Testbench test_sample_module>\n                            <Function test_feature>\n\n        When invoking ``pytest`` without ``--collect-only`` option::\n\n            <Dir tests>\n                <Module test_sample_module.py>\n                    <Function test_sample_module>\n\n        Tree created with ``--collect-only`` option is to help users to visualize\n        hierarchy tree of cocotb runners and cocotb tests.\n\n        Args:\n            collector: Collector used to collect test items, mostly Python module.\n            items: Collected test items by collector.\n\n        Yields:\n            Test items, including cocotb runners and cocotb tests.\n        \"\"\"\n        collectonly: bool = collector.config.option.collectonly\n        runner: Runner | None = collector.getparent(Runner)\n\n        for item in items:\n            if not isinstance(item, Function):\n                yield item\n\n            elif inspect.iscoroutinefunction(item.function):\n                if item.get_closest_marker(\"cocotb_runner\"):\n                    item.warn(\n                        UserWarning(\n                            \"You have applied @pytest.mark.cocotb_runner marker on coroutine function. \"\n                            f\"This is an usage mistake. Please remove it from {item.nodeid!r}\"\n                        )\n                    )\n                elif item.get_closest_marker(\"cocotb_test\"):\n                    if runner:\n                        # Collected cocotb test must be always under cocotb runner\n                        if collectonly:\n                            # Show collected cocotb test under cocotb runner when invoking pytest --collect-only\n                            # It will help user to visualize hierarchy tree of cocotb tests and cocotb runners\n                            yield item\n                        else:\n                            # Add cocotb test keywords to cocotb runner\n                            # This will allow to run cocotb runner by using keywords associated with cocotb test\n                            runner.item.extra_keyword_matches.update(item.keywords)\n                            # Skip cocotb test here, it will be collected by pytest that is running from HDL simulator\n                else:\n                    yield item  # some coroutine test function that is not part of cocotb\n\n            elif item.get_closest_marker(\"cocotb_test\"):\n                item.warn(\n                    UserWarning(\n                        \"You have applied @pytest.mark.cocotb_test marker on non-async test function. \"\n                        f\"This is an usage mistake. Please remove it from {item.nodeid!r}\"\n                    )\n                )\n            elif item.get_closest_marker(\"cocotb_runner\"):\n                # Avoid recursion of cocotb runners\n                if not runner:\n                    # <Module file>\n                    #   <Function name>       <--- cocotb runner as test function\n                    #   <Runner name>         <--- cocotb runner as collector of cocotb tests\n                    #     <Testbench name>    <--- test module aka testbench (Python module with cocotb tests)\n                    #       <Function name>   <--- cocotb test\n                    yield item\n\n                    if item.parent:\n                        yield Runner.from_parent(\n                            item.parent,\n                            name=item.name,\n                            item=item,\n                        )\n            else:\n                yield item  # some test function that is not part of cocotb\n\n    def pytest_fixture_setup(\n        self, fixturedef: FixtureDef, request: Any\n    ) -> object | None:\n        \"\"\"Skip applying async fixture to non-async test functions when fixture autouse was used.\n\n        Args:\n            fixturedef: The fixture definition object.\n            request: The fixture request object.\n\n        Returns:\n            True when async fixture will be skipped. Otherwise None and continue with next plugin.\n        \"\"\"\n        fixturefunc = fixturedef.func\n        is_coroutine: bool = inspect.iscoroutinefunction(fixturefunc)\n        is_async_generator: bool = inspect.isasyncgenfunction(fixturefunc)\n        autouse: bool = getattr(fixturedef, \"_autouse\", False)\n\n        if autouse and (is_coroutine or is_async_generator):\n            cache_key = fixturedef.cache_key(request)\n            fixturedef.cached_result = (None, cache_key, None)\n            return True\n\n        return None\n\n    @hookimpl(tryfirst=True, wrapper=True)\n    def pytest_runtest_logreport(\n        self, report: TestReport\n    ) -> Generator[None, None, None]:\n        with self._lock:\n            yield\n\n    def _handle_test_reports(self) -> None:\n        \"\"\"Main thread for receiving cocotb test reports from pytest sub-process (simulator).\"\"\"\n        config: Config = self._config\n        hook = config.hook\n\n        while True:\n            try:\n                with self._listener.accept() as connection:\n                    data: dict[str, Any] | None = connection.recv()\n\n                    if data is None:\n                        return  # terminate thread\n\n                    report: CollectReport | TestReport | None = (\n                        hook.pytest_report_from_serializable(config=config, data=data)\n                    )\n\n                    if isinstance(report, TestReport):\n                        report.nodeid = self._get_mangled_nodeid(report)\n                        hook.pytest_runtest_logreport(report=report)\n\n            except BaseException:\n                self._notify_exception(ExceptionInfo.from_current())\n\n    def _notify_exception(self, excinfo: ExceptionInfo) -> None:\n        self._config.notify_exception(excinfo, self._config.option)\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_fixture.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Helper classes to support cocotb coroutines with pytest fixtures.\"\"\"\n\nfrom __future__ import annotations\n\nfrom types import TracebackType\nfrom typing import Any, Union, cast\n\nfrom cocotb._test_manager import TestManager\n\n\nclass AsyncFixtureCachedResult(\n    tuple[\n        TestManager, Any, Union[tuple[BaseException, Union[TracebackType, None]], None]\n    ]\n):\n    \"\"\"Cached result from asynchronous fixture.\n\n    Class compatible with pytest fixture cached result.\n    Pytest is expecting 3-elements tuple: (result, cache_key, None) or\n    (None, cache_key, (exception, exception.__traceback__)).\n\n    Unfortunately, it must be valid before asynchronous task.\n    In this case, asynchronous cache result will contain (task, cache_key, None)\n    and result will be obtained later.\n\n    Summary:\n\n        (task, cache_key, None)                 - asynchronous task not completed (default)\n        (result, cache_key, None)               - asynchronous task completed successfully\n        (None, cache_key, (e, e.__traceback__)) - asynchronous task completed with exception\n    \"\"\"\n\n    def __getitem__(self, index: Any) -> Any:\n        \"\"\"Dynamically get result from asynchronous task.\"\"\"\n        task = cast(\"TestManager\", super().__getitem__(0))._main_task\n\n        if not task.done() or index == 1:\n            return super().__getitem__(index)\n\n        exception: BaseException | None = task.exception()\n\n        if index == 0:\n            return None if exception else task.result()\n\n        if index == 2 and exception:\n            return (exception, exception.__traceback__)\n\n        return None\n\n\ndef resolve_fixture_arg(arg: Any) -> Any:\n    \"\"\"Resolve fixture argument.\"\"\"\n    return arg._main_task.result() if isinstance(arg, TestManager) else arg\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_handle.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Facilities to mock cocotb sim handle when collecting test items\nfrom the main pytest parent process, outside of HDL simulation environment.\n\nThis is need to avoid raising an :py:exc:`AttributeError` or :py:exc:`KeyError` exception\nwhen accessing :py:data:`cocotb.top` global variable during pytest collection phase.\n\"\"\"\n\nfrom __future__ import annotations\n\n\nclass MockSimHandle:\n    \"\"\"Mocking :py:class:`cocotb.handle.SimHandleBase`.\"\"\"\n\n    def __getitem__(self, key: str) -> MockSimHandle:\n        \"\"\"Mock nested access to item ``obj[a][b][c]``.\"\"\"\n        return self\n\n    def __getattr__(self, key: str) -> MockSimHandle:\n        \"\"\"Mock nested access to attribute ``obj.a.b.c``.\"\"\"\n        return self\n\n    def __call__(self, *args: object, **kwargs: object) -> MockSimHandle:\n        \"\"\"Mock calling methods.\"\"\"\n        return self\n\n    def __int__(self) -> int:\n        \"\"\"Mock casting to integer.\"\"\"\n        return 0\n\n    def __eq__(self, other: object) -> bool:\n        \"\"\"Mock ``==``.\"\"\"\n        return False\n\n    def __nq__(self, other: object) -> bool:\n        \"\"\"Mock ``!=``.\"\"\"\n        return False\n\n    def __le__(self, other: object) -> bool:\n        \"\"\"Mock ``<=``.\"\"\"\n        return False\n\n    def __lt__(self, other: object) -> bool:\n        \"\"\"Mock ``<``.\"\"\"\n        return False\n\n    def __ge__(self, other: object) -> bool:\n        \"\"\"Mock ``>=``.\"\"\"\n        return False\n\n    def __gt__(self, other: object) -> bool:\n        \"\"\"Mock ``>``.\"\"\"\n        return False\n\n    def __len__(self) -> int:\n        \"\"\"Mock collections.\"\"\"\n        return 0\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_init.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Loaded by simulator.\"\"\"\n\nfrom __future__ import annotations\n\nimport sys\n\nimport cocotb\nfrom cocotb_tools import _env\nfrom cocotb_tools.pytest._regression import RegressionManager\n\n\ndef run_regression() -> None:\n    \"\"\"Run regression using pytest as regression manager for cocotb tests.\"\"\"\n\n    # sys.path normally includes \"\" (the current directory), but does not appear to when Python is embedded.\n    # Add it back because users expect to be able to import files in their test directory.\n    sys.path.insert(0, \"\")\n\n    manager: RegressionManager = RegressionManager(\n        # Use the same command line arguments as from the main pytest parent process\n        *_env.as_args(\"COCOTB_PYTEST_ARGS\"),\n        # Node identifier of cocotb runner\n        nodeid=_env.as_str(\"COCOTB_PYTEST_NODEID\"),\n        # List of cocotb runner keywords\n        keywords=_env.as_list(\"COCOTB_PYTEST_KEYWORDS\"),\n        # Provide list of test modules (Python modules with cocotb tests) to be loaded\n        test_modules=_env.as_list(\"COCOTB_TEST_MODULES\"),\n        # Cocotb runner is using generated JUnit XML results file to determine\n        # if executed cocotb tests passed or failed. Test function (cocotb runner)\n        # from the main pytest parent process will also fail if any of cocotb test failed.\n        xmlpath=_env.as_str(\"COCOTB_RESULTS_FILE\"),\n        # Path to directory location from where pytest was invoked\n        invocation_dir=_env.as_path(\"COCOTB_PYTEST_DIR\"),\n        # IPC address (Unix socket, Windows pipe, TCP, ...) to tests reporter\n        reporter_address=_env.as_str(\"COCOTB_PYTEST_REPORTER_ADDRESS\"),\n        # Name of HDL top level design\n        toplevel=_env.as_str(\"COCOTB_TOPLEVEL\"),\n        # Initialization value for the random generator\n        seed=cocotb.RANDOM_SEED,\n    )\n\n    manager.start_regression()\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_junitxml.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Handling JUnit XML.\"\"\"\n\nfrom __future__ import annotations\n\nfrom _pytest.junitxml import LogXML, xml_key\nfrom pytest import Config, TestReport, hookimpl\n\n\nclass JUnitXML:\n    def __init__(self, log_xml: LogXML) -> None:\n        \"\"\"Create new instance of JUnit XML.\n\n        Args:\n            plugin: Handler to built-in pytest ``junitxml`` plugin.\n        \"\"\"\n        self._log_xml: LogXML = log_xml\n\n    @staticmethod\n    def register(config: Config) -> None:\n        \"\"\"Register new instance of JUnit XML if ``junitxml`` plugin was activated.\"\"\"\n        log_xml: LogXML | None = config.stash.get(xml_key, None)\n\n        if log_xml:\n            config.pluginmanager.register(JUnitXML(log_xml))\n\n    @hookimpl(tryfirst=True)\n    def pytest_runtest_logreport(self, report: TestReport) -> None:\n        \"\"\"Fixing classname and name attributes when nodeid contains multiple [] (``runner[]::test[]``).\"\"\"\n        # Pytest is using / as separator regardless of OS environment\n        address = (\n            report.nodeid.replace(\"/\", \".\").replace(\".py::\", \".\").replace(\"::\", \".\")\n        )\n        classname, _, name = address.rpartition(\".\")\n        reporter = self._log_xml.node_reporter(report)\n\n        reporter.add_attribute(\"classname\", classname)\n        reporter.add_attribute(\"name\", name)\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_logging.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Everything related with logging.\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nfrom logging import (\n    Filter,\n    LogRecord,\n    getLogger,\n    getLogRecordFactory,\n    setLogRecordFactory,\n)\nfrom typing import Callable\n\nfrom _pytest.logging import DEFAULT_LOG_FORMAT, LoggingPlugin\nfrom pytest import Config, Session, hookimpl\n\nimport cocotb\nfrom cocotb.simtime import TimeUnit, get_sim_time\n\nCOCOTB_LOG_FORMAT: str = (\n    \"%(sim_time_str)8s%(sim_time_unit)s %(levelname)-8s %(name)s %(message)s\"\n)\n\n\ndef get_level(name: str) -> int:\n    \"\"\"Get log level based on provided name.\n\n    Args:\n        name: Name of log level.\n\n    Returns:\n        Integer value of log level.\n    \"\"\"\n    return getattr(logging, name.upper(), 0)\n\n\nclass SimContextFilter(Filter):\n    \"\"\"Attach information about simulation to log record using log filter.\"\"\"\n\n    def __init__(self, config: Config) -> None:\n        \"\"\"Create new instance of simulation context filter.\n\n        Args:\n            config: The pytest configuration object.\n        \"\"\"\n        self._sim_time_unit: TimeUnit = config.option.cocotb_sim_time_unit\n        self._is_simulation: bool = getattr(cocotb, \"is_simulation\", False)\n\n    def filter(self, record: LogRecord) -> bool:\n        \"\"\"Attach information about simulation to log record.\"\"\"\n        if not hasattr(record, \"sim_time\"):\n            sim_time: int | float | None = self._get_sim_time()\n            record.sim_time_unit = self._sim_time_unit\n\n            if sim_time is None:\n                record.sim_time = 0\n                record.sim_time_str = \"-.--\"\n            else:\n                record.sim_time = sim_time\n                record.sim_time_str = f\"{sim_time:.2f}\"\n\n        return True\n\n    def _get_sim_time(self) -> int | float | None:\n        if self._is_simulation:\n            try:\n                return get_sim_time(self._sim_time_unit)\n            except RecursionError:\n                pass  # If get_sim_time will try to log\n\n        return None\n\n\nclass Logging:\n    \"\"\"Logging plugin to configure logging in pytest environment.\"\"\"\n\n    def __init__(self, config: Config) -> None:\n        \"\"\"Create new instance of logging plugin.\"\"\"\n        self._filter: Filter = SimContextFilter(config)\n        option = config.option\n\n        if not option.log_format and config.getini(\"log_format\") is DEFAULT_LOG_FORMAT:\n            option.log_format = COCOTB_LOG_FORMAT\n\n        create_log_record: Callable[..., LogRecord] = getLogRecordFactory()\n\n        def log_record_factory(*args: object, **kwargs: object) -> LogRecord:\n            record: LogRecord = create_log_record(*args, **kwargs)\n\n            self._filter.filter(record)\n\n            return record\n\n        setLogRecordFactory(log_record_factory)\n\n        if option.gpi_log_level:\n            getLogger(\"gpi\").setLevel(get_level(option.gpi_log_level))\n\n        if option.cocotb_log_level:\n            getLogger(\"cocotb\").setLevel(get_level(option.cocotb_log_level))\n\n    @hookimpl(tryfirst=True)\n    def pytest_sessionstart(self, session: Session) -> None:\n        \"\"\"Called after the :py:class:`pytest.Session` object has been created and before performing collection and\n        entering the run test loop.\n\n        Args:\n            session: The pytest session object.\n        \"\"\"\n        config: Config = session.config\n        plugin: LoggingPlugin | None = config.pluginmanager.get_plugin(\"logging-plugin\")\n\n        if plugin:\n            plugin.log_file_handler.addFilter(self._filter)\n            plugin.log_cli_handler.addFilter(self._filter)\n            plugin.caplog_handler.addFilter(self._filter)\n            plugin.report_handler.addFilter(self._filter)\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_option.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Generic option used as command line argument and entry in configuration file.\"\"\"\n\nfrom __future__ import annotations\n\nimport shlex\nfrom collections.abc import Iterable\nfrom pathlib import Path\nfrom typing import Any, Literal\n\nfrom pytest import Config, OptionGroup, Parser\n\nfrom cocotb_tools import _env\n\nPREFIXES: tuple[str, ...] = (\"cocotb_\", \"gpi_\", \"pygpi_\")\n\n\nIniType = Literal[\n    \"string\",\n    \"paths\",\n    \"pathlist\",\n    \"args\",\n    \"linelist\",\n    \"bool\",\n    \"int\",\n    \"float\",\n]\n\n\nclass Option:\n    \"\"\"Representation of single cocotb option that can be set from\n    configuration file, environment variable or command line.\"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        description: str,\n        default: object | None = None,\n        default_in_help: str | None = None,\n        environment: str | None = None,\n        **kwargs: object,\n    ) -> None:\n        \"\"\"Create new instance of single option.\n\n        Args:\n            name: Name of option.\n            description: Help description of option.\n            default: Default value for option.\n            default_in_help: Message used in option help instead of default value.\n            environment: Name of environment variable.\n            kwargs: Additional name arguments passed to :py:func:`argparse.ArgumentParser.add_argument`.\n        \"\"\"\n        self.name: str = name\n        self.description: str = description\n        self.extra: dict[str, Any] = dict(kwargs)\n        self.default: Any = default\n        self.default_in_help: str | None = default_in_help\n        self.environment: str = environment if environment else name.upper()\n\n    @property\n    def argument(self) -> str:\n        \"\"\"Command line argument.\"\"\"\n        return \"--\" + self.name.replace(\"_\", \"-\")\n\n    def add_to_parser(self, parser: Parser, group: OptionGroup) -> None:\n        argument: str = self.argument\n        default: Any = self.default\n        choices: tuple[str, ...] | None = self.extra.get(\"choices\")\n        argtype: type | None = self.extra.get(\"type\")\n        action: str | None = self.extra.get(\"action\")\n        nargs: str | None = self.extra.get(\"nargs\")\n        ini_type: IniType | None = None\n\n        # Map command line argument to option in configuration file\n        # Environment variable set by user can override default value for option\n        if action == \"store_true\":\n            default = _env.as_bool(self.environment, default)\n            ini_type = \"bool\"\n        elif nargs:\n            default = _env.as_list(self.environment, default)\n            ini_type = \"paths\" if argtype == Path else \"args\"\n        elif argtype is int:\n            default = _env.as_int(self.environment, default)\n            ini_type = \"int\"\n        elif argtype is Path:\n            default = _env.as_path(self.environment, default)\n            ini_type = \"string\"\n        elif argtype is shlex.split:\n            default = _env.as_args(self.environment, default)\n            ini_type = \"args\"\n        elif choices:\n            default = _env.as_str(self.environment, default).lower()\n            ini_type = \"string\"\n\n            # Resolve values passed from environment variables\n            if not default or default in choices:\n                pass\n            elif \"yes\" in choices and default in _env.TRUE:\n                default = \"yes\"\n            elif \"no\" in choices and default in _env.FALSE:\n                default = \"no\"\n            else:\n                raise ValueError(\n                    f\"Invalid value '{default}' for environment variable {self.environment}. \"\n                    f\"Expecting one of {(*choices,)}\"\n                )\n        else:\n            default = _env.as_str(self.environment, default)\n            ini_type = \"string\"\n\n        # Add option entry to configuration files (pyproject.toml, pytest.ini, ...)\n        parser.addini(\n            self.name,\n            help=f\"Default value for {argument}\",\n            type=ini_type,\n            default=default,\n        )\n\n        # Add option as command line argument\n        group.addoption(\n            argument,\n            help=(\n                f\"{self.description}\\n\"\n                f\"Environment variable: {self.environment}\\n\"\n                f\"Default: {self.default_in_help or default}\"\n            ),\n            **self.extra,\n        )\n\n\ndef add_options_to_parser(parser: Parser, name: str, options: Iterable[Option]) -> None:\n    \"\"\"Add options to parser.\n\n    Args:\n        parser:  Pytest parser.\n        name:    Name of group for options.\n        options: List of options to be added to parser.\n    \"\"\"\n    group: OptionGroup = parser.getgroup(name, description=f\"{name} options\")\n\n    for option in options:\n        option.add_to_parser(parser, group)\n\n\ndef populate_ini_to_options(config: Config, options: Iterable[Option]) -> None:\n    \"\"\"Populate values from configuration files to command line options.\n\n    Args:\n        config: The pytest configuration object.\n        options: List of options.\n    \"\"\"\n    for option in options:\n        value: Any = config.getoption(option.name)\n\n        if value is None:\n            setattr(config.option, option.name, config.getini(option.name))\n\n\ndef is_cocotb_option(name: str) -> bool:\n    \"\"\"Check if provided name is a cocotb option.\n\n    Args:\n        name: Name of option (command line argument, entry from configuration file, ...).\n\n    Returns:\n        True if option is cococtb option. Otherwise False.\n    \"\"\"\n    return any(name.startswith(prefix) for prefix in PREFIXES)\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_regression.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Pytest regression manager for cocotb.\"\"\"\n\nfrom __future__ import annotations\n\nimport bdb\nimport hashlib\nimport inspect\nimport random\nfrom collections import deque\nfrom collections.abc import AsyncGenerator, Awaitable, Generator, Iterable\nfrom functools import wraps\nfrom importlib import import_module\nfrom logging import Logger, getLogger\nfrom multiprocessing.connection import Client\nfrom pathlib import Path\nfrom time import sleep, time\nfrom typing import Any, Callable, Literal, cast\n\nfrom _pytest.config import default_plugins\nfrom _pytest.logging import LoggingPlugin\nfrom _pytest.outcomes import Exit, Skipped\nfrom pytest import (\n    CallInfo,\n    Class,\n    Collector,\n    Config,\n    ExceptionInfo,\n    ExitCode,\n    FixtureDef,\n    Function,\n    Item,\n    Mark,\n    Module,\n    PytestPluginManager,\n    Session,\n    TestReport,\n    hookimpl,\n)\n\nimport cocotb\nimport cocotb._shutdown\nimport cocotb._test_manager\nimport cocotb.simulator\nimport cocotb.types._resolve\nfrom cocotb._extended_awaitables import with_timeout\nfrom cocotb._gpi_triggers import Timer\nfrom cocotb._test_manager import TestManager\nfrom cocotb.simtime import TimeUnit, get_sim_time\nfrom cocotb_tools.pytest._fixture import (\n    AsyncFixtureCachedResult,\n    resolve_fixture_arg,\n)\nfrom cocotb_tools.pytest._test import RunningTestSetup\n\nRETRIES: int = 10\nINTERVAL: float = 0.1  # seconds\n\nAsyncFunction = Callable[..., Awaitable]\nWhen = Literal[\"setup\", \"call\", \"teardown\"]\n\"\"\"Test phase.\"\"\"\n\n\nclass SimFailure(BaseException):\n    \"\"\"A Test failure due to simulator failure. Used internally.\"\"\"\n\n\ndef finish_on_exception(method: Callable[..., Any]) -> Callable[..., Any]:\n    \"\"\"Wrap class method, capture exception, notify pytest and plugins, finish simulation.\"\"\"\n\n    @wraps(method)\n    def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any:\n        try:\n            return method(self, *args, **kwargs)\n        except BaseException:\n            # Notify pytest and plugins about exception. Finish pytest and simulation\n            self._notify_exception(ExceptionInfo.from_current())\n            self._finish()\n\n    return wrapper\n\n\nclass RegressionManager:\n    \"\"\"Pytest regression manager for cocotb.\"\"\"\n\n    _timer1 = Timer(1)\n\n    def __init__(\n        self,\n        *args: str,\n        nodeid: str = \"\",\n        toplevel: str = \"\",\n        reporter_address: str = \"\",\n        xmlpath: str | None = None,\n        keywords: Iterable[str] | None = None,\n        test_modules: Iterable[str] | None = None,\n        invocation_dir: Path | str | None = None,\n        seed: int | None = None,\n    ) -> None:\n        \"\"\"Create new instance of regression manager for cocotb tests.\n\n        Args:\n            args: Command line arguments for pytest.\n            nodeid: Node identifier of cocotb runner.\n            toplevel: Name of HDL top level design.\n            xmlpath: Override the ``--junit-xml`` option.\n            keywords: List of cocotb runner keywords.\n            test_modules: List of test modules (Python modules with cocotb tests) to be loaded.\n            invocation_dir: Path to directory location from where pytest was invoked.\n            reporter_address: IPC address (Unix socket, Windows pipe, TCP, ...) to tests reporter.\n            seed: Initialization value for the random number generator. If not provided, use current timestamp.\n        \"\"\"\n        self._toplevel: str = toplevel\n        \"\"\"Name of top level.\"\"\"\n\n        self._running_test: TestManager\n        \"\"\"Current running test: \"setup\", \"call\" or \"teardown\".\"\"\"\n\n        self._setups: deque[TestManager] = deque[TestManager]()\n        \"\"\"List of test setups that were populated from the :py:func:`pytest.hookspec.pytest_fixture_setup` hook.\"\"\"\n\n        self._call: TestManager | None = None\n        \"\"\"Test call that was populated from the :py:func:`pytest.hookspec.pytest_runtest_call` hook.\"\"\"\n\n        self._teardowns: deque[TestManager] = deque[TestManager]()\n        \"\"\"List of test teardowns that were populated from registered setup finalizers via\n        :py:meth:`pytest.FixtureRequest.addfinalizer`` method.\n        \"\"\"\n\n        self._scheduled: bool = False\n        self._index: int = 0\n        self._finished: bool = False\n        self._call_start: float | None = None\n        self._sim_time_start: float = 0\n        self._sim_time_unit: TimeUnit = \"step\"\n        self._nodeid: str = nodeid\n        self._keywords: list[str] = list(keywords) if keywords else []\n        self._reporter_address: str = reporter_address\n        self._logging_plugin: LoggingPlugin | None = None\n        self._logging_root_level: int = getLogger().level\n        self._logging_level: int = 0\n        self._logging_restored: bool = False\n        self._seed: int = int(time()) if seed is None else seed\n        self._random_state: Any = random.getstate()\n        self._random_x_resolver_state: Any = (\n            cocotb.types._resolve._randomResolveRng.getstate()\n        )\n\n        pluginmanager = PytestPluginManager()\n\n        # Initialize configuration object needed for pytest\n        config: Config = Config(\n            pluginmanager,\n            invocation_params=Config.InvocationParams(\n                args=args,\n                plugins=None,\n                dir=Path(invocation_dir) if invocation_dir else Path.cwd(),\n            ),\n        )\n\n        if args:\n            # Handle any \"-p no:plugin\" args.\n            pluginmanager.consider_preparse(args, exclude_only=True)\n\n        for plugin in default_plugins:\n            pluginmanager.import_plugin(plugin)\n\n        # Register itself as plugin\n        config.pluginmanager.register(self, name=\"cocotb_regression_manager\")\n\n        # Parse pytest command line arguments, including from PYTEST_ADDOPTS environment variable\n        config = config.pluginmanager.hook.pytest_cmdline_parse(\n            pluginmanager=config.pluginmanager, args=list(args)\n        )\n\n        # Get log file option from command line or from configuration file(s)\n        log_file: str | None = config.getoption(\"log_file\") or config.getini(\"log_file\")\n\n        # Unify it to current working directory where cocotb runner is running to avoid overriding it\n        if log_file:\n            config.option.log_file = Path(log_file).name\n\n        if xmlpath:\n            config.option.xmlpath = xmlpath\n\n        if test_modules:\n            # https://github.com/pytest-dev/pytest/issues/1596\n            # We cannot use --pyargs to load Python modules directly because conftest.py will be not loaded\n            config.option.pyargs = False\n            config.args = [\n                str(import_module(test_module).__file__) for test_module in test_modules\n            ]\n\n        # Create session context for tests\n        self._session: Session = Session.from_config(config)\n        self._session.exitstatus = ExitCode.OK  # this is unset in pytest by default\n\n        # Call all pytest_configure hooks from registered plugins to configure config object\n        self._session.config._do_configure()\n\n    @finish_on_exception\n    def start_regression(self) -> None:\n        \"\"\"Start regression manager.\"\"\"\n        self._session.config.hook.pytest_sessionstart(session=self._session)\n        self._session.config.hook.pytest_collection(session=self._session)\n        self._session.config.hook.pytest_runtestloop(session=self._session)\n\n    @hookimpl(tryfirst=True)\n    def pytest_sessionstart(self, session: Session) -> None:\n        \"\"\"Called after the :py:class:`pytest.Session` object has been created and\n        before performing collection and entering the run test loop.\n\n        Args:\n            session: The pytest session object.\n        \"\"\"\n        self._logging_plugin = session.config.pluginmanager.get_plugin(\"logging-plugin\")\n\n    @hookimpl(tryfirst=True)\n    def pytest_report_header(self, config: Config, start_path: Path) -> str | list[str]:\n        \"\"\"Return a string or list of strings to be displayed as header info for terminal reporting.\n\n        Args:\n            config: The pytest config object.\n            start_path: The starting dir.\n\n        Returns:\n            Lines returned by a plugin are displayed before those of plugins which ran before it.\n        \"\"\"\n        return [\n            f\"Running on {cocotb.SIM_NAME} version {cocotb.SIM_VERSION}\",\n            f\"Initialized cocotb v{cocotb.__version__} from {Path(__file__).parent.resolve()}\",\n            f\"Seeding Python random module with {self._seed}\",\n            f\"Top level set to {self._toplevel!r}\",\n        ]\n\n    @hookimpl(tryfirst=True, wrapper=True)\n    def pytest_pycollect_makeitem(\n        self, collector: Module | Class, name: str, obj: object\n    ) -> Generator[\n        None,\n        Item | Collector | list[Item | Collector] | None,\n        list[Item | Collector] | None,\n    ]:\n        result: Item | Collector | list[Item | Collector] | None = yield\n\n        if result is None:\n            return None\n\n        items: Iterable[Item | Collector] = (\n            result if isinstance(result, list) else (result,)\n        )\n\n        return list(self._collect(items))\n\n    @hookimpl(tryfirst=True)\n    def pytest_runtestloop(self, session: Session) -> bool:\n        if (\n            session.testsfailed\n            and not session.config.option.continue_on_collection_errors\n        ):\n            raise session.Interrupted(\n                f\"{session.testsfailed} error{'s' if session.testsfailed != 1 else ''} during collection\"\n            )\n\n        if not session.config.option.collectonly and session.items:\n            item, nextitem = self._get_item()\n            item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)\n        else:\n            self._finish()\n\n        return True\n\n    @hookimpl(tryfirst=True)\n    def pytest_runtest_protocol(self, item: Item, nextitem: Item | None) -> bool:\n        \"\"\"Perform the runtest protocol for a single test item.\n\n        Args:\n            item: Test item for which the runtest protocol is performed.\n            nextitem: The scheduled-to-be-next test item (or ``None`` if this is the end my friend).\n        \"\"\"\n        item.ihook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location)\n        self._setup(item=item, nextitem=nextitem)\n\n        return True\n\n    @property\n    def _item(self) -> Item:\n        \"\"\"Get current pytest item (test).\"\"\"\n        return self._session.items[self._index]\n\n    @property\n    def _nextitem(self) -> Item | None:\n        \"\"\"Get next pytest item (test) needed by test teardown phase.\"\"\"\n        index: int = self._index + 1\n\n        return self._session.items[index] if index < len(self._session.items) else None\n\n    def _collect(\n        self, items: Iterable[Item | Collector]\n    ) -> Generator[Item | Collector, None, None]:\n        for item in items:\n            if not isinstance(item, Function):\n                yield item\n\n            elif \"cocotb_test\" in item.keywords and inspect.iscoroutinefunction(\n                item.function\n            ):\n                item.extra_keyword_matches.update(self._keywords)\n\n                yield item\n\n    def _call_and_report(\n        self,\n        item: Item,\n        when: When,\n        func: Callable[..., None] | None = None,\n        **kwargs: object,\n    ) -> TestReport:\n        \"\"\"Invoke test setup, call, teardown and generate test report from it.\n\n        Args:\n            item: The pytest item.\n            when: Test setup, call or teardown.\n            func: Test function that will be called.\n            kwargs: Additional named arguments that will be passed to the test function.\n\n        Returns:\n            Test report.\n        \"\"\"\n        if not func:\n            self._logging_root_level = getLogger().level\n            func = getattr(item.ihook, f\"pytest_runtest_{when}\")\n            kwargs[\"item\"] = item\n            self._call_start = None\n\n        reraise: tuple[type[BaseException], ...] = (Exit,)\n\n        if not item.config.getoption(\"usepdb\", False):\n            reraise += (KeyboardInterrupt,)\n\n        call: CallInfo = CallInfo.from_call(\n            lambda: func(**kwargs),\n            when=when,\n            reraise=reraise,\n        )\n\n        if self._call_start is None:\n            self._call_start = call.start\n            self._sim_time_unit = self._session.config.option.cocotb_sim_time_unit\n            self._sim_time_start = get_sim_time(self._sim_time_unit)\n        else:\n            call.start = self._call_start\n            call.duration = call.stop - call.start\n\n        report: TestReport = item.ihook.pytest_runtest_makereport(item=item, call=call)\n\n        if _check_interactive_exception(call, report):\n            _interactive_exception(item, call, report)\n\n        return report\n\n    def _completed(self, item: Item, when: When) -> TestReport:\n        \"\"\"Part of test setup, call or teardown completed callback.\n\n        Args:\n            item: The pytest item.\n            when: Test \"setup\", \"call\" or \"teardown\".\n\n        Returns:\n            Test report.\n        \"\"\"\n        self._update_report_section(item=item, when=when)\n\n        return self._call_and_report(\n            item=item, when=when, func=self._running_test.result\n        )\n\n    @finish_on_exception\n    def _setup_completed(self) -> None:\n        \"\"\"Test setup completed callback.\"\"\"\n        item: Item = self._item\n        nextitem: Item | None = self._nextitem\n\n        report: TestReport = self._completed(item=item, when=\"setup\")\n        self._setup(item=item, nextitem=nextitem, report=report)\n\n    def _setup(\n        self, item: Item, nextitem: Item | None = None, report: TestReport | None = None\n    ) -> None:\n        \"\"\"Test setup.\n\n        Args:\n            item: The pytest item.\n            nextitem: The next pytest item. ``None`` if there are no more pytest items.\n            report: Test report.\n        \"\"\"\n        if not report:\n            self._setups.clear()\n            report = self._call_and_report(item=item, when=\"setup\")\n\n        if not report.passed:\n            item.ihook.pytest_runtest_logreport(report=report)\n            self._teardown(item=item, nextitem=nextitem)\n            return\n\n        if self._setups:\n            self._start(self._setups.popleft())\n            return\n\n        item.ihook.pytest_runtest_logreport(report=report)\n\n        self._call = None\n        report = self._call_and_report(item=item, when=\"call\")\n\n        if self._call:\n            self._start(self._call)\n        else:\n            item.ihook.pytest_runtest_logreport(report=report)\n            self._teardown(item=item, nextitem=nextitem)\n\n    @finish_on_exception\n    def _call_completed(self) -> None:\n        \"\"\"Test call completed callback.\"\"\"\n        item: Item = self._item\n        nextitem: Item | None = self._nextitem\n\n        report: TestReport = self._completed(item=item, when=\"call\")\n        item.ihook.pytest_runtest_logreport(report=report)\n        self._teardown(item=item, nextitem=nextitem)\n\n    @finish_on_exception\n    def _teardown_completed(self) -> None:\n        \"\"\"Test teardown completed callback.\"\"\"\n        item: Item = self._item\n        nextitem: Item | None = self._nextitem\n\n        report: TestReport = self._completed(item=item, when=\"teardown\")\n        self._teardown(item=item, nextitem=nextitem, report=report)\n\n    def _teardown(\n        self, item: Item, nextitem: Item | None = None, report: TestReport | None = None\n    ) -> None:\n        \"\"\"Test teardown.\n\n        Args:\n            item: The pytest item.\n            nextitem: The next pytest item. ``None`` if there are no more pytest items.\n            report: Test report.\n        \"\"\"\n        if not report:\n            self._teardowns.clear()\n            report = self._call_and_report(\n                item=item, when=\"teardown\", nextitem=nextitem\n            )\n\n        if self._teardowns:\n            self._start(self._teardowns.popleft())\n            return\n\n        item.ihook.pytest_runtest_logreport(report=report)\n        item.ihook.pytest_runtest_logfinish(nodeid=item.nodeid, location=item.location)\n\n        if nextitem:\n            item, nextitem = self._pop_item()\n            item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)\n        else:\n            self._finish()\n\n    def _get_item(self) -> tuple[Item, Item | None]:\n        return self._item, self._nextitem\n\n    def _pop_item(self) -> tuple[Item, Item | None]:\n        self._index += 1\n\n        return self._get_item()\n\n    def _notify_exception(self, excinfo: ExceptionInfo) -> None:\n        self._session.exitstatus = ExitCode.INTERNAL_ERROR\n        self._session.config.notify_exception(excinfo, self._session.config.option)\n\n    def _finish(self) -> None:\n        if self._finished:  # this method must be called once\n            return\n\n        self._finished = True\n\n        self._session.config.hook.pytest_sessionfinish(\n            session=self._session,\n            exitstatus=self._session.exitstatus,\n        )\n\n        self._session.config._ensure_unconfigure()\n        self._shutdown()\n\n    @hookimpl(tryfirst=True)\n    def pytest_runtest_setup(self, item: Item) -> None:\n        \"\"\"Called to perform the setup phase for a test item.\n\n        Args:\n            item: The pytest item (test function).\n        \"\"\"\n        self._save_logging_state()\n\n        # seed random number generator based on test module, name, and COCOTB_RANDOM_SEED\n        hasher = hashlib.sha1()\n        hasher.update(item.nodeid.encode())\n        seed: int = self._seed + int(hasher.hexdigest(), 16)\n\n        # seed random number generators with test seed\n        self._random_state = random.getstate()\n        random.seed(seed)\n        self._random_x_resolver_state = (\n            cocotb.types._resolve._randomResolveRng.getstate()\n        )\n        cocotb.types._resolve._randomResolveRng.seed(seed)\n        cocotb.RANDOM_SEED = seed\n\n    @hookimpl(tryfirst=True)\n    def pytest_runtest_call(self, item: Item) -> None:\n        \"\"\"Called to run the test for test item (the call phase).\n\n        Args:\n            item: The pytest item (test function).\n        \"\"\"\n        self._save_logging_state()\n\n    @hookimpl(tryfirst=True)\n    def pytest_runtest_teardown(self, item: Item, nextitem: Item | None = None) -> None:\n        \"\"\"Called to perform the teardown phase for a test item.\n\n        Args:\n            item: The pytest item (test function).\n            nextitem: The scheduled-to-be-next pytest item (next test function).\n        \"\"\"\n        self._save_logging_state()\n\n        # Restore random seed to original value\n        cocotb.RANDOM_SEED = self._seed\n        random.setstate(self._random_state)\n        cocotb.types._resolve._randomResolveRng.setstate(self._random_x_resolver_state)\n\n    @hookimpl(tryfirst=True)\n    def pytest_fixture_setup(\n        self,\n        fixturedef: FixtureDef[Any],\n        request: Any,  # NOTE: type not available in public pytest API\n    ) -> object | None:\n        \"\"\"Execution of fixture setup.\"\"\"\n        fixturefunc = fixturedef.func\n        is_coroutine: bool = inspect.iscoroutinefunction(fixturefunc)\n        is_async_generator: bool = inspect.isasyncgenfunction(fixturefunc)\n\n        if not is_coroutine and not is_async_generator:\n            return None\n\n        func: Callable[[], Any]\n        setup: TestManager\n\n        if is_async_generator:\n            # Test setup with teardown, re-assign added sub-tasks during setup to teardown\n            func = self._setup_async_generator(fixturedef, request)\n        else:\n            # Test setup-only without teardown\n            func = self._setup_async_function(fixturedef, request)\n\n        if is_async_generator:\n            # Test setup with teardown, added sub-tasks during setup will be cancelled by test teardown\n            setup = RunningTestSetup(\n                func(),\n                name=f\"Setup {request.fixturename}\",\n                test_complete_cb=self._setup_completed,\n            )\n        else:\n            # Test setup-only without teardown, run all tasks only during test setup\n            setup = TestManager(\n                func(),\n                name=f\"Setup {request.fixturename}\",\n                test_complete_cb=self._setup_completed,\n            )\n\n        cache_key = fixturedef.cache_key(request)\n        fixturedef.cached_result = AsyncFixtureCachedResult((setup, cache_key, None))  # type: ignore[assignment]\n\n        self._setups.append(setup)\n\n        return True\n\n    def _setup_async_generator(\n        self,\n        fixturedef: FixtureDef[Any],\n        request: Any,\n    ) -> Callable[[], Any]:\n        \"\"\"Test setup with teardown.\"\"\"\n\n        async def func() -> Any:\n            self._restore_logging_state()\n\n            kwargs: dict[str, Any] = {\n                argname: resolve_fixture_arg(request.getfixturevalue(argname))\n                for argname in fixturedef.argnames\n            }\n\n            iterator: AsyncGenerator[Any, None] = cast(\n                \"AsyncGenerator\", fixturedef.func(**kwargs)\n            )\n\n            result = await iterator.__anext__()\n            self._add_teardown(fixturedef, request, iterator)\n\n            return result\n\n        return func\n\n    def _setup_async_function(\n        self, fixturedef: FixtureDef[Any], request: Any\n    ) -> Callable[[], Any]:\n        \"\"\"Test setup-only without teardown.\"\"\"\n\n        async def func() -> Any:\n            self._restore_logging_state()\n\n            kwargs: dict[str, Any] = {\n                argname: resolve_fixture_arg(request.getfixturevalue(argname))\n                for argname in fixturedef.argnames\n            }\n\n            return await cast(\"AsyncFunction\", fixturedef.func)(**kwargs)\n\n        return func\n\n    @hookimpl(tryfirst=True)\n    def pytest_pyfunc_call(self, pyfuncitem: Function) -> object | None:\n        testfunction = pyfuncitem.obj\n\n        if not inspect.iscoroutinefunction(testfunction):\n            return None\n\n        timeout: tuple[float, TimeUnit] | None = _get_timeout(pyfuncitem)\n\n        if timeout:\n            testfunction = _wrap_with_timeout(testfunction, timeout)\n\n        async def func() -> None:\n            self._restore_logging_state()\n            funcargs = pyfuncitem.funcargs\n\n            kwargs: dict[str, Any] = {\n                argname: resolve_fixture_arg(funcargs[argname])\n                for argname in pyfuncitem._fixtureinfo.argnames\n            }\n\n            await testfunction(**kwargs)\n\n        self._call = TestManager(\n            func(),\n            name=f\"Test {pyfuncitem.name}\",\n            test_complete_cb=self._call_completed,\n        )\n\n        return True\n\n    @hookimpl(trylast=True, wrapper=True)\n    def pytest_runtest_makereport(\n        self, item: Item, call: CallInfo[None]\n    ) -> Generator[None, TestReport, TestReport]:\n        \"\"\"Called to create a :class:`~pytest.TestReport` for each of\n        the setup, call and teardown runtest phases of a test item.\n\n        Created test report will contain additional properties about simulation and cocotb:\n\n        * `cocotb`: Mark test report as cocotb test report. Always set to True.\n        * `sim_time_start`: Simulation time when specific test phase started.\n        * `sim_time_stop`: Simulation time when specific test phase ended.\n        * `sim_time_duration`: Simulation duration (stop - start) for specific test phase.\n        * `sim_time_unit`: Time unit for simulation time. Possible values: `step`, `fs`, `ps`,\n          `ns`, `us`, `ms` or `sec` (seconds).\n        * `runner_nodeid`: Node identifier of cocotb runner (test to run simulator by pytest parent process).\n        * `random_seed`: Value of seed used for randomization.\n\n        Above properties are accessible from generated test report and they will be available from\n        various generated test report outputs like JUnit XML report.\n\n        Args:\n            item: The item (test).\n            call: The :class:`~pytest.CallInfo` for the test phase (setup, call, teardown).\n\n        Returns:\n            New object of test report with additional properties about simulation and cocotb.\n        \"\"\"\n        report: TestReport = yield  # get generated test report from other plugins\n\n        sim_time_stop: float = get_sim_time(self._sim_time_unit)\n\n        # Additional properties that will be included with generated test report\n        properties: dict[str, Any] = {\n            \"cocotb\": True,\n            \"sim_time_start\": self._sim_time_start,\n            \"sim_time_stop\": sim_time_stop,\n            \"sim_time_duration\": sim_time_stop - self._sim_time_start,\n            \"sim_time_unit\": self._sim_time_unit,\n            \"runner_nodeid\": self._nodeid,  # identify cocotb runner\n            \"random_seed\": self._seed,\n        }\n\n        # Make properties available for other plugins. The `extra` argument from pytest.TestReport\n        # __init__(self, ..., **extra) constructor is doing the same\n        report.__dict__.update(properties)\n\n        # Make properties available in generated test reports like JUnit XML report\n        report.user_properties.extend(properties.items())\n\n        return report\n\n    @hookimpl(tryfirst=True)\n    def pytest_runtest_logreport(self, report: TestReport) -> None:\n        if self._reporter_address:\n            config: Config = self._session.config\n\n            data: dict[str, Any] = config.hook.pytest_report_to_serializable(\n                config=config, report=report\n            )\n\n            for retry in range(RETRIES, -1, -1):\n                try:\n                    with Client(self._reporter_address) as client:\n                        client.send(data)\n                    return\n                except Exception:\n                    if retry:\n                        sleep(INTERVAL)\n                    else:\n                        self._notify_exception(ExceptionInfo.from_current())\n\n    def _add_teardown(\n        self,\n        fixturedef: FixtureDef[Any],\n        request: Any,\n        iterator: AsyncGenerator[Any, None],\n    ) -> None:\n        \"\"\"Add asynchronous test teardown.\n\n        Args:\n            fixturedef: Definition of fixture.\n            request: Fixture request.\n            iterator: Asynchronous generator from invoked yield statement.\n        \"\"\"\n\n        async def func() -> None:\n            self._restore_logging_state()\n\n            try:\n                await iterator.__anext__()\n            except StopAsyncIteration:\n                pass\n\n        setup: TestManager = self._running_test\n        teardown: TestManager = TestManager(\n            func(),\n            name=f\"Teardown {request.fixturename}\",\n            test_complete_cb=self._teardown_completed,\n        )\n\n        def finalizer() -> None:\n            # Assign setup tasks (without the main task) to test teardown\n            if isinstance(setup, RunningTestSetup):\n                for task in setup.subtasks:\n                    if not task.cancelled():\n                        teardown.add_task(task)\n\n            self._teardowns.append(teardown)\n\n        fixturedef.addfinalizer(finalizer)\n\n    def _save_logging_state(self) -> None:\n        \"\"\"Save state of logging including log handlers and current log level.\"\"\"\n        self._logging_level = getLogger().level\n        self._logging_restored = False\n\n    def _restore_logging_state(self) -> None:\n        \"\"\"Restore log handlers needed by pytest capture mechanism.\n\n        These log handlers were unnecessary removed by using context manager in pytest logging plugin.\n        Because how everything is working when using async functions, context manager exists immediately\n        after scheduling async function to cocotb scheduler.\n        \"\"\"\n        if not self._logging_restored and self._logging_plugin:\n            root_logger: Logger = getLogger()\n            root_logger.setLevel(self._logging_level)\n            root_logger.addHandler(self._logging_plugin.log_file_handler)\n            root_logger.addHandler(self._logging_plugin.log_cli_handler)\n            root_logger.addHandler(self._logging_plugin.caplog_handler)\n            root_logger.addHandler(self._logging_plugin.report_handler)\n            self._logging_restored = True\n\n    def _update_report_section(\n        self, item: Item, when: Literal[\"setup\", \"call\", \"teardown\"]\n    ) -> None:\n        \"\"\"Update report section in item.\n\n        Args:\n            item: Test function.\n            when: Test phase.\n        \"\"\"\n        if self._logging_plugin:\n            log: str = self._logging_plugin.report_handler.stream.getvalue().strip()\n\n            # Update the latest log section\n            for index, section in reversed(list(enumerate(item._report_sections))):\n                if section[0] == when and section[1] == \"log\":\n                    item._report_sections[index] = (when, \"log\", log)\n                    break\n\n            # These log handlers are per test function phase, no needed anymore\n            root_logger: Logger = getLogger()\n            root_logger.setLevel(self._logging_root_level)\n            root_logger.removeHandler(self._logging_plugin.caplog_handler)\n            root_logger.removeHandler(self._logging_plugin.report_handler)\n\n    def _on_sim_end(self) -> None:\n        try:\n            raise SimFailure(\n                \"cocotb expected it would shut down the simulation, but the simulation ended prematurely. \"\n                \"This could be due to an assertion failure or a call to an exit routine in the HDL, \"\n                \"or due to the simulator running out of events to process (is your clock running?).\"\n            )\n        except BaseException:\n            self._notify_exception(ExceptionInfo.from_current())\n        finally:\n            self._finish()\n\n    def _start(self, running_test: TestManager) -> None:\n        \"\"\"Start test setup, call or teardown.\n\n        Args:\n            running_test: Test to run.\n        \"\"\"\n        self._running_test = running_test\n\n        if self._scheduled:\n            self._timer1._register(self._running_test.start)\n        else:\n            self._scheduled = True\n            self._running_test.start()\n\n    def _shutdown(self) -> None:\n        cocotb._shutdown._shutdown()\n\n        # Setup simulator finalization\n        cocotb.simulator.stop_simulator()\n\n\ndef _check_interactive_exception(call: CallInfo, report: TestReport) -> bool:\n    \"\"\"Check whether the call raised an exception that should be reported as interactive.\"\"\"\n    if call.excinfo is None:\n        return False  # Didn't raise.\n\n    if hasattr(report, \"wasxfail\"):\n        return False  # Exception was expected.\n\n    # Special control flow exception.\n    return not isinstance(call.excinfo.value, (Skipped, bdb.BdbQuit))\n\n\ndef _interactive_exception(item: Item, call: CallInfo, report: TestReport) -> None:\n    \"\"\"Interactive exception using Python Debugger (pdb).\"\"\"\n    try:\n        item.ihook.pytest_exception_interact(node=item, call=call, report=report)\n    except Exit:\n        pass\n\n\ndef _to_timeout(duration: float, unit: TimeUnit) -> tuple[float, TimeUnit]:\n    \"\"\"Helper function to extract ``*marker.args`` and ``**marker.kwargs`` to tuple.\"\"\"\n    return duration, unit\n\n\ndef _get_timeout(function: Function) -> tuple[float, TimeUnit] | None:\n    \"\"\"Get timeout from test function.\"\"\"\n    marker: Mark | None = function.get_closest_marker(\"cocotb_timeout\")\n\n    return _to_timeout(*marker.args, **marker.kwargs) if marker else None\n\n\ndef _wrap_with_timeout(\n    func: Callable[..., Awaitable],\n    timeout: tuple[float, TimeUnit],\n) -> Callable[..., Awaitable]:\n    \"\"\"Wrap async test function (setup, call, teardown) with timeout.\"\"\"\n\n    @wraps(func)\n    async def wrapped(*args: object, **kwargs: object) -> Any:\n        return await with_timeout(func(*args, **kwargs), timeout[0], timeout[1])\n\n    return wrapped\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_runner.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Module related with handling cocotb runners and collecting cocotb tests from these runners.\"\"\"\n\nfrom __future__ import annotations\n\nimport os\nfrom collections.abc import Iterable\nfrom importlib import import_module\nfrom pathlib import Path\nfrom typing import Any\n\nfrom pytest import Collector, Item\n\nfrom cocotb_tools.pytest._testbench import Testbench\n\n\nclass Runner(Collector):\n    \"\"\"Collector that will collect cocotb tests from cocotb runner.\"\"\"\n\n    def __init__(\n        self,\n        item: Item,\n        *args: Any,\n        **kwargs: Any,\n    ) -> None:\n        \"\"\"Create new instance of collector to collect cocotb tests\n        from Python module(s) that will be run by cocotb runner.\n\n        Args:\n            item:   Cocotb runner test function.\n            args:   Additional positional arguments for pytest collector.\n            kwargs: Additional named arguments for pytest collector.\n        \"\"\"\n        super().__init__(*args, **kwargs)\n\n        self.item: Item = item\n\n    def collect(self) -> Iterable[Item | Collector]:\n        \"\"\"Collect cocotb tests from Python module(s) that will be run by cocotb runner.\n\n        Yields:\n            Collected item or collector.\n        \"\"\"\n        test_modules: Iterable[str] | None = None\n\n        for marker in self.item.iter_markers(\"cocotb_runner\"):\n            if marker.args:\n                test_modules = marker.args\n                break\n\n        for test_module in test_modules or (self.path.stem,):\n            # Check if test_module exists as Python file\n            path: Path = self.path.parent / Path(\n                test_module.replace(\".\", os.path.pathsep) + \".py\"\n            )\n\n            if not path.exists():\n                # Try to get path to Python file by importing test_module as Python module\n                path = Path(str(import_module(test_module).__file__))\n\n            yield Testbench.from_parent(self, name=path.stem, path=path)\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_test.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Extend cocotb test module.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import Coroutine\nfrom typing import Any, Callable\n\nfrom cocotb._base_triggers import Trigger\nfrom cocotb._test_manager import TestManager\nfrom cocotb.task import Task\n\n\nclass RunningTestSetup(TestManager):\n    \"\"\"Running test setup without cancelling added sub-tasks.\"\"\"\n\n    def __init__(\n        self,\n        coro: Coroutine[Trigger, None, None],\n        *,\n        name: str,\n        test_complete_cb: Callable[[], None],\n    ) -> None:\n        \"\"\"Create new instance of running test setup.\"\"\"\n        super().__init__(coro, name=name, test_complete_cb=test_complete_cb)\n\n        self.subtasks: list[Task[Any]] = []\n        \"\"\"Sub-tasks that must be keep alive during test setup, call and teardown.\"\"\"\n\n    def add_task(self, task: Task[Any]) -> None:\n        \"\"\"Add task to test setup.\"\"\"\n        self.subtasks.append(task)\n"
  },
  {
    "path": "src/cocotb_tools/pytest/_testbench.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Module representing collection of cocotb tests.\"\"\"\n\nfrom __future__ import annotations\n\nfrom pytest import Module\n\n\nclass Testbench(Module):\n    \"\"\"Collector that will collect cocotb tests from test modules.\"\"\"\n"
  },
  {
    "path": "src/cocotb_tools/pytest/hdl.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Build and test HDL designs.\"\"\"\n\nfrom __future__ import annotations\n\nimport os\nimport re\nfrom collections.abc import Mapping, MutableMapping, MutableSequence, Sequence\nfrom pathlib import Path\nfrom shutil import which\nfrom typing import Any, Callable\n\nfrom pytest import Config, FixtureRequest\n\nfrom cocotb_tools.runner import (\n    VHDL,\n    PathLike,\n    Runner,\n    VerilatorControlFile,\n    Verilog,\n)\n\n_POSIX_PATH: re.Pattern = re.compile(r\"[^A-Za-z0-9/._-]\")\n\n# Name of HDL simulator per executable\n# TODO: Move to cocotb_tools.runner?\n_SIMULATORS: dict[str, str] = {\n    # open-source simulators first\n    \"verilator\": \"verilator\",\n    \"nvc\": \"nvc\",\n    \"ghdl\": \"ghdl\",\n    \"iverilog\": \"icarus\",\n    # proprietary simulators\n    \"xrun\": \"xcelium\",\n    \"vcs\": \"vcs\",\n    \"vsim\": \"questa\",\n    \"vsimsa\": \"riviera\",\n}\n\n\ndef _get_simulator(config: Config) -> str:\n    \"\"\"Get name of HDL simulator.\n\n    Args:\n        config: Pytest configuration object.\n\n    Returns:\n        Name of HDL simulator.\n    \"\"\"\n    simulator: str = config.option.cocotb_simulator\n\n    if not simulator or simulator == \"auto\":\n        for command, name in _SIMULATORS.items():\n            if which(command):\n                return name\n\n    return simulator\n\n\nclass HDL:\n    \"\"\"Build HDL design and run test against specific HDL top level.\"\"\"\n\n    def __init__(self, request: FixtureRequest) -> None:\n        \"\"\"Create new instance of HDL design.\n\n        Args:\n            request: The pytest fixture request.\n        \"\"\"\n        config: Config = request.config\n        option = config.option\n        hook = config.hook\n        nodeid: str = request.node.nodeid\n\n        # We need information if .build()/.test() is running during session stage and by xdist worker\n        # This is needed to protect build/test directory\n        self._is_session_scoped: bool = request.scope == \"session\"\n        self._is_xdist_worker: bool = (\n            getattr(request.config, \"workerinput\", None) is not None\n        )\n\n        # Use only allowed characters by POSIX standard\n        # Pytest is always using \"/\" as path separator regardless of current OS environment\n        nodeid = _POSIX_PATH.sub(\"_\", nodeid.replace(\".py::\", \"/\").replace(\"::\", \"/\"))\n\n        if os.path.sep != \"/\":\n            nodeid = nodeid.replace(\"/\", os.path.sep)\n\n        self.test_dir: PathLike = Path(option.cocotb_build_dir).resolve() / nodeid\n        \"\"\"Directory to run the tests in.\"\"\"\n\n        self.runner: Runner = hook.pytest_cocotb_make_runner(\n            simulator_name=_get_simulator(request.config)\n        )\n        \"\"\"Instance that allows to build HDL and run cocotb tests.\"\"\"\n\n        # Build options\n        self.library: str = option.cocotb_library\n        \"\"\"The library name to compile into.\"\"\"\n\n        self.sources: MutableSequence[\n            PathLike | VHDL | Verilog | VerilatorControlFile\n        ] = []\n        \"\"\"Language-agnostic list of source files to build.\"\"\"\n\n        self.includes: MutableSequence[PathLike] = []\n        \"\"\"Verilog include directories.\"\"\"\n\n        self.defines: MutableMapping[str, object] = {}\n        \"\"\"Defines to set.\"\"\"\n\n        self.parameters: MutableMapping[str, object] = {}\n        \"\"\"Verilog parameters or VHDL generics.\"\"\"\n\n        self.build_args: MutableSequence[str | VHDL | Verilog] = []\n        \"\"\"Extra build arguments for the simulator.\"\"\"\n\n        self.toplevel: str | None = None\n        \"\"\"Name of the HDL toplevel module.\"\"\"\n\n        self.always: bool = option.cocotb_always\n        \"\"\"Always run the build step.\"\"\"\n\n        self.clean: bool = option.cocotb_clean\n        \"\"\"Delete *build_dir* before building.\"\"\"\n\n        self.verbose: bool = option.cocotb_verbose\n        \"\"\"Enable verbose messages.\"\"\"\n\n        self.timescale: tuple[str, str] | None = option.cocotb_timescale\n        \"\"\"Tuple containing time unit and time precision for simulation.\"\"\"\n\n        self.waves: bool = option.cocotb_waves\n        \"\"\"Record signal traces.\"\"\"\n\n        self.build_dir: PathLike = self.test_dir\n        \"\"\"Directory to run the build step in.\"\"\"\n\n        self.cwd: PathLike = self.build_dir\n        \"\"\"Directory to execute the build command(s) in.\"\"\"\n\n        # Test options\n        self.test_module: str | Sequence[str] = \"\"\n        \"\"\"Name(s) of the Python module(s) containing the tests to run.\"\"\"\n\n        self.toplevel_library: str = option.cocotb_toplevel_library\n        \"\"\"The library name for HDL toplevel module.\"\"\"\n\n        self.toplevel_lang: str | None = option.cocotb_toplevel_lang\n        \"\"\"Language of the HDL toplevel module.\"\"\"\n\n        self.gpi_interfaces: list[str] = option.cocotb_gpi_interfaces\n        \"\"\"List of GPI interfaces to use, with the first one being the entry point.\"\"\"\n\n        self.seed: str | int | None = option.cocotb_seed\n        \"\"\"A specific random seed to use.\"\"\"\n\n        self.elab_args: MutableSequence[str] = []\n        \"\"\"A list of elaboration arguments for the simulator.\"\"\"\n\n        self.test_args: MutableSequence[str] = []\n        \"\"\"A list of extra arguments for the simulator.\"\"\"\n\n        self.plusargs: MutableSequence[str] = []\n        \"\"\"'plusargs' to set for the simulator.\"\"\"\n\n        self.env: MutableMapping[str, str] = {}\n        \"\"\"Extra environment variables to set.\"\"\"\n\n        self.gui: bool = option.cocotb_gui\n        \"\"\"Run with simulator GUI.\"\"\"\n\n        self.pre_cmd: list[str] = []\n        \"\"\"Commands to run before simulation begins. Typically Tcl commands for simulators that support them.\"\"\"\n\n        self._apply_markers(request.node)\n\n        # Store reference to command line options\n        self._option = option\n\n        if not self.toplevel_lang or self.toplevel_lang == \"auto\":\n            if len(self.runner.supported_gpi_interfaces) == 1:\n                self.toplevel_lang = list(self.runner.supported_gpi_interfaces)[0]\n            else:\n                # HDL simulator supports multiple languages\n                self.toplevel_lang = None\n\n        if not self.test_module and not self._is_session_scoped:\n            self.test_module = request.path.name.partition(\".\")[0]\n\n        if not self.toplevel and self.test_module:\n            if isinstance(self.test_module, str):\n                self.toplevel = self.test_module\n            elif isinstance(self.test_module, Sequence):\n                self.toplevel = self.test_module[0]\n\n            if self.toplevel.startswith(\"test_\"):\n                self.toplevel = self.toplevel.removeprefix(\"test_\")\n\n            elif self.toplevel.endswith(\"_test\"):\n                self.toplevel = self.toplevel.removesuffix(\"_test\")\n\n    @property\n    def simulator(self) -> str:\n        \"\"\"Name of HDL simulator.\"\"\"\n        return str(self.runner.__class__.__name__).lower()\n\n    def __setitem__(self, key: str, value: object) -> None:\n        \"\"\"Set HDL parameter/generic in HDL design.\"\"\"\n        self.parameters[key] = value\n\n    def __getitem__(self, key: str) -> object:\n        \"\"\"Get HDL parameter/generic.\"\"\"\n        return self.parameters[key]\n\n    def build(\n        self,\n        library: str | None = None,\n        sources: Sequence[PathLike | VHDL | Verilog | VerilatorControlFile]\n        | None = None,\n        includes: Sequence[PathLike] | None = None,\n        defines: Mapping[str, object] | None = None,\n        parameters: Mapping[str, object] | None = None,\n        build_args: Sequence[str | VHDL | Verilog] | None = None,\n        toplevel: str | None = None,\n        always: bool = False,\n        clean: bool = False,\n        verbose: bool = False,\n        timescale: tuple[str, str] | None = None,\n        waves: bool = False,\n        build_dir: PathLike | None = None,\n        cwd: PathLike | None = None,\n    ) -> None:\n        \"\"\"Build HDL design.\n\n        Args:\n            library:\n                The library name to compile into.\n\n            sources:\n                Language-agnostic list of source files to build.\n\n            includes:\n                Verilog include directories.\n\n            defines:\n                Defines to set.\n\n            parameters:\n                Verilog parameters or VHDL generics.\n\n            build_args:\n                Extra build arguments for the simulator.\n\n            toplevel:\n                Name of the HDL toplevel module.\n\n            always:\n                Always run the build step.\n\n            clean:\n                Delete *build_dir* before building.\n\n            verbose:\n                Enable verbose messages.\n\n            timescale:\n                Tuple containing time unit and time precision for simulation.\n\n            waves:\n                Record signal traces.\n\n            build_dir:\n                Directory to run the build step in.\n\n            cwd:\n                Directory to execute the build command(s) in.\n        \"\"\"\n        # Run build only once when executing this method during session stage\n        # https://github.com/pytest-dev/pytest-xdist/issues/271#issuecomment-826396320\n        if self._is_session_scoped and self._is_xdist_worker:\n            return\n\n        option = self._option\n\n        build_dir = build_dir or self.build_dir\n        Path(build_dir).mkdir(0o755, parents=True, exist_ok=True)\n\n        # Allow to extend build, elab, test and + arguments from cli and configs\n        build_args = (build_args or self.build_args) + option.cocotb_build_args\n        includes = (includes or self.includes) + option.cocotb_includes\n\n        # Allow to override HDL parameters/generics, environment variables and defines from cli and configs\n        parameters = (parameters or self.parameters) | option.cocotb_parameters\n        defines = (defines or self.defines) | option.cocotb_defines\n\n        self.runner.build(\n            hdl_library=library or self.library,\n            sources=sources or self.sources,\n            includes=includes,\n            defines=defines,\n            parameters=parameters,\n            build_args=build_args,\n            hdl_toplevel=toplevel or self.toplevel or None,\n            always=always or self.always,\n            build_dir=build_dir,\n            cwd=cwd or build_dir,\n            clean=clean or self.clean,\n            verbose=verbose or self.verbose,\n            timescale=timescale or self.timescale,\n            waves=waves or self.waves,\n        )\n\n    def test(\n        self,\n        test_module: str | Sequence[str] | None = None,\n        toplevel: str | None = None,\n        toplevel_library: str | None = None,\n        toplevel_lang: str | None = None,\n        gpi_interfaces: list[str] | None = None,\n        parameters: Mapping[str, object] | None = None,\n        seed: str | int | None = None,\n        elab_args: Sequence[str] | None = None,\n        test_args: Sequence[str] | None = None,\n        plusargs: Sequence[str] | None = None,\n        env: Mapping[str, str] | None = None,\n        gui: bool = False,\n        waves: bool = False,\n        verbose: bool = False,\n        pre_cmd: list[str] | None = None,\n        timescale: tuple[str, str] | None = None,\n        build_dir: PathLike | None = None,\n        test_dir: PathLike | None = None,\n    ) -> Path:\n        \"\"\"Test HDL design.\n\n        Args:\n            test_module:\n                Name(s) of the Python module(s) containing the tests to run.\n\n            toplevel:\n                Name of the HDL toplevel module.\n\n            toplevel_library:\n                The library name for HDL toplevel module.\n\n            toplevel_lang:\n                Language of the HDL toplevel module.\n\n            gpi_interfaces:\n                List of GPI interfaces to use, with the first one being the entry point.\n\n            parameters:\n                Verilog parameters or VHDL generics.\n\n            seed:\n                A specific random seed to use.\n\n            elab_args:\n                A list of elaboration arguments for the simulator.\n\n            test_args:\n                A list of extra arguments for the simulator.\n\n            plusargs:\n                'plusargs' to set for the simulator.\n\n            env:\n                Extra environment variables to set.\n\n            gui:\n                Run with simulator GUI.\n\n            waves:\n                Record signal traces.\n\n            verbose:\n                Enable verbose messages.\n\n            pre_cmd:\n                Commands to run before simulation begins. Typically Tcl commands for simulators that support them.\n\n            timescale:\n                Tuple containing time unit and time precision for simulation.\n\n            build_dir:\n                Directory to run the build step in.\n\n            test_dir:\n                Directory to run the tests in.\n\n        Returns:\n            Path to created results file with cocotb tests in JUnit XML format.\n        \"\"\"\n        option = self._option\n\n        build_dir = build_dir or self.build_dir\n        Path(build_dir).mkdir(0o755, parents=True, exist_ok=True)\n\n        test_dir = test_dir or self.test_dir\n        Path(test_dir).mkdir(0o755, parents=True, exist_ok=True)\n\n        # Allow to extend build, elab, test and + arguments from cli and configs\n        elab_args = (elab_args or self.elab_args) + option.cocotb_elab_args\n        test_args = (test_args or self.test_args) + option.cocotb_test_args\n        plusargs = (plusargs or self.plusargs) + option.cocotb_plusargs\n        pre_cmd = (pre_cmd or self.pre_cmd) + option.cocotb_pre_cmd\n        timescale = timescale or self.timescale\n\n        # Allow to override HDL parameters/generics, environment variables and defines from cli and configs\n        parameters = (parameters or self.parameters) | option.cocotb_parameters\n        env = (env or self.env) | option.cocotb_env\n\n        return self.runner.test(\n            test_module=test_module or self.test_module,\n            hdl_toplevel=toplevel or self.toplevel or \"\",\n            hdl_toplevel_lang=toplevel_lang or self.toplevel_lang,\n            hdl_toplevel_library=toplevel_library or self.toplevel_library,\n            gpi_interfaces=gpi_interfaces or self.gpi_interfaces or None,\n            seed=seed or self.seed,\n            elab_args=elab_args,\n            test_args=test_args,\n            plusargs=plusargs,\n            extra_env=env,\n            waves=waves or self.waves,\n            gui=gui or self.gui,\n            parameters=parameters or None,\n            build_dir=build_dir,\n            test_dir=test_dir,\n            results_xml=str(Path(test_dir) / \"results.xml\"),\n            pre_cmd=pre_cmd or None,\n            verbose=verbose or self.verbose,\n            timescale=None if self.simulator in (\"xcelium\",) else timescale,\n        )\n\n    def _apply_markers(self, node: Any) -> None:\n        \"\"\"Apply all cocotb markers starting from the root (session) to the leaf (test function).\n\n        * Markers with positional arguments are extending targeted attribute.\n        * Markers with named arguments are updating targeted attribute.\n\n        Args:\n            node: The pytest node (session, package, module, class, function, ...).\n        \"\"\"\n        for parent in reversed(list(node.iter_parents())):\n            for marker in parent.own_markers:\n                name: str = marker.name\n\n                if name.startswith(\"cocotb_\"):\n                    apply: Callable[..., None] | None = getattr(\n                        self, f\"_mark_{name}\", None\n                    )\n\n                    if apply:\n                        apply(*marker.args, **marker.kwargs)\n\n    def _mark_cocotb_runner(self, test_module: str = \"\", *args: str) -> None:\n        self.test_module = [test_module, *args] if test_module else list(args)\n\n    def _mark_cocotb_sources(\n        self, *args: PathLike | Verilog | VHDL | VerilatorControlFile\n    ) -> None:\n        self.sources.extend(args)\n\n    def _mark_cocotb_defines(self, **kwargs: object) -> None:\n        self.defines.update(kwargs)\n\n    def _mark_cocotb_parameters(self, **kwargs: object) -> None:\n        self.parameters.update(kwargs)\n\n    def _mark_cocotb_env(self, **kwargs: str) -> None:\n        self.env.update(kwargs)\n\n    def _mark_cocotb_includes(self, *args: PathLike) -> None:\n        self.includes.extend(args)\n\n    def _mark_cocotb_plusargs(self, *args: str) -> None:\n        self.plusargs.extend(args)\n\n    def _mark_cocotb_timescale(self, unit: str, precision: str | None = None) -> None:\n        self.timescale = (unit, precision if precision else unit)\n\n    def _mark_cocotb_seed(self, value: str | int) -> None:\n        self.seed = value\n\n    def _mark_cocotb_build_args(self, *args: str | VHDL | Verilog) -> None:\n        self.build_args.extend(args)\n\n    def _mark_cocotb_elab_args(self, *args: str) -> None:\n        self.elab_args.extend(args)\n\n    def _mark_cocotb_test_args(self, *args: str) -> None:\n        self.test_args.extend(args)\n\n    def _mark_cocotb_pre_cmd(self, *args: str) -> None:\n        self.pre_cmd.extend(args)\n\n    def _mark_cocotb_library(self, name: str) -> None:\n        self.library = name\n\n    def _mark_cocotb_waves(self, condition: bool = True) -> None:\n        self.waves = condition\n\n    def _mark_cocotb_verbose(self, condition: bool = True) -> None:\n        self.verbose = condition\n\n    def _mark_cocotb_always(self, condition: bool = True) -> None:\n        self.always = condition\n\n    def _mark_cocotb_clean(self, condition: bool = True) -> None:\n        self.clean = condition\n"
  },
  {
    "path": "src/cocotb_tools/pytest/hookspecs.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Specification of cocotb hook functions.\"\"\"\n\nfrom __future__ import annotations\n\nfrom pytest import FixtureRequest, hookspec\n\nfrom cocotb_tools.pytest.hdl import HDL\nfrom cocotb_tools.runner import Runner\n\n\n@hookspec(firstresult=True)\ndef pytest_cocotb_make_hdl(request: FixtureRequest) -> HDL | None:\n    \"\"\"Create new instance of :py:class:`cocotb_tools.pytest.hdl.HDL`.\n\n    .. note::\n\n        Any conftest file can implement this hook. Stops at first non-None result.\n\n    Args:\n        request: The pytest fixture request object.\n\n    Returns:\n        New instance of HDL.\n    \"\"\"\n\n\n@hookspec(firstresult=True)\ndef pytest_cocotb_make_runner(simulator_name: str) -> Runner | None:\n    \"\"\"Create new instance of :py:class:`cocotb_tools.runner.Runner`.\n\n    .. note::\n\n        Any conftest file can implement this hook. Stops at first non-None result.\n\n    Args:\n        simulator_name: Name of HDL simulator.\n\n    Returns:\n        New instance of runner.\n    \"\"\"\n"
  },
  {
    "path": "src/cocotb_tools/pytest/mark.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Plugin markers.\"\"\"\n\nfrom __future__ import annotations\n\nfrom inspect import Parameter, signature\nfrom typing import Callable\n\nfrom pytest import Config, MarkDecorator, mark\n\nfrom cocotb.simtime import TimeUnit\nfrom cocotb_tools.runner import (\n    VHDL,\n    PathLike,\n    VerilatorControlFile,\n    Verilog,\n)\n\n\ndef cocotb_runner(test_module: str = \"\", *extra_test_module: str) -> MarkDecorator:\n    \"\"\"Mark test function as cocotb runner.\n\n    Example usage:\n\n    .. code:: python\n\n        import pytest\n        from cocotb_tools.pytest.hdl import HDL\n\n        @pytest.fixture(name=\"sample_module\")\n        def sample_module_fixture(hdl: HDL) -> HDL:\n            # Define HDL design and build it\n            hdl.toplevel = \"sample_module\"\n            hdl.sources = (DESIGNS / \"sample_module.sv\",)\n            hdl.build()\n\n            return hdl\n\n        @pytest.mark.cocotb_runner\n        def test_dut(sample_module: HDL) -> None:\n            # Run HDL simulator with cocotb tests\n            sample_module.test()\n\n    Args:\n        test_module:\n            Name of Python module with cocotb tests to be loaded by cocotb :py:attr:`~cocotb_tools.pytest.hdl.HDL.runner`.\n\n    Returns:\n        Decorated test function as cocotb runner.\n    \"\"\"\n    return mark.cocotb_runner(test_module=test_module, *extra_test_module)\n\n\ndef cocotb_test() -> MarkDecorator:\n    \"\"\"Mark coroutine function as cocotb test.\n\n    Example usage:\n\n    .. code:: python\n\n        # NOTE: decorator is not needed if coroutine function starts with the test_ prefix and it uses dut fixture\n        async def test_dut_feature(dut) -> None:\n            # Test DUT feature\n            ...\n\n        @pytest.mark.cocotb_test\n        async def non_canonical_test_name(dut) -> None:\n            # Test DUT feature but from a test function that doesn't follow with the pytest naming convention\n            ...\n\n    Returns:\n        Decorated coroutine function as cocotb test.\n    \"\"\"\n    return mark.cocotb_test()\n\n\ndef cocotb_timeout(duration: float, unit: TimeUnit) -> MarkDecorator:\n    \"\"\"Mark coroutine function with simulation time duration before the test is forced to fail.\n\n    Example usage:\n\n    .. code:: python\n\n        @pytest.mark.cocotb_timeout(duration=200, unit=\"ns\")\n        async def test_dut_feature_with_timeout(dut) -> None:\n            # Test DUT feature with timeout configured from cocotb marker\n            ...\n\n    Args:\n        duration: Simulation time duration before the test is forced to fail.\n        unit: Simulation time unit that accepts any unit that :class:`~cocotb.triggers.Timer` does.\n\n    Raises:\n        :exc:`~cocotb.triggers.SimTimeoutError`: Test function timeouted.\n\n    Returns:\n        Decorated coroutine function with simulation time duration before the test is forced to fail.\n    \"\"\"\n    return mark.cocotb_timeout(duration=duration, unit=unit)\n\n\ndef cocotb_sources(\n    *source: PathLike | Verilog | VHDL | VerilatorControlFile,\n) -> MarkDecorator:\n    \"\"\"Add language-agnostic list of source files to build.\"\"\"\n    return mark.cocotb_sources(*source)\n\n\ndef cocotb_defines(**define: object) -> MarkDecorator:\n    \"\"\"Set defines.\"\"\"\n    return mark.cocotb_defines(**define)\n\n\ndef cocotb_parameters(**parameter: object) -> MarkDecorator:\n    \"\"\"Set Verilog/SystemVerilog parameters and VHDL generics.\"\"\"\n    return mark.cocotb_parameters(**parameter)\n\n\ndef cocotb_env(**env: str) -> MarkDecorator:\n    \"\"\"Set environment variables.\"\"\"\n    return mark.cocotb_env(**env)\n\n\ndef cocotb_includes(*include: PathLike) -> MarkDecorator:\n    \"\"\"Add Verilog includes.\"\"\"\n    return mark.cocotb_includes(*include)\n\n\ndef cocotb_plusargs(*plusarg: str) -> MarkDecorator:\n    \"\"\"Add plus arguments for the simulator.\"\"\"\n    return mark.cocotb_plusargs(*plusarg)\n\n\ndef cocotb_timescale(unit: str, precision: str | None = None) -> MarkDecorator:\n    \"\"\"Set time unit and time precision for simulation.\"\"\"\n    return mark.cocotb_timescale(unit=unit, precision=precision)\n\n\ndef cocotb_seed(value: str | int) -> MarkDecorator:\n    \"\"\"A specific random seed to use.\"\"\"\n    return mark.cocotb_seed(value=value)\n\n\ndef cocotb_build_args(*arg: str | VHDL | Verilog) -> MarkDecorator:\n    \"\"\"Add extra build arguments for the simulator.\"\"\"\n    return mark.cocotb_build_args(*arg)\n\n\ndef cocotb_elab_args(*arg: str) -> MarkDecorator:\n    \"\"\"Add extra elaboration arguments to the simulator.\"\"\"\n    return mark.cocotb_elab_args(*arg)\n\n\ndef cocotb_test_args(*arg: str) -> MarkDecorator:\n    \"\"\"Add extra runtime arguments to the simulator.\"\"\"\n    return mark.cocotb_test_args(*arg)\n\n\ndef cocotb_pre_cmd(*arg: str) -> MarkDecorator:\n    \"\"\"Add extra commands to run before simulation begins. Typically Tcl commands for simulators that support them..\"\"\"\n    return mark.cocotb_pre_cmd(*arg)\n\n\ndef cocotb_library(name: str) -> MarkDecorator:\n    \"\"\"Set the library name to compile into.\"\"\"\n    return mark.cocotb_library(name=name)\n\n\ndef cocotb_waves(condition: bool = True) -> MarkDecorator:\n    \"\"\"Record signal traces.\"\"\"\n    return mark.cocotb_waves(condition=condition)\n\n\ndef cocotb_verbose(condition: bool = True) -> MarkDecorator:\n    \"\"\"Enable verbose messages.\"\"\"\n    return mark.cocotb_verbose(condition=condition)\n\n\ndef cocotb_always(condition: bool = True) -> MarkDecorator:\n    \"\"\"Always run the build step.\"\"\"\n    return mark.cocotb_always(condition=condition)\n\n\ndef cocotb_clean(condition: bool = True) -> MarkDecorator:\n    \"\"\"Delete *build_dir* before building.\"\"\"\n    return mark.cocotb_clean(condition=condition)\n\n\ndef _marker_description(marker: Callable[..., MarkDecorator]) -> str:\n    \"\"\"Get pretty formatted description of marker.\n\n    Args:\n        marker: Definition of marker for pytest.\n\n    Returns:\n        Pretty formatted description of provided marker.\n    \"\"\"\n    args: list[str] = []\n\n    for name, parameter in signature(marker).parameters.items():\n        arg: str = \"\"\n\n        if parameter.kind == Parameter.VAR_KEYWORD:\n            arg = f\"{name}=...\"\n\n        else:\n            arg = name\n\n        if parameter.default != Parameter.empty:\n            arg += f\"={parameter.default}\"\n\n        if parameter.kind == Parameter.KEYWORD_ONLY and \"*\" not in args:\n            args.append(\"*\")\n\n        args.append(arg)\n\n        if parameter.kind == Parameter.VAR_POSITIONAL:\n            args.append(\"...\")\n\n    description: str = str(marker.__doc__).lstrip().splitlines()[0]\n\n    return f\"{marker.__name__}({', '.join(args)}): {description}\".rstrip()\n\n\ndef _register_markers(config: Config) -> None:\n    \"\"\"Register plugin markers.\n\n    Args:\n        config: Pytest configuration object.\n    \"\"\"\n    for marker in (\n        cocotb_runner,\n        cocotb_test,\n        cocotb_timeout,\n        cocotb_library,\n        cocotb_sources,\n        cocotb_defines,\n        cocotb_includes,\n        cocotb_parameters,\n        cocotb_plusargs,\n        cocotb_env,\n        cocotb_seed,\n        cocotb_timescale,\n        cocotb_always,\n        cocotb_clean,\n        cocotb_waves,\n        cocotb_build_args,\n        cocotb_elab_args,\n        cocotb_test_args,\n        cocotb_pre_cmd,\n    ):\n        config.addinivalue_line(\"markers\", _marker_description(marker))\n"
  },
  {
    "path": "src/cocotb_tools/pytest/plugin.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Pytest plugin to integrate pytest with cocotb.\"\"\"\n\nfrom __future__ import annotations\n\nimport inspect\nimport shlex\nimport textwrap\nfrom argparse import ArgumentParser\nfrom collections.abc import Generator, Iterable, Mapping\nfrom pathlib import Path\nfrom time import time\nfrom typing import TYPE_CHECKING, Any\n\nfrom pluggy import Result\nfrom pytest import (\n    Class,\n    Collector,\n    CollectReport,\n    Config,\n    ExitCode,\n    FixtureRequest,\n    Item,\n    Mark,\n    Module,\n    Parser,\n    PytestPluginManager,\n    TerminalReporter,\n    TestReport,\n    TestShortLogReport,\n    fixture,\n    hookimpl,\n    mark,\n)\n\nimport cocotb\nimport cocotb.handle\nfrom cocotb.handle import SimHandleBase\nfrom cocotb_tools.pytest import hookspecs\nfrom cocotb_tools.pytest._compat import (\n    cocotb_decorator_as_pytest_marks,\n    is_cocotb_decorator,\n)\nfrom cocotb_tools.pytest._controller import Controller\nfrom cocotb_tools.pytest._logging import Logging\nfrom cocotb_tools.pytest._option import (\n    Option,\n    add_options_to_parser,\n    populate_ini_to_options,\n)\nfrom cocotb_tools.pytest.hdl import _SIMULATORS, HDL\nfrom cocotb_tools.pytest.mark import _register_markers\nfrom cocotb_tools.runner import Runner, get_runner\n\n_ENTRY_POINT: str = \",\".join(\n    (\n        \"cocotb_tools._coverage:start_cocotb_library_coverage\",\n        \"cocotb.logging:_configure\",\n        \"cocotb._init:init_package_from_simulation\",\n        \"cocotb_tools.pytest._init:run_regression\",\n    )\n)\nif TYPE_CHECKING:\n    from typing import TypeAlias\n\n    TestStatus: TypeAlias = (\n        TestShortLogReport | tuple[str, str, str | tuple[str, Mapping[str, bool]]]\n    )\n\n\ndef _to_timescale(value: str) -> tuple[str, str]:\n    \"\"\"Split string containing timescale to time unit and time precision.\n\n    Args:\n        value: Timescale in format of ``UNIT[/PRECISION]``.\n\n    Returns:\n        Time unit and time precision based on provided timescale.\n    \"\"\"\n    time_unit, _, time_precision = value.partition(\"/\")\n\n    time_unit = time_unit.strip()\n    time_precision = time_precision.strip()\n\n    return time_unit, time_precision or time_unit\n\n\ndef _to_dict(items: Iterable[str]) -> dict[str, object]:\n    \"\"\"Convert list of items into dictionary.\n\n    Args:\n        items: List of items in form of ``NAME=VALUE``.\n\n    Returns:\n        List of items as dictionary.\n    \"\"\"\n    result: dict[str, object] = {}\n\n    for item in items:\n        name, _, value = item.partition(\"=\")\n        result[name] = value\n\n    return result\n\n\n_OPTIONS: tuple[Option, ...] = (\n    Option(\n        \"cocotb_summary\",\n        action=\"store_true\",\n        description=\"Show cocotb test summary info.\",\n    ),\n    Option(\n        \"cocotb_sim_time_unit\",\n        choices=(\"step\", \"fs\", \"ps\", \"ns\", \"us\", \"ms\", \"sec\"),\n        default=\"ns\",\n        description=\"Simulation time unit that will be used during tests reporting.\",\n    ),\n    Option(\n        \"cocotb_gui\",\n        action=\"store_true\",\n        description=\"Enable the GUI mode in the simulator (if supported).\",\n    ),\n    Option(\n        \"cocotb_waves\",\n        action=\"store_true\",\n        description=\"Enable wave traces dump for simulator (if supported).\",\n    ),\n    Option(\n        \"cocotb_waveform_viewer\",\n        metavar=\"NAME\",\n        default=\"surfer\",\n        description=\"\"\"\n            The name of the waveform viewer executable to use (like surfer) when GUI mode is enabled for simulators\n            that do not have a built-in waveform viewer (like Verilator) The executable name will be called with the\n            name of the waveform file as the argument.\n        \"\"\",\n    ),\n    Option(\n        \"cocotb_seed\",\n        metavar=\"INTEGER\",\n        default=int(time()),\n        default_in_help=\"current epoch time in seconds\",\n        environment=\"COCOTB_RANDOM_SEED\",\n        type=int,\n        description=\"Seed the Python random module to recreate a previous test stimulus.\",\n    ),\n    Option(\n        \"cocotb_attach\",\n        metavar=\"SECONDS\",\n        default=0,\n        type=int,\n        description=\"\"\"\n            Pause time value in seconds before the simulator start. If set to non-zero value, cocotb will print the\n            process ID (PID) to attach to and wait the specified time in seconds before actually letting the\n            simulator run.\n        \"\"\",\n    ),\n    Option(\n        \"cocotb_plusargs\",\n        nargs=\"*\",\n        default=[],\n        metavar=\"PLUSARG\",\n        description=\"\"\"\n            Plusargs are options that are starting with a plus (``+``) sign.  They are passed to the simulator and are\n            also available within cocotb as cocotb.plusargs. In the simulator, they can be read by the\n            Verilog/SystemVerilog system functions ``$test$plusargs`` and ``$value$plusargs``.\n        \"\"\",\n    ),\n    Option(\n        \"cocotb_resolve_x\",\n        choices=(\"error\", \"weak\", \"zeros\", \"ones\", \"random\"),\n        description=\"\"\"\n            Defines how to resolve bits with a value of ``X``, ``Z``, ``U``, ``W``, or ``-`` when being converted to integer. Valid settings are:\n\n            * ``error``:  Resolves nothing.\n            * ``weak``:   Resolves ``L`` to 0 and ``H`` to 1.\n            * ``zeros``:  Like weak, but resolves all other non-0/1 values to ``0``.\n            * ``ones``:   Like weak, but resolves all other non-0/1 values to ``1``.\n            * ``random``: Like weak, but resolves all other non-0/1 values randomly to either 0 or 1.\n\n            There is also a slight difference in behavior of bool(logic).\n            When this is set, bool(logic) treats all non-0/1 values as equivalent to 0.\n            When this is not set, bool(logic) will fail on non-0/1 values.\n            Warning: Using this feature is not recommended.\n        \"\"\",\n    ),\n    Option(\n        \"cocotb_scheduler_debug\",\n        action=\"store_true\",\n        description=\"\"\"\n            Enable additional log output of the coroutine scheduler. This will default the value of debug, which\n            can later be modified.\n        \"\"\",\n    ),\n    Option(\n        \"cocotb_simulator\",\n        choices=(\"auto\", *tuple(_SIMULATORS.values())),\n        default=\"auto\",\n        metavar=\"NAME\",\n        description=\"\"\"\n            Select HDL simulator for cocotb. The ``auto`` option will automatically pick one of available HDL\n            simulators where precedence order is based on available choices for this argument, from the highest priority\n            (most left) to the lowest priority (most right).\n        \"\"\",\n    ),\n    Option(\n        \"cocotb_trust_inertial_writes\",\n        action=\"store_true\",\n        description=\"\"\"\n            It enables a mode which allows cocotb to trust that VPI/VHPI/FLI inertial writes are applied properly\n            according to the respective standards. This mode can lead to noticeable performance improvements, and\n            also includes some behavioral difference that are considered by the cocotb maintainers to be “better”.\n            Not all simulators handle inertial writes properly, so use with caution. This is achieved by not\n            scheduling writes to occur at the beginning of the ``ReadWrite`` mode, but instead trusting that the\n            simulator’s inertial write mechanism is correct. This allows cocotb to avoid a VPI callback into Python\n            to apply writes.\n        \"\"\",\n    ),\n    Option(\n        \"cocotb_pytest_args\",\n        type=shlex.split,\n        default=[],\n        metavar=\"ARGS\",\n        description=\"\"\"\n            By default, instance of pytest that is running from HDL simulator as regression manager for cocotb tests,\n            will be called with the same command line arguments as pytest invoked by user from command line that\n            is starting cocotb runners (HDL simulators). This option allows user to override it and pass own\n            arguments to pytest instance that is running from HDL simulator process. For example,\n            it can be used to set different verbosity levels or capture modes between them.\n            Example: ``pytest -v --capture=no --cocotb-pytest-args='-vv --capture=fd'``\n        \"\"\",\n    ),\n    Option(\n        \"cocotb_pytest_dir\",\n        default_in_help=\"current working directory\",\n        metavar=\"PATH\",\n        type=Path,\n        description=\"Override path from where pytest was invoked.\",\n    ),\n    Option(\n        \"cocotb_build_dir\",\n        default=\"sim_build\",\n        metavar=\"PATH\",\n        type=Path,\n        description=\"Directory to run the build step in.\",\n    ),\n    Option(\n        \"cocotb_defines\",\n        nargs=\"*\",\n        metavar=\"NAME[=VALUE]\",\n        default=[],\n        description=\"Extra defines to set.\",\n    ),\n    Option(\n        \"cocotb_includes\",\n        nargs=\"*\",\n        metavar=\"PATH\",\n        default=[],\n        type=Path,\n        description=\"Extra Verilog include directories.\",\n    ),\n    Option(\n        \"cocotb_parameters\",\n        nargs=\"*\",\n        metavar=\"NAME[=VALUE]\",\n        default=[],\n        description=\"Extra Verilog parameters or VHDL generics.\",\n    ),\n    Option(\n        \"cocotb_library\",\n        default=\"top\",\n        metavar=\"NAME\",\n        description=\"The library name to compile into.\",\n    ),\n    Option(\n        \"cocotb_always\",\n        action=\"store_true\",\n        description=\"Always run the build step.\",\n    ),\n    Option(\n        \"cocotb_clean\",\n        action=\"store_true\",\n        description=\"Delete build directory before building.\",\n    ),\n    Option(\n        \"cocotb_verbose\",\n        action=\"store_true\",\n        description=\"Enable verbose messages.\",\n    ),\n    Option(\n        \"cocotb_timescale\",\n        metavar=\"UNIT[/PRECISION]\",\n        description=\"Timescale containing time unit and time precision for simulation.\",\n    ),\n    Option(\n        \"cocotb_env\",\n        metavar=\"NAME[=VALUE]\",\n        nargs=\"*\",\n        default=[],\n        description=\"Extra environment variables to set.\",\n    ),\n    Option(\n        \"cocotb_toplevel_library\",\n        default=\"top\",\n        metavar=\"NAME\",\n        description=\"The library name for HDL toplevel module.\",\n    ),\n    Option(\n        \"cocotb_toplevel_lang\",\n        choices=(\"auto\", \"verilog\", \"vhdl\"),\n        default=\"auto\",\n        description=\"\"\"\n            Language of the HDL toplevel module.\n            Can be set to notify tests about preferred language in multi-language HDL design.\n            This is also used by simulators that support more than one interface\n            (:term:`VPI`, :term:`VHPI`, or :term:`FLI`) to select the appropriate interface to start cocotb.\n            When set to ``auto``, value will be automatically evaluated based on selected HDL simulator or\n            list of HDL source files provided during build stage in :py:meth:`cocotb_tools.pytest.hdl.HDL.build` or\n            :py:meth:`cocotb_tools.runner.Runner.build` methods.\n        \"\"\",\n    ),\n    Option(\n        \"cocotb_gpi_interfaces\",\n        nargs=\"*\",\n        metavar=\"NAME\",\n        default=[],\n        description=\"List of GPI interfaces to use, with the first one being the entry point.\",\n    ),\n    Option(\n        \"cocotb_build_args\",\n        type=shlex.split,\n        default=[],\n        metavar=\"ARGS\",\n        description=\"Extra build arguments for the simulator.\",\n    ),\n    Option(\n        \"cocotb_elab_args\",\n        type=shlex.split,\n        default=[],\n        metavar=\"ARGS\",\n        description=\"Extra elaboration arguments for the simulator.\",\n    ),\n    Option(\n        \"cocotb_test_args\",\n        type=shlex.split,\n        default=[],\n        metavar=\"ARGS\",\n        description=\"Extra arguments for the simulator.\",\n    ),\n    Option(\n        \"cocotb_pre_cmd\",\n        type=shlex.split,\n        default=[],\n        metavar=\"ARGS\",\n        description=\"Extra commands to run before simulation begins.\",\n    ),\n    Option(\n        \"cocotb_log_level\",\n        choices=(\"trace\", \"debug\", \"info\", \"warning\", \"error\", \"critical\"),\n        description=\"\"\"\n            The default log level of all \"cocotb\" Python loggers. The default is unset, which means that the log\n            level is inherited from the root logger. This behaves similarly to :py:const:`logging.NOTSET`.\n        \"\"\",\n    ),\n    Option(\n        \"gpi_log_level\",\n        choices=(\"trace\", \"debug\", \"info\", \"warning\", \"error\", \"critical\"),\n        description=\"\"\"\n            The default log level of all \"gpi\" (the low-level simulator interface) loggers, including both Python\n            and the native GPI logger. The default is unset, which means that the log level is inherited from the\n            root logger. This behaves similarly to :py:const:`logging.NOTSET`.\n        \"\"\",\n    ),\n    Option(\n        \"pygpi_users\",\n        nargs=\"*\",\n        metavar=\"MODULE:FUNCTION\",\n        default=(_ENTRY_POINT,),\n        description=\"\"\"\n            The Python module and callable that starts up the Python cosimulation environment. User overloads can be\n            used to enter alternative Python frameworks or to hook existing cocotb functionality. It is formatted as\n            ``path.to.entry.module:entry_point.function,other_module:other_func``. The string before the colon is the\n            Python module to import and the string following the colon is the object to call as the entry function.\n            The entry function must be a callable matching this form: ``entry_function(argv: List[str]) -> None``\n        \"\"\",\n    ),\n)\n\n\ndef _options_for_documentation() -> ArgumentParser:\n    \"\"\"It helps to attach plugin options into Sphinx documentation using the sphinx-argparse extension.\"\"\"\n    parser: ArgumentParser = ArgumentParser(\n        prog=\"pytest\",\n        description=\"Plugin options\",\n    )\n\n    for option in _OPTIONS:\n        default: Any\n\n        if option.extra.get(\"action\") == \"store_true\":\n            default = False\n        else:\n            default = option.default_in_help or option.default\n\n        parser.add_argument(\n            option.argument,\n            help=(\n                f\"{textwrap.dedent(option.description)}\\n\\n\"\n                f\"Configuration option: ``{option.name}``\\n\\n\"\n                f\"Environment variable: :envvar:`{option.environment}`\"\n            ),\n            default=default,\n            **option.extra,\n        )\n\n    return parser\n\n\n@fixture(scope=\"session\")\ndef dut() -> SimHandleBase:\n    \"\"\"A cocotb fixture that is providing a simulation handle to DUT.\n\n    Provided simulation handle is the same as :py:data:`cocotb.top`.\n\n    Example usage:\n\n    .. code:: python\n\n        async def test_dut_feature_1(dut) -> None:\n            dut.rst.value = 0\n            dut.clk.value = 0\n\n            # Testing DUT feature\n            ...\n\n    Returns:\n        Simulation handle to DUT (equivalent to :py:data:`cocotb.top`).\n    \"\"\"\n    return cocotb.top\n\n\n@fixture(scope=\"session\")\ndef hdl_session(request: FixtureRequest) -> HDL:\n    \"\"\"A cocotb fixture that is providing a helper instance to define own HDL design and to build it.\n\n    .. note::\n\n        This fixture is scoped to global ``session`` scope.\n        It can be useful to build the whole HDL project with different HDL modules at once not per test.\n\n    It contains own instance of :py:class:`~cocotb_tools.runner.Runner` that can be accessed directly\n    from :py:attr:`~cocotb_tools.pytest.hdl.HDL.runner` member.\n\n    Defined HDL design can be build by invoking the :py:meth:`~cocotb_tools.pytest.hdl.HDL.build()` method\n    from **non-async** test functions. This method will invoke build step from :py:attr:`~cocotb_tools.pytest.hdl.HDL.runner` member.\n\n    Requested fixture will pass various plugin :ref:`options <pytest-plugin-options>`\n    to own instance of :py:class:`~cocotb_tools.runner.Runner`. Like setting a desired verbosity level for cocotb runner.\n\n    Please refer to available public members of :py:class:`~cocotb_tools.pytest.hdl.HDL` that can be used to define own HDL design.\n\n    Example usage:\n\n    .. code:: python\n\n        import pytest\n        from cocotb_tools.pytest.hdl import HDL\n\n\n        @pytest.fixture(scope=\"session\")\n        def my_hdl_project(hdl_session: HDL) -> HDL:\n            # Build whole HDL design with all HDL modules at once\n            hdl_session.sources = (\n                # Add more HDL source files here\n                # ...\n                DIR / \"my_hdl_module_1.sv\",\n                DIR / \"my_hdl_module_2.sv\",\n            )\n\n            hdl_session.build()\n\n            return hdl_session\n\n\n        @pytest.fixture(name=\"my_hdl_module_1\")\n        def my_hdl_module_1_fixture(hdl: HDL, my_hdl_project: HDL) -> HDL:\n            # Define HDL module 1\n            hdl.build_dir = my_hdl_project.build_dir\n            hdl.toplevel = \"my_hdl_module_1\"\n\n            return hdl\n\n\n        @pytest.fixture(name=\"my_hdl_module_2\")\n        def my_hdl_module_2_fixture(hdl: HDL, my_hdl_project: HDL) -> HDL:\n            # Define HDL module 2\n            hdl.build_dir = my_hdl_project.build_dir\n            hdl.toplevel = \"my_hdl_module_2\"\n\n            return hdl\n\n\n        @pytest.mark.cocotb_runner\n        def test_dut_1(my_hdl_module_1: HDL) -> None:\n            # Run HDL simulator with cocotb tests\n            my_hdl_module_1.test()\n\n\n        @pytest.mark.cocotb_runner\n        def test_dut_2(my_hdl_module_2: HDL) -> None:\n            # Run HDL simulator with cocotb tests\n            my_hdl_module_2.test()\n\n\n    Args:\n        request: The pytest fixture request that is providing plugin :ref:`options <pytest-plugin-options>`\n                 to this fixture. These options will be used to configure own instance of\n                 :py:class:`~cocotb_tools.runner.Runner`.\n\n    Returns:\n        Instance that allows to build and test HDL design.\n    \"\"\"\n    return request.config.hook.pytest_cocotb_make_hdl(request=request)\n\n\n@fixture\ndef hdl(request: FixtureRequest, hdl_session: HDL) -> HDL:\n    \"\"\"A cocotb fixture that is providing a helper instance to define own HDL design, to build it and\n    run set of cocotb tests from test modules (testbenches) against selected top level design.\n\n    .. note::\n\n        This fixture is scoped to default ``function`` scope.\n        It can help to build HDL module per test and run tests for defined HDL top level.\n\n    It contains own instance of :py:class:`~cocotb_tools.runner.Runner` that can be accessed directly\n    from :py:attr:`~cocotb_tools.pytest.hdl.HDL.runner` member.\n\n    Defined HDL design can be build by invoking the :py:meth:`~cocotb_tools.pytest.hdl.HDL.build()` method and\n    test by invoking the :py:meth:`~cocotb_tools.pytest.hdl.HDL.test()` method from **non-async** test functions.\n    These methods will invoke build and test steps from :py:attr:`~cocotb_tools.pytest.hdl.HDL.runner` member.\n\n    Requested fixture will pass various plugin :ref:`options <pytest-plugin-options>`\n    to own instance of :py:class:`~cocotb_tools.runner.Runner`. Like setting a desired verbosity level for cocotb runner.\n\n    Please refer to available public members of :py:class:`~cocotb_tools.pytest.hdl.HDL` that can be used to define own HDL design.\n\n    Example usage:\n\n    .. code:: python\n\n        import pytest\n        from cocotb_tools.pytest.hdl import HDL\n\n\n        @pytest.fixture(name=\"my_hdl_module\")\n        def my_hdl_module_fixture(hdl: HDL) -> HDL:\n            # Build HDL module per test\n            hdl.toplevel = \"my_hdl_module\"\n\n            hdl.sources = (\n                # Add more HDL source files here\n                # ...\n                DIR / \"my_hdl_module.sv\",\n            )\n\n            hdl.build()\n\n            return hdl\n\n\n        @pytest.mark.cocotb_runner\n        def test_dut(my_hdl_module: HDL) -> None:\n            # Run HDL simulator with cocotb tests\n            my_hdl_module.test()\n\n\n    Args:\n        request: The pytest fixture request that is providing plugin :ref:`options <pytest-plugin-options>`\n                 to this fixture. These options will be used to configure own instance of\n                 :py:class:`~cocotb_tools.runner.Runner`.\n        hdl_session: HDL design defined at global ``session`` scope level.\n\n    Returns:\n        Instance that allows to build and test HDL design.\n    \"\"\"\n    instance: HDL = request.config.hook.pytest_cocotb_make_hdl(request=request)\n\n    # Runner in test() method is checking for hdl_toplevel_lang,\n    # if missing then it will retrieve this information from list of HDL source files\n    # Unfortunately, they are not set in Runner created during function scope when build() was not called\n    if not hdl_session.toplevel_lang and hasattr(hdl_session.runner, \"_sources\"):\n        instance.toplevel_lang = hdl_session.runner._check_hdl_toplevel_lang(\n            hdl_session.toplevel_lang\n        )\n\n    return instance\n\n\ndef pytest_addoption(parser: Parser, pluginmanager: PytestPluginManager) -> None:\n    add_options_to_parser(parser, \"cocotb\", _OPTIONS)\n\n\ndef pytest_addhooks(pluginmanager: PytestPluginManager) -> None:\n    \"\"\"Called at plugin registration time to add specification of cocotb hooks.\n\n    Args:\n        pluginmanager: The pytest plugin manager.\n    \"\"\"\n    pluginmanager.add_hookspecs(hookspecs)\n\n\n@hookimpl(trylast=True)\ndef pytest_cocotb_make_hdl(request: FixtureRequest) -> HDL:\n    \"\"\"Create new instance of :py:class:`cocotb_tools.pytest.hdl.HDL`.\n\n    Args:\n        request: The pytest fixture request object.\n\n    Returns:\n        New instance of HDL.\n    \"\"\"\n    return HDL(request)\n\n\n@hookimpl(trylast=True)\ndef pytest_cocotb_make_runner(simulator_name: str) -> Runner:\n    \"\"\"Create new instance of :py:class:`cocotb_tools.runner.Runner`.\n\n    Args:\n        simulator_name: Name of HDL simulator.\n\n    Returns:\n        New instance of runner.\n    \"\"\"\n    return get_runner(simulator_name)\n\n\n@hookimpl(tryfirst=True)\ndef pytest_configure(config: Config) -> None:\n    option = config.option\n\n    _register_markers(config)\n    populate_ini_to_options(config, _OPTIONS)\n\n    if not option.cocotb_timescale:\n        option.cocotb_timescale = None\n\n    elif isinstance(option.cocotb_timescale, str):\n        option.cocotb_timescale = _to_timescale(option.cocotb_timescale)\n\n    if isinstance(option.cocotb_env, list):\n        option.cocotb_env = _to_dict(option.cocotb_env)\n\n    if isinstance(option.cocotb_defines, list):\n        option.cocotb_defines = _to_dict(option.cocotb_defines)\n\n    if isinstance(option.cocotb_parameters, list):\n        option.cocotb_parameters = _to_dict(option.cocotb_parameters)\n\n    config.pluginmanager.register(Logging(config), \"cocotb_logging\")\n\n    if not getattr(cocotb, \"is_simulation\", False):\n        config.pluginmanager.register(Controller(config), \"cocotb_controller\")\n\n\n@hookimpl(tryfirst=True)\ndef pytest_pycollect_makeitem(\n    collector: Module | Class, name: str, obj: object\n) -> Item | Collector | list[Item | Collector] | None:\n    if is_cocotb_decorator(obj):\n        obj = cocotb_decorator_as_pytest_marks(collector, name, obj)\n\n        return collector.config.hook.pytest_pycollect_makeitem(\n            collector=collector, name=name, obj=obj\n        )\n\n    if inspect.isfunction(obj):\n        markers: list[Mark] | None = getattr(obj, \"pytestmark\", None)\n\n        if any(\n            marker.name in (\"cocotb_runner\", \"cocotb_test\") for marker in markers or ()\n        ):\n            setattr(obj, \"__test__\", True)\n\n        elif (\n            inspect.iscoroutinefunction(obj)\n            and \"dut\" in inspect.signature(obj).parameters\n        ):\n            marker: Mark = mark.cocotb_test().mark\n\n            if markers is None:\n                setattr(obj, \"pytestmark\", [marker])\n            else:\n                markers.append(marker)\n\n    return None\n\n\ndef _is_cocotb_test_report(item: Any) -> bool:\n    \"\"\"Check if provided pytest item is cocotb test report.\n\n    Args:\n        item: Pytest item (test report).\n\n    Returns:\n        True if provided pytest item is cocotb test report. Otherwise False.\n    \"\"\"\n    return isinstance(item, TestReport) and getattr(item, \"cocotb\", False)\n\n\n@hookimpl(hookwrapper=True, trylast=True)\ndef pytest_report_teststatus(\n    report: CollectReport | TestReport, config: Config\n) -> Generator[None, Result[TestStatus], None]:\n    result: Result[TestStatus] = yield\n    status: TestStatus = result.get_result()\n\n    if (\n        isinstance(report, TestReport)\n        and (\"cocotb_runner\" in report.keywords)\n        and (report.when == \"call\")\n    ):\n        category, letter, word = status\n        category = f\"{category} cocotb runner\"\n        if isinstance(word, str):\n            word = f\"{word} COCOTB RUNNER\"\n        else:\n            word = (f\"{word[0]} COCOTB RUNNER\", word[1])\n        result.force_result(\n            TestShortLogReport(category=category, letter=letter, word=word)\n        )\n\n\n@hookimpl(hookwrapper=True, tryfirst=True)\ndef pytest_terminal_summary(\n    terminalreporter: TerminalReporter,\n    exitstatus: ExitCode,\n    config: Config,\n) -> Generator[None]:\n    # Print cocotb runner failures before test failures\n    terminalreporter.summary_failures_combined(\n        which_reports=\"failed cocotb runner\",\n        sep_title=\"COCOTB RUNNER FAILURES\",\n        style=config.option.tbstyle,\n    )\n    # Continue with the rest of pytest terminal summary\n    yield\n\n    if not config.option.cocotb_summary:\n        return\n\n    terminalreporter.section(\"cocotb test summary info\", cyan=True, bold=True)\n    sim_time_unit: str = config.option.cocotb_sim_time_unit\n\n    summary: tuple[list[str], ...] = (\n        [\"TEST\"],\n        [\"STATUS\"],\n        [f\"SIM TIME ({sim_time_unit})\"],\n        [\"REAL TIME (s)\"],\n        [f\"RATIO ({sim_time_unit}/s)\"],\n    )\n\n    map_status: dict[str, str] = {\n        \"passed\": \"PASS\",\n        \"failed\": \"FAIL\",\n        \"skipped\": \"SKIP\",\n        \"xfailed\": \"PASS\",\n        \"xpassed\": \"FAIL\",\n    }\n\n    count: dict[str, int] = {\n        \"PASS\": 0,\n        \"FAIL\": 0,\n        \"SKIP\": 0,\n    }\n\n    status_markups: dict[str, tuple[str, ...]] = {\n        \"PASS\": (\"green\",),\n        \"FAIL\": (\"red\",),\n        \"SKIP\": (\"yellow\",),\n    }\n\n    widths: list[int] = [len(column[0]) for column in summary]\n    aligns: tuple[str, ...] = (\"<\", \"^\", \">\", \">\", \">\")\n    sum_sim_time: float = 0\n    sum_real_time: float = 0\n    tests: int = 0\n\n    for status, items in terminalreporter.stats.items():\n        if status in (\"passed\", \"failed\", \"skipped\", \"xfailed\", \"xpassed\"):\n            test_status = map_status[status]\n\n            for item in items:\n                if _is_cocotb_test_report(item):\n                    count[test_status] += 1\n                    tests += 1\n\n                    sim_time: float = getattr(item, \"sim_time_duration\", 0)\n                    real_time: float = getattr(item, \"duration\", 0)\n                    ratio: float = sim_time / real_time if real_time else 0\n\n                    sum_sim_time += sim_time\n                    sum_real_time += real_time\n\n                    summary[0].append(item.nodeid)\n                    summary[1].append(test_status)\n                    summary[2].append(f\"{sim_time:.2f} \")\n                    summary[3].append(f\"{real_time:.2f} \")\n                    summary[4].append(f\"{ratio:.2f} \")\n\n                    for index, column_width in enumerate(widths):\n                        widths[index] = max(column_width, len(summary[index][-1]))\n\n    sum_ratio = sum_sim_time / sum_real_time if sum_real_time else 0\n    passed: int = count[\"PASS\"]\n    failed: int = count[\"FAIL\"]\n    skipped: int = count[\"SKIP\"]\n\n    summary[0].append(f\"TESTS={tests} PASS={passed} FAIL={failed} SKIP={skipped}\")\n    summary[1].append(\"\")\n    summary[2].append(f\"{sum_sim_time:.2f} \")\n    summary[3].append(f\"{sum_real_time:.2f} \")\n    summary[4].append(f\"{sum_ratio:.2f} \")\n\n    rows: int = len(summary[0])\n    columns: int = len(summary)\n    last: int = rows - 1\n\n    for row in range(rows):\n        if row == last:\n            terminalreporter.write_sep(\"-\")\n\n        terminalreporter.write(\"**\")\n\n        for column in range(columns):\n            value: Any = summary[column][row]\n            width: int = widths[column]\n            align: str = aligns[column]\n            markups: dict[str, bool] = {}\n\n            if column == 1 and row not in (0, last):\n                markups = dict.fromkeys(status_markups[value], True)\n\n            terminalreporter.write(f\" {{:{align}{width}}} \".format(value), **markups)\n\n        terminalreporter.write(\"**\\n\")\n        terminalreporter.ensure_newline()\n\n        if row == 0:\n            terminalreporter.write_sep(\"-\")\n\n    terminalreporter.flush()\n"
  },
  {
    "path": "src/cocotb_tools/pytest/py.typed",
    "content": ""
  },
  {
    "path": "src/cocotb_tools/runner.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Build HDL and run cocotb tests.\"\"\"\n\n# TODO: maybe do globbing and expanduser/expandvars in --include, --vhdl-sources, --verilog-sources\n# TODO: create a short README and a .gitignore (content: \"*\") in both build_dir and test_dir? (Some other tools do this.)\n# TODO: support timescale on all simulators\n# TODO: support custom dependencies\nfrom __future__ import annotations\n\nimport logging\nimport multiprocessing\nimport os\nimport re\nimport shlex\nimport shutil\nimport subprocess\nimport sys\nimport tempfile\nimport warnings\nfrom abc import ABC, abstractmethod\nfrom collections.abc import Iterable, Mapping, Sequence\nfrom contextlib import suppress\nfrom itertools import chain\nfrom pathlib import Path\nfrom typing import (\n    Any,\n    Generic,\n    TextIO,\n    TypeVar,\n    Union,\n)\n\nimport find_libpython\n\nimport cocotb_tools.config\nfrom cocotb_tools import _env\nfrom cocotb_tools.check_results import get_results\nfrom cocotb_tools.sim_versions import NvcVersion\n\nif sys.version_info >= (3, 10):\n    from typing import TypeAlias\n\nPathLike: TypeAlias = Union[\"os.PathLike[str]\", str]\n\"A path that can be passed to :class:`pathlib.Path` or :func:`open`\"\n\n_Command: TypeAlias = list[str]\n\n_magic_re = re.compile(r\"([\\\\{}])\")\n_space_re = re.compile(r\"([\\s])\", re.ASCII)\n\n\nMAX_PARALLEL_BUILD_JOBS: int = 4\n\"\"\"The maximum number of parallel build threads in calls to :meth:`.Runner.build`.\n\nIf the number of CPU cores is less than this value, it uses the CPU core count.\nSet this variable to globally change the number of parallel build jobs.\n\"\"\"\n\n\ndef _get_max_parallel_build_jobs() -> int:\n    return min(MAX_PARALLEL_BUILD_JOBS, multiprocessing.cpu_count())\n\n\ndef _as_tcl_value(value: str) -> str:\n    # add '\\' before special characters and spaces\n    value = _magic_re.sub(r\"\\\\\\1\", value)\n    value = value.replace(\"\\n\", r\"\\n\")\n    value = _space_re.sub(r\"\\\\\\1\", value)\n    if value[:1] == '\"':\n        value = \"\\\\\" + value\n\n    return value\n\n\n_sv_escapes = {\n    \"\\n\": \"\\\\n\",\n    \"\\t\": \"\\\\t\",\n    \"\\\\\": \"\\\\\\\\\",\n    '\"': '\\\\\"',\n    \"\\v\": \"\\\\v\",\n    \"\\f\": \"\\\\f\",\n    \"\\xff\": \"\\\\xFF\",\n}\nfor i in range(32):\n    if chr(i) not in _sv_escapes:\n        _sv_escapes[chr(i)] = f\"\\\\x{i:02x}\"\n\n_sv_escape_translate_table = str.maketrans(_sv_escapes)\n\n\ndef _as_sv_literal(value: object) -> str:\n    if isinstance(value, (int, float)):\n        return str(value)\n    elif isinstance(value, str):\n        return '\"' + value.translate(_sv_escape_translate_table) + '\"'\n    else:\n        raise TypeError(\"Can't serialize this type as an SV literal\")\n\n\ndef _shlex_join(split_command: Iterable[str]) -> str:\n    \"\"\"\n    Return a shell-escaped string from *split_command*\n    This is here more for compatibility purposes\n    \"\"\"\n    return \" \".join(shlex.quote(arg) for arg in split_command)\n\n\n_T = TypeVar(\"_T\")\n\n\nclass _Tag(Generic[_T]):\n    def __init__(self, value: _T) -> None:\n        self.value = value\n\n    def __repr__(self) -> str:\n        return f\"{type(self).__qualname__}({self.value!r})\"\n\n\nclass _ValueAndTag(Generic[_T]):\n    def __init__(self, value: _T, tag: type[_Tag]) -> None:\n        self.value = value\n        self.tag = tag\n\n\nclass _ValueAndOptionalTag(Generic[_T]):\n    def __init__(self, value: _T, tag: type[_Tag] | None) -> None:\n        self.value = value\n        self.tag = tag\n\n\nclass VHDL(_Tag):\n    \"\"\"Tags source files and build arguments to :meth:`Runner.build() <cocotb_tools.runner.Runner.build>` as VHDL-specific.\"\"\"\n\n\nclass Verilog(_Tag):\n    \"\"\"Tags source files and build arguments to :meth:`Runner.build() <cocotb_tools.runner.Runner.build>` as Verilog-specific.\"\"\"\n\n\nclass VerilatorControlFile(_Tag):\n    \"\"\"Tags source files to :meth:`Runner.build() <cocotb_tools.runner.Runner.build>` as Verilator control files.\"\"\"\n\n\n_verilog_extensions = (\".v\", \".sv\", \".vh\", \".svh\")\n_vhdl_extensions = (\".vhd\", \".vhdl\")\n\n\ndef _determine_file_type(\n    filename: PathLike,\n) -> type[Verilog] | type[VHDL] | type[VerilatorControlFile]:\n    ext = Path(filename).suffix\n    if ext in _verilog_extensions:\n        return Verilog\n    elif ext in _vhdl_extensions:\n        return VHDL\n    elif ext == \".vlt\":\n        return VerilatorControlFile\n    else:\n        raise ValueError(\n            f\"Can't determine source file type of {filename}. Use the `VHDL`, `Verilog`, or `VerilatorControlFile` tags.\"\n        )\n\n\nclass Runner(ABC):\n    supported_gpi_interfaces: dict[str, list[str]] = {}\n\n    def __init__(self) -> None:\n        self._simulator_in_path()\n\n        self.env: dict[str, str] = {}\n\n        # for running test() independently of build()\n        self.build_dir: Path = get_abs_path(\"sim_build\")\n        self.parameters: Mapping[str, object] = {}\n\n        self.log = logging.getLogger(type(self).__qualname__)\n        self.log.setLevel(logging.INFO)\n\n    @abstractmethod\n    def _simulator_in_path(self) -> None:\n        \"\"\"Raise exception if the simulator executable does not exist in :envvar:`PATH`.\n\n        Raises:\n            SystemExit: Simulator executable does not exist in :envvar:`PATH`.\n        \"\"\"\n\n    def _check_hdl_toplevel_lang(self, hdl_toplevel_lang: str | None) -> str:\n        \"\"\"Return *hdl_toplevel_lang* if supported by simulator, raise exception otherwise.\n\n        Returns:\n            *hdl_toplevel_lang* if supported by the simulator.\n\n        Raises:\n            ValueError: *hdl_toplevel_lang* is not supported by the simulator.\n        \"\"\"\n        if hdl_toplevel_lang is None:\n            if self._vhdl_sources and not self._verilog_sources and not self._sources:\n                lang = \"vhdl\"\n            elif self._verilog_sources and not self._vhdl_sources and not self._sources:\n                lang = \"verilog\"\n            elif self._sources and not self._vhdl_sources and not self._verilog_sources:\n                top_source = self._sources[-1]\n                if top_source.tag is VHDL:\n                    lang = \"vhdl\"\n                elif top_source.tag is Verilog:\n                    lang = \"verilog\"\n                else:\n                    raise ValueError(\n                        \"First argument to *sources* must be a VHDL or Verilog file. \"\n                        f\"Got a {top_source.tag.__qualname__} file: {top_source.value}\"\n                    )\n            else:\n                raise ValueError(\n                    f\"{type(self).__qualname__}: Must specify a hdl_toplevel_lang in a mixed-language design\"\n                )\n        else:\n            lang = hdl_toplevel_lang\n\n        if lang in self.supported_gpi_interfaces:\n            return lang\n        else:\n            raise ValueError(\n                f\"{type(self).__qualname__}: hdl_toplevel_lang {hdl_toplevel_lang!r} is not \"\n                f\"in supported list: {', '.join(self.supported_gpi_interfaces)}\"\n            )\n\n    def _set_env_common(self) -> None:\n        # We have to set all environment variables before building because Xcelium and VCS load VPI for some reason.\n        # TODO: Remove this. Why are Xcelium and VCS loading VPI during build?\n\n        self.env.update(os.environ)\n\n        gpi_users: list[str] = []\n\n        # Ensure libpython is in GPI_USERS before pygpi_entry_point\n        if \"GPI_USERS\" not in self.env:\n            if (libpython_loc := self.env.get(\"LIBPYTHON_LOC\")) is not None:\n                gpi_users.append(libpython_loc)\n            else:\n                libpython_path = find_libpython.find_libpython()\n                if libpython_path is None:\n                    raise ValueError(\n                        \"Unable to find libpython, please make sure the appropriate libpython is installed\"\n                    )\n                gpi_users.append(libpython_path)\n\n        # TODO the following line reappends the path on every call to build() or test(). This needs to not be an attribute.\n        # Most of the stuff on this class really shouldn't be an attribute, but that's a non-trivial and API-breaking refactor.\n        self.env[\"PATH\"] += os.pathsep + str(cocotb_tools.config.libs_dir)\n        self.env[\"PYTHONPATH\"] = os.pathsep.join(sys.path)\n        self.env[\"PYGPI_PYTHON_BIN\"] = sys.executable\n        if \"GPI_USERS\" not in self.env:\n            gpi_users.append(cocotb_tools.config.pygpi_entry_point())\n            self.env[\"GPI_USERS\"] = \";\".join(gpi_users)\n\n    def _set_env_build(self) -> None:\n        self._set_env_common()\n\n    def _set_env_test(self) -> None:\n        \"\"\"Set environment variables for sub-processes.\"\"\"\n        self._set_env_common()\n\n        # The NVC simulator allows specifying the top unit as {entity}-{arch}.\n        # The architecture is needed during elaboration, but when finding the root handle\n        # we only need the entity name, so strip off the architecture if present.\n        self.env[\"COCOTB_TOPLEVEL\"] = self.sim_hdl_toplevel.split(\"-\")[0]\n        self.env[\"COCOTB_TEST_MODULES\"] = self.test_module\n        self.env[\"TOPLEVEL_LANG\"] = self.hdl_toplevel_lang\n\n    @abstractmethod\n    def _build_command(self) -> Sequence[_Command]:\n        \"\"\"Return command to build the HDL sources.\"\"\"\n\n    @abstractmethod\n    def _test_command(self) -> Sequence[_Command]:\n        \"\"\"Return command to run a test.\"\"\"\n\n    def _use_external_viewer(self) -> bool:\n        \"\"\"Return if an external viewer should be called after simulation when ``gui=True``.\"\"\"\n        return False\n\n    def _waves_file(self) -> str | None:\n        \"\"\"Return file name of the generated waveform file for use with external viewer.\"\"\"\n        return None\n\n    def build(\n        self,\n        hdl_library: str = \"top\",\n        verilog_sources: Sequence[PathLike | Verilog] = [],\n        vhdl_sources: Sequence[PathLike | VHDL] = [],\n        sources: Sequence[PathLike | VHDL | Verilog | VerilatorControlFile] = [],\n        includes: Sequence[PathLike] = [],\n        defines: Mapping[str, object] = {},\n        parameters: Mapping[str, object] = {},\n        build_args: Sequence[str | VHDL | Verilog] = [],\n        hdl_toplevel: str | None = None,\n        always: bool = False,\n        build_dir: PathLike = \"sim_build\",\n        cwd: PathLike | None = None,\n        clean: bool = False,\n        verbose: bool = False,\n        timescale: tuple[str, str] | None = None,\n        waves: bool = False,\n        log_file: PathLike | None = None,\n    ) -> None:\n        \"\"\"Build the HDL sources.\n\n        With mixed language simulators, *sources* will be built,\n        followed by *vhdl_sources*, then *verilog_sources*.\n        With simulators that only support either VHDL or Verilog, *sources* will be built,\n        followed by *vhdl_sources* and *verilog_sources*, respectively.\n\n        If your source files use an atypical file extension,\n        use :class:`VHDL`, :class:`Verilog`, or :class:`VerilatorControlFile`\n        to tag the path as a VHDL, Verilog, or Verilator control file source file, respectively.\n        If the filepaths aren't tagged, the extension is used to determine if they are VHDL or Verilog files.\n\n        +----------+------------------------------------+\n        | Language | File Extensions                    |\n        +==========+====================================+\n        | VHDL     | ``.vhd``, ``.vhdl``                |\n        +----------+------------------------------------+\n        | Verilog  | ``.v``, ``.sv``, ``.vh``, ``.svh`` |\n        +----------+------------------------------------+\n\n\n        .. code-block:: python\n\n            runner.build(\n                sources=[\n                    VHDL(\"/my/file.is_actually_vhdl\"),\n                    Verilog(\"/other/file.verilog\"),\n                ],\n            )\n\n        The same tagging works for *build_args*.\n        Tagged *build_args* only supply that option to the compiler when building the source file for the tagged language.\n        Non-tagged *build_args* are supplied when compiling any language.\n\n        Args:\n            hdl_library: The library name to compile into.\n            verilog_sources: Verilog source files to build.\n            vhdl_sources: VHDL source files to build.\n            sources: Language-agnostic list of source files to build.\n            includes: Verilog include directories.\n            defines: Defines to set.\n            parameters: Verilog parameters or VHDL generics.\n            build_args: Extra build arguments for the simulator.\n            hdl_toplevel: The name of the HDL toplevel module.\n            always: Always run the build step.\n            build_dir: Directory to run the build step in.\n            cwd: Directory to execute the build command(s) in. Defaults to *build_dir*.\n            clean: Delete *build_dir* before building.\n            verbose: Enable verbose messages.\n            timescale: Tuple containing time unit and time precision for simulation.\n            waves: Record signal traces. Overridden by the :envvar:`WAVES` environment variable.\n            log_file: File to write the build log to.\n\n        .. deprecated:: 2.0\n\n            Uses of the *verilog_sources* and *vhdl_sources* parameters should be replaced with the language-agnostic *sources* argument.\n        \"\"\"\n\n        self.clean: bool = clean\n        self.build_dir = get_abs_path(build_dir)\n        if self.clean:\n            self.rm_build_folder(self.build_dir)\n        self.build_dir.mkdir(parents=True, exist_ok=True)\n\n        # note: to avoid mutating argument defaults, we ensure that no value\n        # is written without a copy. This is much more concise and leads to\n        # a better docstring than using `None` as a default in the parameters\n        # list.\n        self.hdl_library: str = hdl_library\n        if verilog_sources:\n            warnings.warn(\n                \"Simulator.build *verilog_sources* parameter is deprecated. Use the language-agnostic *sources* parameter instead.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n        self._set_verilog_sources(verilog_sources)\n        if vhdl_sources:\n            warnings.warn(\n                \"Simulator.build *vhdl_sources* parameter is deprecated. Use the language-agnostic *sources* parameter instead.\",\n                DeprecationWarning,\n                stacklevel=2,\n            )\n        self._set_vhdl_sources(vhdl_sources)\n        self._set_sources(sources)\n        self.includes: list[Path] = [\n            get_abs_path(include_dir) for include_dir in includes\n        ]\n        self.defines = dict(defines)\n        self.parameters = dict(parameters)\n        self._set_build_args(build_args)\n        self.always: bool = always\n        self.hdl_toplevel: str | None = hdl_toplevel\n        self.verbose: bool = verbose\n        self.timescale: tuple[str, str] | None = timescale\n        self.log_file: PathLike | None = log_file\n        self.cwd = self.build_dir if cwd is None else cwd\n\n        self.waves = _env.as_bool(\"WAVES\", waves)\n\n        self._set_env_build()\n\n        cmds: Sequence[_Command] = self._build_command()\n        self._execute(cmds, cwd=self.cwd)\n\n    def test(\n        self,\n        test_module: str | Sequence[str],\n        hdl_toplevel: str,\n        hdl_toplevel_library: str = \"top\",\n        hdl_toplevel_lang: str | None = None,\n        gpi_interfaces: list[str] | None = None,\n        testcase: str | Sequence[str] | None = None,\n        seed: str | int | None = None,\n        elab_args: Sequence[str] = [],\n        test_args: Sequence[str] = [],\n        plusargs: Sequence[str] = [],\n        extra_env: Mapping[str, str] = {},\n        waves: bool = False,\n        gui: bool = False,\n        parameters: Mapping[str, object] | None = None,\n        build_dir: PathLike | None = None,\n        test_dir: PathLike | None = None,\n        results_xml: str | None = None,\n        pre_cmd: list[str] | None = None,\n        verbose: bool = False,\n        timescale: tuple[str, str] | None = None,\n        log_file: PathLike | None = None,\n        test_filter: str | None = None,\n    ) -> Path:\n        \"\"\"Run the tests.\n\n        Args:\n            test_module: Name(s) of the Python module(s) containing the tests to run.\n                Can be a comma-separated list.\n            hdl_toplevel: Name of the HDL toplevel module.\n            hdl_toplevel_library: The library name for HDL toplevel module.\n            hdl_toplevel_lang: Language of the HDL toplevel module.\n            gpi_interfaces: List of GPI interfaces to use, with the first one being the entry point.\n            testcase: Name(s) of a specific testcase(s) to run.\n                If not set, run all testcases found in *test_module*.\n                Can be a comma-separated list.\n            seed: A specific random seed to use.\n            elab_args: A list of elaboration arguments for the simulator.\n            test_args: A list of extra arguments for the simulator.\n            plusargs: 'plusargs' to set for the simulator.\n            extra_env: Extra environment variables to set.\n            waves: Record signal traces. Overridden by the :envvar:`WAVES` environment variable.\n            gui: Run with simulator GUI. Overridden by the :envvar:`GUI` environment variable.\n            parameters: Verilog parameters or VHDL generics.\n            build_dir: Directory the build step has been run in.\n            test_dir: Directory to run the tests in.\n            results_xml: Name of xUnit XML file to store test results in.\n                If an absolute path is provided it will be used as-is,\n                :file:`{build_dir}/results.xml` otherwise.\n                This argument should not be set when run with ``pytest``.\n            verbose: Enable verbose messages.\n            pre_cmd: Commands to run before simulation begins.\n                Typically Tcl commands for simulators that support them.\n            timescale: Tuple containing time unit and time precision for simulation.\n            log_file: File to write the test log to.\n            test_filter: Regular expression which matches test names.\n                Only matched tests are run if this argument if given.\n\n        Returns:\n            The absolute location of the results XML file which can be\n            defined by the *results_xml* argument.\n        \"\"\"\n\n        __tracebackhide__ = True  # Hide the traceback when using pytest\n\n        if build_dir is not None:\n            self.build_dir = get_abs_path(build_dir)\n\n        if parameters is not None:\n            self.parameters = dict(parameters)\n\n        if test_dir is None:\n            self.test_dir = self.build_dir\n        else:\n            self.test_dir = get_abs_path(test_dir)\n        self.test_dir.mkdir(parents=True, exist_ok=True)\n\n        if isinstance(test_module, str):\n            self.test_module = test_module\n        else:\n            self.test_module = \",\".join(test_module)\n\n        # note: to avoid mutating argument defaults, we ensure that no value\n        # is written without a copy. This is much more concise and leads to\n        # a better docstring than using `None` as a default in the parameters\n        # list.\n        self.sim_hdl_toplevel = hdl_toplevel\n        self.hdl_toplevel_library: str = hdl_toplevel_library\n        self.hdl_toplevel_lang = self._check_hdl_toplevel_lang(hdl_toplevel_lang)\n        if gpi_interfaces:\n            self.gpi_interfaces = gpi_interfaces\n        else:\n            self.gpi_interfaces = []\n            for gpi_if in self.supported_gpi_interfaces.values():\n                self.gpi_interfaces.append(gpi_if[0])\n\n        self.pre_cmd = pre_cmd\n\n        self.elab_args = list(elab_args)\n        self.test_args = list(test_args)\n        self.plusargs = list(plusargs)\n        self.env = dict(extra_env)\n\n        if testcase is not None:\n            if isinstance(testcase, str):\n                names = [s.strip() for s in testcase.split(\",\") if s.strip()]\n            else:\n                names = list(testcase)\n            regex = r\"\\.(\" + \"|\".join(rf\".*{re.escape(name)}\" for name in names) + \")$\"\n            self.env[\"COCOTB_TEST_FILTER\"] = regex\n\n        if test_filter is not None:\n            self.env[\"COCOTB_TEST_FILTER\"] = test_filter\n\n        if seed is not None:\n            self.env[\"COCOTB_RANDOM_SEED\"] = str(seed)\n\n        self.log_file = log_file\n        self.waves = _env.as_bool(\"WAVES\", waves)\n        self.gui = _env.as_bool(\"GUI\", gui)\n        self.timescale = timescale\n\n        if verbose is not None:\n            self.verbose = verbose\n\n        # Pytest test name is used by the next couple sections.\n        pytest_current_test: str = _env.as_str(\"PYTEST_CURRENT_TEST\")\n\n        if pytest_current_test:\n            self.current_test_name = pytest_current_test.rsplit(\":\", maxsplit=1)[\n                -1\n            ].split(\" \", maxsplit=1)[0]\n        else:\n            self.current_test_name = \"test\"\n\n        results_xml_path: None | Path = (\n            Path(results_xml) if results_xml is not None else None\n        )\n\n        # result.xml filename precedence:\n        # 1. absolute path\n        # 2. pytest test name\n        # 3. relative path\n        # 4. default name\n        if results_xml_path is not None and results_xml_path.is_absolute():\n            results_xml_file = results_xml_path\n        elif pytest_current_test:\n            if results_xml_path is not None:\n                raise NotImplementedError(\n                    \"Relative result_xml paths aren't supported when using pytest\"\n                )\n            results_xml_file = self.test_dir / f\"{self.current_test_name}.result.xml\"\n        elif results_xml_path is not None:\n            results_xml_file = self.test_dir / results_xml_path\n        else:\n            results_xml_file = self.test_dir / \"results.xml\"\n\n        with suppress(OSError):\n            results_xml_file.unlink()\n\n        # transport the settings to cocotb via environment variables\n        self._set_env_test()\n        self.env[\"COCOTB_RESULTS_FILE\"] = str(results_xml_file)\n\n        cmds: Sequence[_Command] = self._test_command()\n        simulator_exit_code: int = 0\n        try:\n            self._execute(cmds, cwd=self.test_dir)\n        except subprocess.CalledProcessError as e:\n            # It is possible for the simulator to fail but still leave results.\n            self.log.error(\"Simulation failed: %d\", e.returncode)\n            simulator_exit_code = e.returncode\n\n        # Only when running under pytest, check the results file here,\n        # potentially raising an exception with failing testcases,\n        # otherwise return the results file for later analysis.\n        if pytest_current_test:\n            try:\n                (num_tests, num_failed) = get_results(results_xml_file)\n            except RuntimeError as e:\n                self.log.error(\"%s\", e.args[0])\n                sys.exit(simulator_exit_code)\n            else:\n                if num_failed:\n                    self.log.error(\n                        \"ERROR: Failed %d of %d tests.\", num_failed, num_tests\n                    )\n                    sys.exit(1 if simulator_exit_code == 0 else simulator_exit_code)\n\n        if simulator_exit_code != 0:\n            sys.exit(simulator_exit_code)\n\n        if pytest_current_test and self._use_external_viewer() and self.gui:\n            viewer: str = _env.as_str(\"COCOTB_WAVEFORM_VIEWER\")\n            if viewer:\n                viewer_path = shutil.which(viewer)\n                if viewer_path is None:\n                    raise ValueError(f\"Cannot find {viewer} in the system path\")\n            else:\n                viewer_path = shutil.which(\"surfer\")\n                if viewer_path is None:\n                    viewer_path = shutil.which(\"gtkwave\")\n            if viewer_path is None:\n                raise SystemError(\n                    \"Cannot find any viewer (surfer or gtkwave) in the system path\"\n                )\n\n            subprocess.run(\n                [f\"{viewer_path} {self._waves_file()}\"],\n                cwd=self.test_dir,\n                check=True,\n                shell=True,\n            )\n\n        self.log.info(\"Results file: %s\", results_xml_file)\n        return results_xml_file\n\n    @abstractmethod\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        \"\"\"Return simulator-specific formatted option strings with *includes* directories.\"\"\"\n\n    @abstractmethod\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        \"\"\"Return simulator-specific formatted option strings with *defines* macros.\"\"\"\n\n    @abstractmethod\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        \"\"\"Return simulator-specific formatted option strings with *parameters*/generics.\"\"\"\n\n    def _execute(self, cmds: Sequence[_Command], cwd: PathLike) -> None:\n        __tracebackhide__ = True  # Hide the traceback when using PyTest.\n\n        if self.log_file is None:\n            self._execute_cmds(cmds, cwd)\n        else:\n            with open(self.log_file, \"w\") as f:\n                self._execute_cmds(cmds, cwd, f)\n\n    def _execute_cmds(\n        self, cmds: Sequence[_Command], cwd: PathLike, stdout: TextIO | None = None\n    ) -> None:\n        __tracebackhide__ = True  # Hide the traceback when using PyTest.\n\n        for cmd in cmds:\n            self.log.info(\"Running command %s in directory %s\", _shlex_join(cmd), cwd)\n\n            # TODO: create a thread to handle stderr and log as error?\n            # TODO: log forwarding\n\n            stderr = None if stdout is None else subprocess.STDOUT\n            subprocess.run(\n                cmd, cwd=cwd, env=self.env, check=True, stdout=stdout, stderr=stderr\n            )\n\n    def rm_build_folder(self, build_dir: Path) -> None:\n        if build_dir.is_dir():\n            self.log.info(\"Removing: %s\", build_dir)\n            shutil.rmtree(build_dir, ignore_errors=True)\n\n    @property\n    def verilog_sources(self) -> list[Path]:\n        return [source.value for source in self._verilog_sources]\n\n    @verilog_sources.setter\n    def verilog_sources(self, value: list[Path]) -> None:\n        self._set_verilog_sources(value)\n\n    def _set_verilog_sources(\n        self, sources: Sequence[PathLike | Verilog | VerilatorControlFile]\n    ) -> None:\n        verilog_sources: list[_ValueAndTag] = []\n        for source in sources:\n            if isinstance(source, _Tag):\n                if isinstance(source, (Verilog, VerilatorControlFile)):\n                    abs_path = get_abs_path(source.value)\n                    verilog_sources.append(_ValueAndTag(abs_path, type(source)))\n                else:\n                    raise ValueError(f\"Unsupported file type: {source}\")\n            else:\n                tag = _determine_file_type(source)\n                abs_path = get_abs_path(source)\n                verilog_sources.append(_ValueAndTag(abs_path, tag))\n        self._verilog_sources = verilog_sources\n\n    @property\n    def vhdl_sources(self) -> list[Path]:\n        return [source.value for source in self._vhdl_sources]\n\n    @vhdl_sources.setter\n    def vhdl_sources(self, value: list[Path]) -> None:\n        self._set_vhdl_sources(value)\n\n    def _set_vhdl_sources(self, sources: Sequence[PathLike | VHDL]) -> None:\n        vhdl_sources: list[_ValueAndTag] = []\n        for source in sources:\n            if isinstance(source, _Tag):\n                if isinstance(source, VHDL):\n                    abs_path = get_abs_path(source.value)\n                    vhdl_sources.append(_ValueAndTag(abs_path, type(source)))\n                else:\n                    raise ValueError(f\"Unsupported file type: {source}\")\n            else:\n                tag = _determine_file_type(source)\n                abs_path = get_abs_path(source)\n                vhdl_sources.append(_ValueAndTag(abs_path, tag))\n        self._vhdl_sources = vhdl_sources\n\n    @property\n    def sources(self) -> list[Path]:\n        return [source.value for source in self._sources]\n\n    @sources.setter\n    def sources(self, value: list[Path]) -> None:\n        self._set_sources(value)\n\n    def _set_sources(\n        self, sources: Sequence[PathLike | Verilog | VHDL | VerilatorControlFile]\n    ) -> None:\n        sources_: list[_ValueAndTag] = []\n        for source in sources:\n            if isinstance(source, _Tag):\n                if isinstance(source, (Verilog, VHDL, VerilatorControlFile)):\n                    abs_path = get_abs_path(source.value)\n                    sources_.append(_ValueAndTag(abs_path, type(source)))\n                else:\n                    raise ValueError(f\"Unsupported file type: {source}\")\n            else:\n                tag = _determine_file_type(source)\n                abs_path = get_abs_path(source)\n                sources_.append(_ValueAndTag(abs_path, tag))\n        self._sources = sources_\n\n    @property\n    def build_args(self) -> list[str]:\n        return [arg.value for arg in self._build_args]\n\n    @build_args.setter\n    def build_args(self, value: list[str]) -> None:\n        self._set_build_args(value)\n\n    def _set_build_args(self, build_args: Sequence[str | Verilog | VHDL]) -> None:\n        build_args_: list[_ValueAndOptionalTag] = []\n        for build_arg in build_args:\n            if isinstance(build_arg, _Tag):\n                if isinstance(build_arg, (Verilog, VHDL)):\n                    build_args_.append(\n                        _ValueAndOptionalTag(build_arg.value, type(build_arg))\n                    )\n                else:\n                    raise ValueError(f\"Unsupported tag type: {build_arg}\")\n            else:\n                build_args_.append(_ValueAndOptionalTag(build_arg, None))\n        self._build_args = build_args_\n\n    def _get_sim_cmd_prefix(self) -> list[str]:\n        sim_cmd_prefix_str = os.getenv(\"SIM_CMD_PREFIX\")\n        if sim_cmd_prefix_str:\n            return sim_cmd_prefix_str.split()\n        else:\n            return []\n\n    def _get_sim_cmd_suffix(self) -> list[str]:\n        sim_cmd_suffix_str = os.getenv(\"SIM_CMD_SUFFIX\")\n        if sim_cmd_suffix_str:\n            return sim_cmd_suffix_str.split()\n        else:\n            return []\n\n\ndef outdated(output: Path, dependencies: Iterable[Path]) -> bool:\n    \"\"\"Return ``True`` if any source files in *dependencies* are newer than the *output* directory.\n\n    Returns:\n        ``True`` if any source files are newer, ``False`` otherwise.\n    \"\"\"\n\n    if not output.is_file():\n        return True\n\n    output_mtime = output.stat().st_mtime\n\n    dep_mtime = 0.0\n    for dependency in dependencies:\n        mtime = dependency.stat().st_mtime\n        dep_mtime = max(mtime, dep_mtime)\n\n    return dep_mtime > output_mtime\n\n\ndef get_abs_path(path: PathLike) -> Path:\n    \"\"\"Return *path* in absolute form.\"\"\"\n\n    path = Path(path)\n    if path.is_absolute():\n        return path.resolve()\n    else:\n        return Path(Path.cwd() / path).resolve()\n\n\nclass Icarus(Runner):\n    \"\"\"Implementation of :class:`Runner` for Icarus Verilog.\n\n    .. admonition:: Simulator-specific Usage\n\n       * ``hdl_toplevel`` argument to :meth:`.build` is *required*.\n       * ``waves=True`` *must* be given to :meth:`.build` if either ``waves`` or ``gui`` are to be used during :meth:`.test`.\n       * ``timescale`` argument to :meth:`.build` must be given to support dumping the command file.\n       * Does not support the ``pre_cmd`` argument to :meth:`.test`.\n    \"\"\"\n\n    supported_gpi_interfaces = {\"verilog\": [\"vpi\"]}\n\n    def _simulator_in_path(self) -> None:\n        if shutil.which(\"iverilog\") is None:\n            raise SystemExit(\"ERROR: iverilog executable not found!\")\n\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        return [f\"-I{include}\" for include in includes]\n\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        return [f\"-D{name}={_as_sv_literal(value)}\" for name, value in defines.items()]\n\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        return [\n            f\"-P{self.hdl_toplevel}.{name}={value}\"\n            for name, value in parameters.items()\n        ]\n\n    def _use_external_viewer(self) -> bool:\n        return True\n\n    def _waves_file(self) -> str | None:\n        return f\"{self.hdl_toplevel}.fst\"\n\n    def _create_cmd_file(self) -> None:\n        assert self.timescale is not None\n        with open(self.cmds_file, \"w\") as f:\n            f.write(\"+timescale+{}/{}\\n\".format(*self.timescale))\n\n    def _create_iverilog_dump_file(self) -> None:\n        dumpfile_path = _as_sv_literal(str(self.build_dir / f\"{self.hdl_toplevel}.fst\"))\n        with open(self.iverilog_dump_file, \"w\") as f:\n            f.write(\"module cocotb_iverilog_dump();\\n\")\n            f.write(\"initial begin\\n\")\n            f.write(\"    string dumpfile_path;\")\n            f.write(\n                '    if ($value$plusargs(\"dumpfile_path=%s\", dumpfile_path)) begin\\n'\n            )\n            f.write(\"        $dumpfile(dumpfile_path);\\n\")\n            f.write(\"    end else begin\\n\")\n            f.write(f\"        $dumpfile({dumpfile_path});\\n\")\n            f.write(\"    end\\n\")\n            f.write(f\"    $dumpvars(0, {self.hdl_toplevel});\\n\")\n            f.write(\"end\\n\")\n            f.write(\"endmodule\\n\")\n\n    @property\n    def sim_file(self) -> Path:\n        return self.build_dir / \"sim.vvp\"\n\n    @property\n    def iverilog_dump_file(self) -> Path:\n        return self.build_dir / \"cocotb_iverilog_dump.v\"\n\n    @property\n    def cmds_file(self) -> Path:\n        return self.build_dir / \"cmds.f\"\n\n    def _build_command(self) -> list[_Command]:\n        if self.hdl_toplevel is None:\n            raise ValueError(\"hdl_toplevel argument is required for all Icarus builds\")\n\n        sources = self._sources + self._verilog_sources\n\n        for source in sources:\n            if source.tag is not Verilog:\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports Verilog. {str(source.value)!r} cannot be compiled.\"\n                )\n\n        for arg in self._build_args:\n            if arg.tag not in (Verilog, None):\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports Verilog. build_args {arg.value!r} cannot be applied.\"\n                )\n\n        build_args = [arg.value for arg in self._build_args]\n        if self.waves:\n            self._create_iverilog_dump_file()\n            build_args += [\"-s\", \"cocotb_iverilog_dump\"]\n\n        if self.timescale is not None:\n            self._create_cmd_file()\n            build_args += [\"-f\", str(self.cmds_file)]\n\n        cmds: list[_Command] = []\n        if outdated(self.sim_file, (source.value for source in sources)) or self.always:\n            cmds = [\n                [\n                    \"iverilog\",\n                    \"-o\",\n                    str(self.sim_file),\n                    \"-s\",\n                    self.hdl_toplevel,\n                    \"-g2012\",\n                ]\n                + self._get_define_options(self.defines)\n                + self._get_include_options(self.includes)\n                + self._get_parameter_options(self.parameters)\n                + [arg for arg in build_args if type(arg) in (str, Verilog)]\n                + [str(source_file.value) for source_file in sources]\n                + [\n                    str(source_file)\n                    for source_file in [self.iverilog_dump_file]\n                    if self.waves\n                ]\n            ]\n\n        else:\n            self.log.warning(\"Skipping compilation of %s\", self.sim_file)\n\n        return cmds\n\n    def _test_command(self) -> list[_Command]:\n        if self.pre_cmd is not None:\n            raise RuntimeError(\"pre_cmd is not implemented for Icarus Verilog.\")\n\n        plusargs = self.plusargs\n        if self.waves or self.gui:\n            plusargs += [\"-fst\"]\n        else:\n            # Disable waveform output\n            plusargs += [\"-none\"]\n\n        return [\n            [\n                *self._get_sim_cmd_prefix(),\n                \"vvp\",\n                \"-m\",\n                cocotb_tools.config.lib_name_path(\"vpi\", \"icarus\").as_posix(),\n                *self.test_args,\n                str(self.sim_file),\n                *plusargs,\n                *self._get_sim_cmd_suffix(),\n            ]\n        ]\n\n\nclass Questa(Runner):\n    \"\"\"Implementation of :class:`Runner` for Siemens Questa.\n\n    .. admonition:: Simulator-specific Usage\n\n       * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`.\n    \"\"\"\n\n    supported_gpi_interfaces = {\"verilog\": [\"vpi\"], \"vhdl\": [\"fli\", \"vhpi\"]}\n\n    def _simulator_in_path(self) -> None:\n        if shutil.which(\"vsim\") is None:\n            raise SystemExit(\"ERROR: vsim executable not found!\")\n\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        return [f\"+incdir+{_as_tcl_value(str(include))}\" for include in includes]\n\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        return [\n            f\"+define+{name}={_as_sv_literal(value)}\" for name, value in defines.items()\n        ]\n\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        return [f\"-g{name}={value}\" for name, value in parameters.items()]\n\n    def _build_command(self) -> list[_Command]:\n        cmds = []\n\n        cmds.append([\"vlib\", _as_tcl_value(self.hdl_library)])\n\n        verbosity_opts = []\n        if not self.verbose:\n            verbosity_opts += [\"-quiet\"]\n\n        vhdl_args = [\n            _as_tcl_value(arg.value)\n            for arg in self._build_args\n            if arg.tag in (VHDL, None)\n        ]\n        verilog_args = [\n            _as_tcl_value(arg.value)\n            for arg in self._build_args\n            if arg.tag in (Verilog, None)\n        ]\n        hdl_library = _as_tcl_value(self.hdl_library)\n        defines = self._get_define_options(self.defines)\n        includes = self._get_include_options(self.includes)\n\n        for source in chain(self._sources, self._vhdl_sources, self._verilog_sources):\n            if source.tag is VHDL:\n                cmds.append(\n                    [\n                        \"vcom\",\n                        *verbosity_opts,\n                        \"-work\",\n                        hdl_library,\n                        *vhdl_args,\n                        _as_tcl_value(str(source.value)),\n                    ]\n                )\n            elif source.tag is Verilog:\n                cmds.append(\n                    [\n                        \"vlog\",\n                        *verbosity_opts,\n                        *([] if self.always else [\"-incr\"]),\n                        \"-work\",\n                        hdl_library,\n                        \"-sv\",\n                        *defines,\n                        *includes,\n                        *verilog_args,\n                        _as_tcl_value(str(source.value)),\n                    ]\n                )\n            else:\n                raise ValueError(f\"Unsupported file type: {source.value}\")\n\n        return cmds\n\n    def _test_command(self) -> list[_Command]:\n        cmds = []\n\n        verbosity_opts = []\n        if not self.verbose:\n            verbosity_opts += [\"-quiet\"]\n\n        if self.pre_cmd is not None:\n            pre_cmd = [\"-do\", *self.pre_cmd]\n        else:\n            pre_cmd = []\n\n        do_script = \"\"\n        if self.waves:\n            do_script += \"log -recursive /*;\"\n\n        if not self.gui:\n            do_script += \"run -all; quit\"\n\n        gpi_if_entry = self.gpi_interfaces[0]\n        if gpi_if_entry == \"fli\":\n            lib_opts = [\n                \"-foreign\",\n                \"cocotb_init \"\n                + _as_tcl_value(\n                    cocotb_tools.config.lib_name_path(\"fli\", \"questa\").as_posix()\n                ),\n            ]\n        elif gpi_if_entry == \"vhpi\":\n            lib_opts = [\"-voptargs=-access=rw+/.\"]\n            lib_opts += [\n                \"-foreign\",\n                \"vhpi_startup_routines_bootstrap \"\n                + _as_tcl_value(\n                    cocotb_tools.config.lib_name_path(\"vhpi\", \"questa\").as_posix()\n                ),\n            ]\n        else:\n            lib_opts = [\n                \"-pli\",\n                _as_tcl_value(\n                    cocotb_tools.config.lib_name_path(\"vpi\", \"questa\").as_posix()\n                ),\n            ]\n\n        cmds.append(\n            self._get_sim_cmd_prefix()\n            + [\"vsim\"]\n            + verbosity_opts\n            + [\"-gui\" if self.gui else \"-c\"]\n            + [\"-onfinish\", \"stop\" if self.gui else \"exit\"]\n            + lib_opts\n            + [_as_tcl_value(v) for v in self.test_args]\n            + [_as_tcl_value(v) for v in self._get_parameter_options(self.parameters)]\n            + [_as_tcl_value(f\"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}\")]\n            + [_as_tcl_value(v) for v in self.plusargs]\n            + pre_cmd\n            + [\"-do\", do_script]\n            + self._get_sim_cmd_suffix(),\n        )\n\n        gpi_extra_list = []\n        for gpi_if in self.gpi_interfaces[1:]:\n            gpi_if_lib_path = cocotb_tools.config.lib_name_path(gpi_if, \"questa\")\n            if gpi_if_lib_path.is_file():\n                gpi_extra_list.append(\n                    gpi_if_lib_path.as_posix() + f\":cocotb{gpi_if}_entry_point\"\n                )\n            else:\n                raise RuntimeError(f\"{gpi_if_lib_path} library not found.\")\n        self.env[\"GPI_EXTRA\"] = \",\".join(gpi_extra_list)\n\n        return cmds\n\n\nclass Ghdl(Runner):\n    \"\"\"Implementation of :class:`Runner` for GHDL.\n\n    .. admonition:: Simulator-specific Usage\n\n       * Does not support the ``pre_cmd`` argument to :meth:`.test`.\n    \"\"\"\n\n    supported_gpi_interfaces = {\"vhdl\": [\"vpi\"]}\n\n    def _set_env_test(self) -> None:\n        super()._set_env_test()\n        if \"COCOTB_TRUST_INERTIAL_WRITES\" not in self.env:\n            self.env[\"COCOTB_TRUST_INERTIAL_WRITES\"] = \"1\"\n\n    def _simulator_in_path(self) -> None:\n        if shutil.which(\"ghdl\") is None:\n            raise SystemExit(\"ERROR: ghdl executable not found!\")\n\n    def _is_mcode_backend(self) -> bool:\n        \"\"\"Is GHDL using the mcode backend?\"\"\"\n        result = subprocess.run(\n            [\"ghdl\", \"--version\"],\n            check=True,\n            text=True,\n            stdout=subprocess.PIPE,\n            stderr=subprocess.STDOUT,\n        )\n        return \"mcode\" in result.stdout\n\n    def _use_external_viewer(self) -> bool:\n        return True\n\n    def _waves_file(self) -> str | None:\n        return f\"{self.hdl_toplevel}.ghw\"\n\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        raise RuntimeError\n\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        raise RuntimeError\n\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        return [f\"-g{name}={value}\" for name, value in parameters.items()]\n\n    def _build_command(self) -> list[_Command]:\n        sources = self._sources + self._vhdl_sources\n\n        for source in sources:\n            if source.tag is not VHDL:\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports VHDL. {str(source.value)!r} cannot be compiled.\"\n                )\n\n        for arg in self._build_args:\n            if arg.tag not in (VHDL, None):\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports VHDL. build_args {arg.value!r} will not be applied.\"\n                )\n\n        cmds = [\n            [\"ghdl\", \"-i\"]\n            + [f\"--work={self.hdl_library}\"]\n            + [arg.value for arg in self._build_args]\n            + [str(source.value) for source in sources]\n        ]\n\n        if self.hdl_toplevel is not None:\n            cmds += [\n                [\n                    \"ghdl\",\n                    \"-m\",\n                    f\"--work={self.hdl_library}\",\n                    *(arg.value for arg in self._build_args),\n                    self.hdl_toplevel,\n                ]\n            ]\n\n        return cmds\n\n    def _test_command(self) -> list[_Command]:\n        if self.pre_cmd is not None:\n            raise RuntimeError(\"pre_cmd is not implemented for GHDL.\")\n\n        ghdl_run_args = self.test_args\n\n        if self._is_mcode_backend() and self.timescale:\n            _, precision = self.timescale\n            # Convert the time precision to a format string supported by GHDL,\n            # if possible.\n            # GHDL only supports setting the time precision if the mcode backend\n            # is used, using the --time-resolution argument causes GHDL to error\n            # out otherwise.\n            # https://ghdl.github.io/ghdl/using/InvokingGHDL.html#cmdoption-ghdl-time-resolution\n            if precision == \"1fs\":\n                ghdl_time_resolution = \"fs\"\n            elif precision == \"1ps\":\n                ghdl_time_resolution = \"ps\"\n            elif precision == \"1ns\":\n                ghdl_time_resolution = \"ns\"\n            elif precision == \"1us\":\n                ghdl_time_resolution = \"us\"\n            elif precision == \"1ms\":\n                ghdl_time_resolution = \"ms\"\n            elif precision == \"1s\":\n                ghdl_time_resolution = \"sec\"\n            else:\n                raise ValueError(\n                    \"GHDL only supports the following precisions in timescale: 1fs, 1ps, 1us, 1ms, 1s\"\n                )\n\n            ghdl_run_args.append(f\"--time-resolution={ghdl_time_resolution}\")\n\n        cmds = [\n            self._get_sim_cmd_prefix()\n            + [\"ghdl\", \"-r\"]\n            + [f\"--work={self.hdl_toplevel_library}\"]\n            + ghdl_run_args\n            + [self.sim_hdl_toplevel]\n            + [\"--vpi=\" + cocotb_tools.config.lib_name_path(\"vpi\", \"ghdl\").as_posix()]\n            + self.plusargs\n            + self._get_parameter_options(self.parameters)\n            + ([f\"--wave={self._waves_file()}\"] if self.waves or self.gui else [])\n            + self._get_sim_cmd_suffix(),\n        ]\n\n        return cmds\n\n\nclass Nvc(Runner):\n    \"\"\"Implementation of :class:`Runner` for NVC.\n\n    .. admonition:: Simulator-specific Usage\n\n       * Supports specifying a particular entity architecture by setting hdl_toplevel to {entity}-{arch}.\n       * Does not support the ``pre_cmd`` argument to :meth:`.test`.\n       * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`.\n    \"\"\"\n\n    supported_gpi_interfaces = {\"vhdl\": [\"vhpi\"]}\n\n    def __init__(self) -> None:\n        super().__init__()\n\n        version_str = subprocess.run(\n            [\"nvc\", \"--version\"],\n            check=True,\n            text=True,\n            stdout=subprocess.PIPE,\n        ).stdout\n        version = NvcVersion.from_commandline(version_str)\n        if version > NvcVersion(\"1.16\"):\n            self._preserve_case = [\"--preserve-case\"]\n        else:\n            self._preserve_case = []\n\n    def _set_env_test(self) -> None:\n        super()._set_env_test()\n        if \"COCOTB_TRUST_INERTIAL_WRITES\" not in self.env:\n            self.env[\"COCOTB_TRUST_INERTIAL_WRITES\"] = \"1\"\n\n    def _simulator_in_path(self) -> None:\n        if shutil.which(\"nvc\") is None:\n            raise SystemExit(\"ERROR: nvc executable not found!\")\n\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        raise RuntimeError\n\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        raise RuntimeError\n\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        return [f\"-g{name}={value}\" for name, value in parameters.items()]\n\n    def _use_external_viewer(self) -> bool:\n        return True\n\n    def _waves_file(self) -> str | None:\n        return f\"{self.hdl_toplevel}.fst\"\n\n    def _build_command(self) -> list[_Command]:\n        sources = self._sources + self._vhdl_sources\n\n        for source in sources:\n            if source.tag is not VHDL:\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports VHDL. {str(source.value)!r} cannot be compiled.\"\n                )\n\n        for arg in self._build_args:\n            if arg.tag not in (VHDL, None):\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports VHDL. build_args {arg.value!r} will not be applied.\"\n                )\n\n        cmds = [\n            [\n                \"nvc\",\n                f\"--work={self.hdl_library}\",\n                \"-L\",\n                str(get_abs_path(self.build_dir)),\n            ]\n            + [arg.value for arg in self._build_args]\n            + [\"-a\"]\n            + [str(source.value) for source in sources]\n            + self._preserve_case\n        ]\n\n        return cmds\n\n    def _test_command(self) -> list[_Command]:\n        work_library = str(get_abs_path(self.build_dir / self.hdl_toplevel_library))\n        cmds = [\n            [\n                *self._get_sim_cmd_prefix(),\n                \"nvc\",\n                f\"--work={self.hdl_toplevel_library}:{work_library}\",\n                \"-L\",\n                str(get_abs_path(self.build_dir)),\n            ]\n            + [arg.value for arg in self._build_args]\n            + [\"-e\", self.sim_hdl_toplevel, \"--no-save\", \"--jit\"]\n            + self.elab_args\n            + self._get_parameter_options(self.parameters)\n            + [\"-r\"]\n            + self.test_args\n            + [\"--load=\" + cocotb_tools.config.lib_name_path(\"vhpi\", \"nvc\").as_posix()]\n            + self.plusargs\n            + ([f\"--wave={self._waves_file()}\"] if self.waves or self.gui else [])\n            + self._get_sim_cmd_suffix(),\n        ]\n\n        return cmds\n\n\nclass AldecBase(Runner):\n    \"\"\"Implementation of :class:`Runner` for Aldec VsimSA.\n\n    .. admonition:: Simulator-specific Usage\n\n       * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`.\n    \"\"\"\n\n    supported_gpi_interfaces = {\"verilog\": [\"vpi\"], \"vhdl\": [\"vhpi\"]}\n\n    def _simulator_in_path(self) -> None:\n        if shutil.which(\"vsimsa\") is None:\n            raise SystemExit(\"ERROR: vsimsa executable not found!\")\n\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        return [f\"+incdir+{_as_tcl_value(str(include))}\" for include in includes]\n\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        return [\n            f\"+define+{name}={self._as_define_value(value)}\"\n            for name, value in defines.items()\n        ]\n\n    def _as_define_value(self, value: object) -> str:\n        if isinstance(value, int):\n            return str(value)\n        elif isinstance(value, str):\n            for char in value:\n                if ord(char) < 32 or ord(char) >= 255 or char in '\\\\\"':\n                    # Control characters are generally not supported.\n                    # Not sure if there's any way to escape quotes or backslashes.\n                    raise ValueError(\n                        f\"Character {char!r} not supported in define value\"\n                    )\n            return '\\\\\"\\\\\\\\\"' + value + '\\\\\\\\\"\\\\\"'\n        else:\n            raise TypeError(\"Can't serialize this type as an SV literal\")\n\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        return [f\"-g{name}={value}\" for name, value in parameters.items()]\n\n    def _build_command(self) -> list[_Command]:\n        do_script: list[str] = [\"onerror {\\n quit -code 1 \\n}\"]\n\n        out_file = self.build_dir / self.hdl_library / f\"{self.hdl_library}.lib\"\n\n        sources = self._sources + self._vhdl_sources + self._verilog_sources\n\n        if outdated(out_file, (source.value for source in sources)) or self.always:\n            vhdl_args = [\n                arg.value for arg in self._build_args if arg.tag in (VHDL, None)\n            ]\n            verilog_args = [\n                arg.value for arg in self._build_args if arg.tag in (Verilog, None)\n            ]\n            defines = \" \".join(self._get_define_options(self.defines))\n            includes = \" \".join(self._get_include_options(self.includes))\n            verilog_args_str = \" \".join(v for v in verilog_args)\n            vhdl_args_str = \" \".join(v for v in vhdl_args)\n            hdl_library = _as_tcl_value(self.hdl_library)\n            ext_name = _as_tcl_value(\n                cocotb_tools.config.lib_name_path(\"vpi\", \"riviera\").as_posix()\n            )\n\n            do_script.append(f\"alib {hdl_library}\")\n\n            for source in sources:\n                if source.tag is Verilog:\n                    do_script.append(\n                        f\"alog -work {hdl_library} -pli {ext_name} -sv {defines} {includes} {verilog_args_str} {_as_tcl_value(str(source.value))}\"\n                    )\n                elif source.tag is VHDL:\n                    do_script.append(\n                        f\"acom -work {hdl_library} {vhdl_args_str} {_as_tcl_value(str(source.value))}\"\n                    )\n                else:\n                    raise ValueError(f\"Unsupported file type: {source.value}\")\n\n        # Explicitly exit the script at the end. In batch mode, which is invoked\n        # implicitly by redirecting STDOUT/STDERR of the alog/acom commands,\n        # the tool exits by itself even without this 'exit' command -- but not\n        # when running from an interactive terminal. Be explicit for predictable\n        # behavior.\n        do_script.append(\"exit\")\n\n        with tempfile.NamedTemporaryFile(delete=False) as do_file:\n            do_file.write(\"\\n\".join(do_script).encode())\n\n        return [[\"vsimsa\", \"-do\", do_file.name]]\n\n    def _test_command(self) -> list[_Command]:\n        do_script: str = \"\"\n\n        do_script = self._append_onerror_command(do_script)\n\n        if self.hdl_toplevel_lang == \"vhdl\":\n            do_script += \"asim +access +w_nets -interceptcoutput -loadvhpi {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS}\\n\".format(\n                TOPLEVEL=_as_tcl_value(\n                    f\"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}\"\n                ),\n                EXT_NAME=_as_tcl_value(\n                    cocotb_tools.config.lib_name_path(\"vhpi\", \"riviera\").as_posix()\n                    + \":vhpi_startup_routines_bootstrap\"\n                ),\n                EXTRA_ARGS=\" \".join(\n                    _as_tcl_value(v)\n                    for v in (\n                        self.test_args + self._get_parameter_options(self.parameters)\n                    )\n                ),\n                PLUSARGS=\" \".join(_as_tcl_value(v) for v in self.plusargs),\n            )\n\n            self.env[\"GPI_EXTRA\"] = (\n                cocotb_tools.config.lib_name_path(\"vpi\", \"riviera\").as_posix()\n                + \":cocotbvpi_entry_point\"\n            )\n        else:\n            do_script += \"asim +access +w_nets -interceptcoutput -pli {EXT_NAME} {EXTRA_ARGS} {TOPLEVEL} {PLUSARGS} \\n\".format(\n                TOPLEVEL=_as_tcl_value(\n                    f\"{self.hdl_toplevel_library}.{self.sim_hdl_toplevel}\"\n                ),\n                EXT_NAME=_as_tcl_value(\n                    cocotb_tools.config.lib_name_path(\"vpi\", \"riviera\").as_posix()\n                ),\n                EXTRA_ARGS=\" \".join(\n                    _as_tcl_value(v)\n                    for v in (\n                        self.test_args + self._get_parameter_options(self.parameters)\n                    )\n                ),\n                PLUSARGS=\" \".join(_as_tcl_value(v) for v in self.plusargs),\n            )\n\n            self.env[\"GPI_EXTRA\"] = (\n                cocotb_tools.config.lib_name_path(\"vhpi\", \"riviera\").as_posix()\n                + \":cocotbvhpi_entry_point\"\n            )\n\n        do_script = self._append_pre_cmd(do_script)\n\n        if self.waves:\n            do_script += \"log -recursive /*;\"\n\n        do_script = self._append_run_commands(do_script)\n\n        with tempfile.NamedTemporaryFile(delete=False) as do_file:\n            do_file.write(do_script.encode())\n\n        return self._simulator_command(do_file)\n\n    def _append_onerror_command(self, do_script: str) -> str:\n        return do_script + \"\\nonerror {\\n quit -code 1 \\n} \\n\"\n\n    def _append_run_commands(self, do_script: str) -> str:\n        \"\"\"Append simulator-specific run commands.\"\"\"\n        return do_script + \"run -all \\nexit\"\n\n    def _simulator_command(self, do_file: Any) -> list[_Command]:\n        \"\"\"Return the simulator invocation command.\"\"\"\n        return [\n            [\n                *self._get_sim_cmd_prefix(),\n                \"vsimsa\",\n                \"-do\",\n                do_file.name,\n                *self._get_sim_cmd_suffix(),\n            ]\n        ]\n\n    def _append_pre_cmd(self, do_script: str) -> str:\n        \"\"\"Hook for subclasses to extend do_script with simulator-specific pre_cmd.\"\"\"\n        if self.pre_cmd is not None:\n            raise RuntimeError(\"pre_cmd is not implemented for this simulator.\")\n        return do_script\n\n\nclass Riviera(AldecBase):\n    \"\"\"Implementation of :class:`Runner` for Aldec Riviera-Pro.\n    .. admonition:: Simulator-specific Usage\n\n       * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`.\n    \"\"\"\n\n    def _append_onerror_command(self, do_script: str) -> str:\n        if self.gui:\n            return do_script\n        else:\n            return super()._append_onerror_command(do_script)\n\n    def _append_run_commands(self, do_script: str) -> str:\n        if getattr(self, \"gui\", False):\n            return do_script + \"echo execute run -all to run the whole simulation.\"\n        else:\n            return do_script + \"run -all \\nexit\"\n\n    def _simulator_command(self, do_file: Any) -> list[_Command]:\n        if getattr(self, \"gui\", False):\n            return [\n                [\n                    *self._get_sim_cmd_prefix(),\n                    \"riviera\",\n                    \"-do\",\n                    do_file.name,\n                    *self._get_sim_cmd_suffix(),\n                ]\n            ]\n        else:\n            return [\n                [\n                    *self._get_sim_cmd_prefix(),\n                    \"vsimsa\",\n                    \"-do\",\n                    do_file.name,\n                    *self._get_sim_cmd_suffix(),\n                ]\n            ]\n\n    def _append_pre_cmd(self, do_script: str) -> str:\n        if self.pre_cmd is None:\n            return do_script\n\n        if not isinstance(self.pre_cmd, list):\n            raise TypeError(\"pre_cmd must be a list of strings.\")\n        if not all(isinstance(s, str) for s in self.pre_cmd):\n            raise TypeError(\"pre_cmd must be a list of strings.\")\n\n        for s in self.pre_cmd:\n            do_script += f\"{s}; \"\n        return do_script + \"\\n\"\n\n\nclass ActiveHDL(AldecBase):\n    \"\"\"Implementation of :class:`Runner` for Aldec Active-HDL.\n    .. admonition:: Simulator-specific Usage\n\n       * Does not support the ``pre_cmd`` argument to :meth:`.test`.\n       * Does not support the ``gui`` argument to :meth:`.test`.\n       * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`.\n    \"\"\"\n\n    def _append_pre_cmd(self, do_script: str) -> str:\n        if self.pre_cmd is not None:\n            raise RuntimeError(\"pre_cmd is not implemented for Aldec ActiveHDL.\")\n        return do_script\n\n\nclass Verilator(Runner):\n    \"\"\"Implementation of :class:`Runner` for Verilator.\n\n    .. admonition:: Simulator-specific Usage\n\n       * ``waves=True`` *must* be given to :meth:`.build` if either ``waves`` or ``gui`` are to be used during :meth:`.test`.\n       * Does not support the ``pre_cmd`` argument to :meth:`.test`.\n    \"\"\"\n\n    supported_gpi_interfaces = {\"verilog\": [\"vpi\"]}\n\n    def _set_env_test(self) -> None:\n        super()._set_env_test()\n        if \"COCOTB_TRUST_INERTIAL_WRITES\" not in self.env:\n            self.env[\"COCOTB_TRUST_INERTIAL_WRITES\"] = \"1\"\n\n    def _simulator_in_path(self) -> None:\n        # the verilator binary is only needed for building\n        return\n\n    def _use_external_viewer(self) -> bool:\n        return True\n\n    def _waves_file(self) -> str | None:\n        return \"dump.vcd\"\n\n    def _simulator_in_path_build_only(self) -> None:\n        executable = shutil.which(\"verilator\")\n        if executable is None:\n            raise SystemExit(\"ERROR: verilator executable not found!\")\n        self.executable: str = executable\n\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        return [f\"-I{include}\" for include in includes]\n\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        return [f\"-D{name}={_as_sv_literal(value)}\" for name, value in defines.items()]\n\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        return [f\"-G{name}={value}\" for name, value in parameters.items()]\n\n    def _build_command(self) -> list[_Command]:\n        self._simulator_in_path_build_only()\n\n        sources = self._sources + self._verilog_sources\n\n        for source in sources:\n            if source.tag not in (Verilog, VerilatorControlFile):\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports Verilog and Verilator Control Files. {str(source.value)!r} cannot be compiled.\"\n                )\n\n        for arg in self._build_args:\n            if arg.tag not in (Verilog, None):\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports Verilog. build_args {arg.value!r} will not be applied.\"\n                )\n\n        if self.hdl_toplevel is None:\n            raise ValueError(\n                f\"{type(self).__qualname__} requires the hdl_toplevel parameter to be specified.\"\n            )\n\n        # TODO: set \"--debug\" if self.verbose\n        # TODO: support \"--always\"\n\n        verilator_cpp = str(\n            cocotb_tools.config.share_dir / \"lib\" / \"verilator\" / \"verilator.cpp\"\n        )\n\n        cmds = []\n        cmds.append(\n            [\n                self.executable,\n                \"-cc\",\n                \"--exe\",\n                \"-Mdir\",\n                str(self.build_dir),\n                \"--top-module\",\n                self.hdl_toplevel,\n                \"--vpi\",\n                \"--public-flat-rw\",\n                \"--prefix\",\n                \"Vtop\",\n                \"-o\",\n                self.hdl_toplevel,\n                \"-LDFLAGS\",\n                f\"-Wl,-rpath,{cocotb_tools.config.libs_dir} -L{cocotb_tools.config.libs_dir} -lcocotbvpi_verilator\",\n            ]\n            + ([\"--trace\"] if self.waves else [])\n            + [arg.value for arg in self._build_args]\n            + (\n                [\"--timescale\", \"{}/{}\".format(*self.timescale)]\n                if self.timescale is not None\n                else []\n            )\n            + self._get_define_options(self.defines)\n            + self._get_include_options(self.includes)\n            + self._get_parameter_options(self.parameters)\n            + [verilator_cpp]\n            + [str(source.value) for source in sources]\n        )\n\n        cmds.append(\n            [\n                \"make\",\n                \"-j\",\n                f\"{_get_max_parallel_build_jobs()}\",\n                \"-C\",\n                str(self.build_dir),\n                \"-f\",\n                \"Vtop.mk\",\n                f\"VM_TRACE={int(self.waves)}\",\n            ]\n        )\n\n        return cmds\n\n    def _test_command(self) -> list[_Command]:\n        if self.pre_cmd is not None:\n            raise RuntimeError(\"pre_cmd is not implemented for Verilator.\")\n\n        out_file = self.build_dir / self.sim_hdl_toplevel\n        return [\n            self._get_sim_cmd_prefix()\n            + [str(out_file)]\n            + ([\"--trace\"] if self.waves or self.gui else [])\n            + self.test_args\n            + self.plusargs\n            + self._get_sim_cmd_suffix(),\n        ]\n\n\nclass Xcelium(Runner):\n    \"\"\"Implementation of :class:`Runner` for Cadence Xcelium.\n\n    .. admonition:: Simulator-specific Usage\n\n       * Does not support the ``waves`` argument to :meth:`.build` (must be set in :meth:`.test` instead).\n       * Does not support the ``pre_cmd`` argument to :meth:`.test`.\n       * Does not support the ``timescale`` argument to :meth:`.test`.\n    \"\"\"\n\n    supported_gpi_interfaces = {\"verilog\": [\"vpi\"], \"vhdl\": [\"vhpi\"]}\n\n    def _simulator_in_path(self) -> None:\n        if shutil.which(\"xrun\") is None:\n            raise SystemExit(\"ERROR: xrun executable not found!\")\n\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        return [f\"-incdir {include}\" for include in includes]\n\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        return [\n            f\"-define {name}={self._as_define_value(value)}\"\n            for name, value in defines.items()\n        ]\n\n    def _as_define_value(self, value: object) -> str:\n        if isinstance(value, int):\n            return str(value)\n        elif isinstance(value, str):\n            for char in value:\n                if ord(char) < 32 or ord(char) >= 255 or char == '\"':\n                    # Control characters are generally not supported.\n                    # Not sure if there's any way to escape quotes.\n                    raise ValueError(\n                        f\"Character {char!r} not supported in define value\"\n                    )\n            return '\"\\\\\"' + value.replace(\"\\\\\", \"\\\\\\\\\") + '\\\\\"\"'\n        else:\n            raise TypeError(\"Can't serialize this type as an SV literal\")\n\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        return [f'-gpg \"{name} => {value}\"' for name, value in parameters.items()]\n\n    def _build_command(self) -> list[_Command]:\n        self.env[\"CDS_AUTO_64BIT\"] = \"all\"\n\n        if self.waves:\n            raise RuntimeError(\n                \"waves is not supported in the build step. Please set it in the test step.\"\n            )\n\n        if self.hdl_toplevel is None:\n            raise ValueError(\"A HDL toplevel is required in all Xcelium compiles.\")\n\n        verbosity_opts = []\n        if self.verbose:\n            verbosity_opts += [\"-messages\"]\n            verbosity_opts += [\"-status\"]\n            verbosity_opts += [\"-gverbose\"]  # print assigned generics/parameters\n\n        else:\n            verbosity_opts += [\"-quiet\"]\n\n        sources = self._sources + self._vhdl_sources + self._verilog_sources\n\n        for source in sources:\n            if source.tag not in (VHDL, Verilog):\n                raise ValueError(f\"Unsupported file type: {source.value}\")\n\n        vhpi_opts = []\n        if any(source.tag is VHDL for source in sources):\n            # Xcelium 23.09.004 fixes cocotb issue #1076 as long as the\n            # following define is set.\n            vhpi_opts.append(\"-NEW_VHPI_PROPAGATE_DELAY\")\n\n        cmds = [\n            [\"xrun\"]\n            + [\"-logfile\"]\n            + [\"xrun_build.log\"]\n            + [\"-elaborate\"]\n            + [\"-xmlibdirname\"]\n            + [f\"{self.build_dir}/xrun_snapshot\"]\n            + [\"-licqueue\"]\n            + ([\"-clean\"] if self.always else [])\n            + verbosity_opts\n            + [\"-access +rwc\"]\n            + vhpi_opts\n            + [f\"-work {self.hdl_library}\"]\n            + (\n                [\"-timescale\", \"{}/{}\".format(*self.timescale)]\n                if self.timescale is not None\n                else []\n            )\n            + [arg.value for arg in self._build_args]\n            + self._get_include_options(self.includes)\n            + self._get_define_options(self.defines)\n            + self._get_parameter_options(self.parameters)\n            + [f\"-top {self.hdl_toplevel}\"]\n            + [str(source_file.value) for source_file in sources]\n        ]\n\n        return cmds\n\n    def _test_command(self) -> list[_Command]:\n        if self.pre_cmd is not None:\n            raise RuntimeError(\"pre_cmd is not implemented for Xcelium.\")\n\n        if self.timescale is not None:\n            raise RuntimeError(\n                \"timescale is not supported in the test step. Please set it in the build step.\"\n            )\n\n        self.env[\"CDS_AUTO_64BIT\"] = \"all\"\n\n        verbosity_opts = []\n        if self.verbose:\n            verbosity_opts += [\"-messages\"]\n            verbosity_opts += [\"-status\"]\n            verbosity_opts += [\"-gverbose\"]  # print assigned generics/parameters\n            verbosity_opts += [\"-pliverbose\"]\n            verbosity_opts += [\"-plidebug\"]  # Enhance the profile output with PLI info\n            verbosity_opts += [\n                \"-plierr_verbose\"\n            ]  # Expand handle info in PLI/VPI/VHPI messages\n\n        else:\n            verbosity_opts += [\"-quiet\"]\n            verbosity_opts += [\"-plinowarn\"]\n\n        tmpdir = f\"implicit_tmpdir_{self.current_test_name}\"\n\n        if self.hdl_toplevel_lang == \"vhdl\":\n            xrun_top = \":\"\n        else:\n            xrun_top = self.sim_hdl_toplevel\n\n        if self.waves:\n            input_tcl = [\n                f'-input \"@database -open cocotb_waves -default\" '\n                f'-input \"@probe -database cocotb_waves -create {xrun_top} -all -depth all\" '\n                f'-input \"@run\" '\n                f'-input \"@exit\" '\n            ]\n        else:\n            input_tcl = [\"-input\", \"@run; exit;\"]\n\n        sources = self._sources + self._vhdl_sources + self._verilog_sources\n\n        vhpi_opts = []\n        if any(source.tag is VHDL for source in sources):\n            # Xcelium 23.09.004 fixes cocotb issue #1076 as long as the\n            # following define is set.\n            vhpi_opts.append(\"-NEW_VHPI_PROPAGATE_DELAY\")\n\n        cmds = [[\"mkdir\", \"-p\", tmpdir]]\n        cmds += [\n            [\n                *self._get_sim_cmd_prefix(),\n                \"xrun\",\n                \"-logfile\",\n                f\"xrun_{self.current_test_name}.log\",\n                \"-xmlibdirname\",\n                f\"{self.build_dir}/xrun_snapshot\",\n                # + [\"-vpicompat 1800v2005\"]  # <1364v1995|1364v2001|1364v2005|1800v2005> Specify the IEEE VPI\n                \"-loadvpisim\",\n                cocotb_tools.config.lib_name_path(\"vpi\", \"xcelium\").as_posix()\n                + \":vlog_startup_routines_bootstrap\",\n                \"-cds_implicit_tmpdir\",\n                tmpdir,\n                \"-licqueue\",\n                *vhpi_opts,\n                *verbosity_opts,\n                \"-R\",\n                *self.test_args,\n                *self.plusargs,\n                \"-gui\" if self.gui else \"\",\n                *input_tcl,\n                *self._get_sim_cmd_suffix(),\n            ]\n        ]\n        self.env[\"GPI_EXTRA\"] = (\n            cocotb_tools.config.lib_name_path(\"vhpi\", \"xcelium\").as_posix()\n            + \":cocotbvhpi_entry_point\"\n        )\n\n        return cmds\n\n\nclass Vcs(Runner):\n    \"\"\"Implementation of :class:`Runner` for Synopsys VCS.\n\n    .. admonition:: Simulator-specific Usage\n\n       * Does not support the ``pre_cmd`` argument to :meth:`.test`.\n       * Does not support VHDL.\n       * Does not support the ``timescale`` argument to :meth:`.build` or :meth:`.test`.\n    \"\"\"\n\n    supported_gpi_interfaces = {\"verilog\": [\"vpi\"]}\n\n    def _simulator_in_path(self) -> None:\n        if shutil.which(\"vcs\") is None:\n            raise SystemExit(\"ERROR: vcs executable not found!\")\n\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        return [f\"+incdir+{include}\" for include in includes]\n\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        return [\n            f\"+define+{name}={_as_sv_literal(value)}\" for name, value in defines.items()\n        ]\n\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        if self.hdl_toplevel is None:\n            raise ValueError(\"A HDL toplevel is required in all VCS compiles.\")\n        return [\n            f\"-pvalue+{self.hdl_toplevel}.{name}={value}\"\n            for name, value in parameters.items()\n        ]\n\n    @property\n    def sim_file(self) -> Path:\n        return self.build_dir / \"simv\"\n\n    @property\n    def _build_opts(self) -> list[str]:\n        opts = [\n            \"-full64\",\n            \"-debug_access+all\",\n            \"+acc+3\",\n            \"-sverilog\",\n            \"-LDFLAGS -Wl,--no-as-needed\",\n        ]\n\n        if self.verbose:\n            opts += [\"-diag all\"]\n        else:\n            opts += [\"-q\"]\n            opts += [\"-suppress=VPI-CT-NS\"]\n\n        return opts\n\n    def _build_command(self) -> list[_Command]:\n        cmds: list[_Command] = []\n        sources = self._sources + self._vhdl_sources + self._verilog_sources\n\n        for source in sources:\n            if source.tag not in (VHDL, Verilog):\n                raise ValueError(f\"Unsupported file type: {source.value}\")\n\n        if outdated(self.sim_file, (source.value for source in sources)) or self.always:\n            cmds = [\n                [\"vcs\"]\n                + self._build_opts\n                + [\"-load\", cocotb_tools.config.lib_name_path(\"vpi\", \"vcs\").as_posix()]\n                + [arg.value for arg in self._build_args]\n                + self._get_include_options(self.includes)\n                + self._get_define_options(self.defines)\n                + self._get_parameter_options(self.parameters)\n                + [\"-top\", f\"{self.hdl_toplevel}\"]\n                + [str(source.value) for source in sources]\n                + [\"-o\", str(self.sim_file)]\n            ]\n        else:\n            self.log.warning(\"Skipping compilation of %s\", self.sim_file)\n\n        return cmds\n\n    def _test_command(self) -> list[_Command]:\n        if self.pre_cmd is not None:\n            raise RuntimeError(\"pre_cmd is not implemented for Vcs.\")\n\n        verbosity_opts = []\n        if self.verbose:\n            verbosity_opts += [\"-diag all\"]\n        else:\n            verbosity_opts += [\"-suppress=ASLR_DETECTED_INFO\"]\n\n        cmds = [\n            [\n                *self._get_sim_cmd_prefix(),\n                str(self.sim_file),\n                *verbosity_opts,\n                *self.test_args,\n                *self.plusargs,\n                *self._get_sim_cmd_suffix(),\n            ]\n        ]\n\n        return cmds\n\n\nclass Dsim(Runner):\n    \"\"\"Implementation of :class:`Runner` for Siemens DSim.\n\n    .. admonition:: Simulator-specific Usage\n\n       * Does not support the ``pre_cmd`` argument to :meth:`.test`.\n    \"\"\"\n\n    supported_gpi_interfaces = {\"verilog\": [\"vpi\"]}\n\n    def _simulator_in_path(self) -> None:\n        if shutil.which(\"dsim\") is None:\n            raise SystemExit(\"ERROR: dsim executable not found!\")\n\n    def _get_include_options(self, includes: Sequence[PathLike]) -> _Command:\n        return [f\"+incdir+{include}\" for include in includes]\n\n    def _get_define_options(self, defines: Mapping[str, object]) -> _Command:\n        return [\n            f\"+define+{name}={_as_sv_literal(value)}\" for name, value in defines.items()\n        ]\n\n    def _get_parameter_options(self, parameters: Mapping[str, object]) -> _Command:\n        return [\n            f\"-defparam {name}={_as_sv_literal(value)}\"\n            for name, value in parameters.items()\n        ]\n\n    @property\n    def sim_file(self) -> Path:\n        return self.build_dir / \"image.so\"\n\n    def _use_external_viewer(self) -> bool:\n        return True\n\n    def _waves_file(self) -> str | None:\n        return \"file.vcd\"\n\n    def _test_command(self) -> list[_Command]:\n        if self.pre_cmd is not None:\n            raise RuntimeError(\"pre_cmd is not implemented for DSim.\")\n\n        plusargs = self.plusargs\n        if self.waves or self.gui:\n            plusargs += [f\"-waves {self._waves_file()}\"]\n\n        if self.timescale:\n            plusargs += [\"-timescale {}/{}\".format(*self.timescale)]\n\n        return [\n            [\n                \"dsim\",\n                \"-work\",\n                str(self.build_dir),\n                \"-pli_lib\",\n                cocotb_tools.config.lib_name_path(\"vpi\", \"dsim\").as_posix(),\n                \"+acc+rwcbfsWF\",\n                \"-image\",\n                \"image\",\n                *self.test_args,\n                *plusargs,\n            ]\n        ]\n\n    def _build_command(self) -> list[_Command]:\n        sources = self._sources + self._verilog_sources\n\n        for source in sources:\n            if source.tag is not Verilog:\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports Verilog. {str(source.value)!r} cannot be compiled.\"\n                )\n\n        for arg in self._build_args:\n            if arg.tag not in (Verilog, None):\n                raise ValueError(\n                    f\"{type(self).__qualname__} only supports Verilog. build_args {arg!r} cannot be applied.\"\n                )\n\n        cmds: list[_Command] = []\n        if outdated(self.sim_file, (source.value for source in sources)) or self.always:\n            cmds = [\n                [\n                    *self._get_sim_cmd_prefix(),\n                    \"dsim\",\n                    \"-work\",\n                    str(self.build_dir),\n                    \"-pli_lib\",\n                    cocotb_tools.config.lib_name_path(\"vpi\", \"dsim\").as_posix(),\n                    \"+acc+rwcbfsWF\",\n                    \"-genimage\",\n                    \"image\",\n                ]\n                + self._get_define_options(self.defines)\n                + self._get_include_options(self.includes)\n                + self._get_parameter_options(self.parameters)\n                + [arg.value for arg in self._build_args]\n                + [str(source_file.value) for source_file in sources]\n                + self._get_sim_cmd_suffix(),\n            ]\n\n        else:\n            self.log.warning(\"Skipping compilation of %s\", self.sim_file)\n\n        return cmds\n\n\nSUPPORTED_RUNNERS: dict[str, type[Runner]] = {\n    \"icarus\": Icarus,\n    \"questa\": Questa,\n    \"ghdl\": Ghdl,\n    \"riviera\": Riviera,\n    \"activehdl\": ActiveHDL,\n    \"verilator\": Verilator,\n    \"xcelium\": Xcelium,\n    \"nvc\": Nvc,\n    \"vcs\": Vcs,\n    \"dsim\": Dsim,\n}\n\"\"\"\nDictionary mapping of simulator names to corresponding Python runners.\nThe keys of this dictionary make up valid ``simulator_name`` strings to pass to :func:`get_runner()`.\n\nExternal libraries may register additional implementations of Python runners\nby adding keys to this dictionary.\n\"\"\"\n\n\ndef get_runner(simulator_name: str) -> Runner:\n    \"\"\"Return an instance of a runner for *simulator_name*.\n\n    Args:\n        simulator_name: Name of simulator to get runner for.\n\n    Raises:\n        ValueError: If *simulator_name* is not one of the supported simulators or an alias of one.\n    \"\"\"\n\n    try:\n        return SUPPORTED_RUNNERS[simulator_name]()\n    except KeyError:\n        raise ValueError(\n            f\"Simulator {simulator_name!r} is not in supported list: {', '.join(SUPPORTED_RUNNERS)}\"\n        ) from None\n"
  },
  {
    "path": "src/cocotb_tools/sim_versions.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# type: ignore  # distutils is untyped, so there's little reason to check this file\n\n\"\"\"\nClasses to compare simulation versions.\n\nThese are for cocotb-internal use only.\n\n.. warning::\n    These classes silently allow comparing versions of different simulators.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport re\nimport sys\n\nfrom cocotb_tools._vendor.distutils_version import LooseVersion\n\nif sys.version_info >= (3, 11):\n    from typing import Self\n\n\nclass ActivehdlVersion(LooseVersion):\n    \"\"\"Version numbering class for Aldec Active-HDL.\n\n    NOTE: unsupported versions exist, e.g.\n    ActivehdlVersion(\"10.5a.12.6914\") > ActivehdlVersion(\"10.5.216.6767\")\n    \"\"\"\n\n\nclass CvcVersion(LooseVersion):\n    \"\"\"Version numbering class for Tachyon DA CVC.\n\n    Example:\n        >>> CvcVersion(\n        ...     \"OSS_CVC_7.00b-x86_64-rhel6x of 07/07/14 (Linux-elf)\"\n        ... ) > CvcVersion(\"OSS_CVC_7.00a-x86_64-rhel6x of 07/07/14 (Linux-elf)\")\n        True\n    \"\"\"\n\n\nclass GhdlVersion(LooseVersion):\n    \"\"\"Version numbering class for GHDL.\"\"\"\n\n\nclass IcarusVersion(LooseVersion):\n    \"\"\"Version numbering class for Icarus Verilog.\n\n    Example:\n        >>> IcarusVersion(\"11.0 (devel)\") > IcarusVersion(\"10.3 (stable)\")\n        True\n        >>> IcarusVersion(\"10.3 (stable)\") <= IcarusVersion(\"10.3 (stable)\")\n        True\n    \"\"\"\n\n    @classmethod\n    def from_commandline(cls, cmdline: str) -> Self:\n        firstline = cmdline.split(\"\\n\", 1)[0]\n        m = re.match(r\"^Icarus Verilog version (\\d+\\.\\d+)\", firstline)\n        if not m:\n            raise ValueError(\n                f\"Unable to parse Icarus Verilog version from: {firstline}\"\n            )\n        version = m.group(1)\n        return cls(version)\n\n\nclass ModelsimVersion(LooseVersion):\n    \"\"\"Version numbering class for Mentor ModelSim.\"\"\"\n\n\nclass QuestaVersion(LooseVersion):\n    \"\"\"Version numbering class for Mentor Questa.\n\n    Example:\n        >>> QuestaVersion(\"10.7c 2018.08\") > QuestaVersion(\"10.7b 2018.06\")\n        True\n        >>> QuestaVersion(\"2020.1 2020.01\") > QuestaVersion(\"10.7c 2018.08\")\n        True\n        >>> QuestaVersion(\"2020.1 2020.01\") == QuestaVersion(\"2020.1\")\n        True\n        >>> QuestaVersion(\"2023.1_2 2023.03\") > QuestaVersion(\"2023.1_1\")\n        True\n    \"\"\"\n\n    def parse(self, vstring):\n        # A Questa version string, as returned by the simulator, consists of two\n        # space-separated parts. The first part is the actual version number,\n        # the second part seems to be the year and month of the initial release.\n        # We only need the first part, which is also used in public\n        # communication by Siemens.\n        try:\n            first_component = vstring.split(\" \", 1)[0]\n        except IndexError:\n            first_component = vstring\n\n        super().parse(first_component)\n\n\nclass RivieraVersion(LooseVersion):\n    \"\"\"Version numbering class for Aldec Riviera-PRO.\n\n    Example:\n        >>> RivieraVersion(\"2019.10.138.7537\") == RivieraVersion(\"2019.10.138.7537\")\n        True\n    \"\"\"\n\n\nclass VcsVersion(LooseVersion):\n    \"\"\"Version numbering class for Synopsys VCS.\n\n    Example:\n        >>> VcsVersion(\"Q-2020.03-1_Full64\") > VcsVersion(\"K-2015.09_Full64\")\n        True\n    \"\"\"\n\n\nclass VerilatorVersion(LooseVersion):\n    \"\"\"Version numbering class for Verilator.\n\n    Example:\n        >>> VerilatorVersion(\"4.032 2020-04-04\") > VerilatorVersion(\"4.031 devel\")\n        True\n    \"\"\"\n\n    @classmethod\n    def from_commandline(cls, cmdline: str) -> Self:\n        \"\"\"Parse the output of ``verilator --version``.\n\n        Example:\n            >>> cmdline = \"Verilator 5.041 devel rev v5.040-1-g4eb030717\"\n            >>> VerilatorVersion.from_commandline(cmdline) >= VerilatorVersion(\"5.040\")\n            True\n\n        Args:\n            cmdline: The command-line output of a call to ``verilator --version``.\n\n        Returns:\n            An instance of :class:`VerilatorVersion`.\n\n        Raises:\n            AssertionError: If *cmdline* does not appear to be generated by Verilator.\n        \"\"\"\n        firstline = cmdline.split(\"\\n\", 1)[0]\n        sim, version, *version_extra = firstline.strip().split(\" \")\n        assert sim == \"Verilator\"\n        return cls(version)\n\n\nclass XceliumVersion(LooseVersion):\n    \"\"\"Version numbering class for Cadence Xcelium.\n\n    Example:\n        >>> XceliumVersion(\"20.06-g183\") > XceliumVersion(\"20.03-s002\")\n        True\n        >>> XceliumVersion(\"20.07-e501\") > XceliumVersion(\"20.06-g183\")\n        True\n    \"\"\"\n\n\nclass IusVersion(XceliumVersion):  # inherit everything from Xcelium\n    \"\"\"Version numbering class for Cadence IUS.\n\n    Example:\n        >>> IusVersion(\"15.20-s050\") > IusVersion(\"15.20-s049\")\n        True\n    \"\"\"\n\n\nclass NvcVersion(LooseVersion):\n    \"\"\"Version numbering class for NVC.\"\"\"\n\n    @classmethod\n    def from_commandline(cls, cmdline: str) -> Self:\n        firstline = cmdline.split(\"\\n\", 1)[0]\n        sim, version, *version_extra = firstline.strip().split(\" \")\n        assert sim == \"nvc\"\n        return cls(version)\n"
  },
  {
    "path": "src/pygpi/__init__.py",
    "content": ""
  },
  {
    "path": "src/pygpi/entry.py",
    "content": "from __future__ import annotations\n\nimport importlib\nimport operator\nfrom typing import Callable\n\nfrom cocotb_tools import _env\n\n\ndef load_entry() -> None:\n    \"\"\"Gather entry point information by parsing :envvar:`PYGPI_USERS`.\"\"\"\n\n    entry_points_str: list[str] = _env.as_list(\n        \"PYGPI_USERS\",\n        (\n            \"cocotb_tools._coverage:start_cocotb_library_coverage\",\n            \"cocotb.logging:_configure\",\n            \"cocotb._init:init_package_from_simulation\",\n            \"cocotb.regression:_run_regression\",\n        ),\n    )\n\n    # Parse the entry point string of the form \"module:func,module:func,...\".\n    # Any failure prevents any entry points from being loaded.\n    entry_points: list[tuple[str, str]] = []\n    try:\n        for entry_point_str in entry_points_str:\n            entry_module_str, entry_func_str = entry_point_str.split(\":\")\n            # TODO maybe some basic validation of the module and function names.\n            # WITHOUT IMPORTING THEM.\n            entry_points.append((entry_module_str, entry_func_str))\n    except Exception as e:\n        raise RuntimeError(f\"Failure to parse PYGPI_USERS {entry_point_str!r}\") from e\n\n    # Run all entry points.\n    # Expect failure to stop the loading of any additional entry points.\n    for entry_module_str, entry_func_str in entry_points:\n        entry_module = importlib.import_module(entry_module_str)\n        entry_func: Callable[[], object] = operator.attrgetter(entry_func_str)(\n            entry_module\n        )\n        entry_func()\n"
  },
  {
    "path": "src/pygpi/py.typed",
    "content": ""
  },
  {
    "path": "src/pyproject.toml",
    "content": "[tool.ruff]\nextend = \"../pyproject.toml\"\n\n[tool.ruff.lint]\nextend-select = [\n    \"PTH\",  # flake8-use-pathlib\n]\nextend-ignore = [\n    \"PTH123\",  # open() should be replaced by Path.open() (preference)\n]\n"
  },
  {
    "path": "tests/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nREGRESSIONS :=  $(shell ls test_cases/)\n\nall: $(REGRESSIONS)\n\n.PHONY: $(REGRESSIONS)\n$(REGRESSIONS):\n\t@echo Running regression suite $@\n\t@cd test_cases/$@ && $(MAKE); ret=$$?; if [ $$ret -ne 0 ]; then echo \"::error ::Failed regression suite $@\"; fi; exit $$ret;\n\n.PHONY: clean\nclean:\n\t@for regression in $(REGRESSIONS); do \\\n\t\t( cd test_cases/$$regression && make clean ); \\\n\tdone\n"
  },
  {
    "path": "tests/benchmarks/test_matrix_multiplier.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport sys\nfrom pathlib import Path\n\nfrom cocotb_tools.runner import get_runner\n\nproj_path = (\n    Path(__file__).resolve().parent.parent.parent / \"examples\" / \"matrix_multiplier\"\n)\n\n\ndef build_and_run_matrix_multiplier(benchmark, sim):\n    hdl_toplevel_lang = \"verilog\"\n    build_args = []\n    test_args = []\n\n    if sim == \"nvc\":\n        build_args = [\"--std=08\"]\n        hdl_toplevel_lang = \"vhdl\"\n\n    sys.path.append(str(proj_path / \"tests\"))\n\n    if hdl_toplevel_lang == \"verilog\":\n        sources = [proj_path / \"hdl\" / \"matrix_multiplier.sv\"]\n    else:\n        sources = [\n            proj_path / \"hdl\" / \"matrix_multiplier_pkg.vhd\",\n            proj_path / \"hdl\" / \"matrix_multiplier.vhd\",\n        ]\n\n    runner = get_runner(sim)\n\n    runner.build(\n        hdl_toplevel=\"matrix_multiplier\",\n        sources=sources,\n        build_args=build_args,\n        build_dir=\"sim_build/matrix_multiplier\",\n    )\n\n    @benchmark\n    def run_test():\n        runner.test(\n            hdl_toplevel=\"matrix_multiplier\",\n            hdl_toplevel_lang=hdl_toplevel_lang,\n            test_module=\"matrix_multiplier_tests\",\n            test_args=test_args,\n            seed=123456789,\n        )\n\n\ndef test_matrix_multiplier_icarus(benchmark):\n    build_and_run_matrix_multiplier(benchmark, \"icarus\")\n\n\ndef test_matrix_multiplier_nvc(benchmark):\n    build_and_run_matrix_multiplier(benchmark, \"nvc\")\n"
  },
  {
    "path": "tests/benchmarks/test_parameterize_perf/parametrize_perf_top.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\nmodule parametrize_perf_top;\nendmodule\n"
  },
  {
    "path": "tests/benchmarks/test_parameterize_perf/parametrize_performance_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\n@cocotb.parametrize(a=range(50), b=range(50), c=range(50))\nasync def parametrize(dut, a, b, c):\n    pass\n"
  },
  {
    "path": "tests/benchmarks/test_parameterize_perf/test_parameterize_perf.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport sys\nfrom pathlib import Path\n\nfrom cocotb_tools.runner import get_runner\n\nTHIS_DIR = Path(__file__).resolve().parent\n\n\ndef test_parameterize_perf_icarus(benchmark) -> None:\n    if str(THIS_DIR) not in sys.path:\n        sys.path.append(str(THIS_DIR))\n\n    runner = get_runner(\"icarus\")\n\n    runner.build(\n        hdl_toplevel=\"parametrize_perf_top\",\n        sources=[THIS_DIR / \"parametrize_perf_top.sv\"],\n        build_dir=\"sim_build\",\n    )\n\n    @benchmark\n    def run_test() -> None:\n        runner.test(\n            hdl_toplevel=\"parametrize_perf_top\",\n            test_module=\"parametrize_performance_tests\",\n            test_filter=\"parametrize/a=49/b=49/c=49\",\n        )\n"
  },
  {
    "path": "tests/designs/array_module/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2016 Potential Ventures Ltd\n# Copyright (c) 2016 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nCOCOTB_TOPLEVEL := array_module\n\nPWD=$(shell pwd)\n\nCOCOTB?=$(PWD)/../../..\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    VERILOG_SOURCES = $(COCOTB)/tests/designs/array_module/array_module.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    ifneq ($(filter $(SIM),ius xcelium),)\n        COMPILE_ARGS += -v93\n    endif\n    VHDL_SOURCES =  $(COCOTB)/tests/designs/array_module/array_module_pack.vhd\n    VHDL_SOURCES += $(COCOTB)/tests/designs/array_module/array_module.vhd\nelse\n    $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "tests/designs/array_module/array_module.sv",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2016 Potential Ventures Ltd\n// Copyright (c) 2016 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`timescale 1 ps / 1 ps\n\ntypedef struct {\n    logic a;\n    logic [7:0] b[0:2];\n} rec_type;\n\nmodule array_module (\n    input                                       clk,\n\n    input  integer                              select_in,\n\n    input          [7:0]                        port_desc_in,\n    input          [0:7]                        port_asc_in,\n    input          [1:8]                        port_ofst_in,\n\n    output         [7:0]                        port_desc_out,\n    output         [0:7]                        port_asc_out,\n    output         [1:8]                        port_ofst_out,\n\n    output logic                                port_logic_out,\n    output logic   [7:0]                        port_logic_vec_out,\n    //output bit                                  port_bool_out,\n    //output integer                              port_int_out,\n    //output real                                 port_real_out,\n    //output byte                                 port_char_out,\n    //output string                               port_str_out,\n    output rec_type                             port_rec_out,\n    output rec_type                             port_cmplx_out[0:1]\n);\n\nparameter logic          param_logic       = 1'b1;\nparameter logic [7:0]    param_logic_vec   = 8'hDA;\n//parameter bit            param_bool        = 1'b1;\n//parameter integer        param_int         = 6;\n//parameter real           param_real        = 3.14;\n//parameter byte           param_char        = \"p\";\n//parameter string         param_str         = \"ARRAYMOD\";\n//parameter rec_type       param_rec         = '{a:'0, b:'{8'h00,8'h00,8'h00}}};\n//parameter rec_type       param_cmplx [0:1] = '{'{a:'0, b:'{8'h00,8'h00,8'h00}}, '{a:'0, b:'{8'h00,8'h00,8'h00}}};\n\nlocalparam logic          const_logic       = 1'b0;\nlocalparam logic [7:0]    const_logic_vec   = 8'h3D;\n//localparam bit            const_bool        = 1'b0;\n//localparam integer        const_int         = 12;\n//localparam real           const_real        = 6.28;\n//localparam byte           const_char        = \"c\";\n//localparam string         const_str         = \"MODARRAY\";\n//localparam rec_type       const_rec         = '{a:'1, b:'{8'hFF,8'hFF,8'hFF}}};\n//localparam rec_type       const_cmplx [1:2] = '{'{a:'1, b:'{8'hFF,8'hFF,8'hFF}}, '{a:'1, b:'{8'hFF,8'hFF,8'hFF}}};\n\nwire [0:3]       sig_t1;\nwire [7:0]       sig_t2[7:4];\nwire [7:0]       sig_t3a[1:4];\nwire [7:0]       sig_t3b[3:0];\nwire [7:0]       sig_t4[0:3][7:4];\nwire [7:0]       sig_t5[0:2][0:3];\nwire [7:0]       sig_t6[0:1][2:4];\n\nwire       [16:23]  sig_asc;\nwire       [23:16]  sig_desc;\nwire logic          sig_logic;\nwire logic [7:0]    sig_logic_vec;\n//     bit            sig_bool;\n//     integer        sig_int;\n//     real           sig_real;\n//     byte           sig_char;\n//     string         sig_str;\n     rec_type       sig_rec;\n     rec_type       sig_cmplx [0:1];\n\ntypedef logic [7:0] uint16_t;\n\nuint16_t sig_t7 [3:0][3:0];\nuint16_t [3:0][3:0] sig_t8;\n\nassign port_ofst_out = port_ofst_in;\n\n//assign port_rec_out       = (select_in == 1) ? const_rec       : (select_in == 2) ? sig_rec       : param_rec;\n//assign port_cmplx_out     = (select_in == 1) ? const_cmplx     : (select_in == 2) ? sig_cmplx     : param_cmplx;\n\nalways @(posedge clk) begin\n    if (select_in == 1) begin\n        port_logic_out         = const_logic;\n        port_logic_vec_out     = const_logic_vec;\n//        port_bool_out          = const_bool;\n//        port_int_out           = const_int;\n//        port_real_out          = const_real;\n//        port_char_out          = const_char;\n//        port_str_out           = const_str;\n        port_rec_out.a         = sig_rec.a;\n        port_rec_out.b[0]      = sig_rec.b[0];\n        port_rec_out.b[1]      = sig_rec.b[1];\n        port_rec_out.b[2]      = sig_rec.b[2];\n        port_cmplx_out[0].a    = sig_cmplx[0].a;\n        port_cmplx_out[0].b[0] = sig_cmplx[0].b[0];\n        port_cmplx_out[0].b[1] = sig_cmplx[0].b[1];\n        port_cmplx_out[0].b[2] = sig_cmplx[0].b[2];\n        port_cmplx_out[1].a    = sig_cmplx[1].a;\n        port_cmplx_out[1].b[0] = sig_cmplx[1].b[0];\n        port_cmplx_out[1].b[1] = sig_cmplx[1].b[1];\n        port_cmplx_out[1].b[2] = sig_cmplx[1].b[2];\n    end else begin\n        if (select_in == 2) begin\n            port_logic_out         = sig_logic;\n            port_logic_vec_out     = sig_logic_vec;\n//            port_bool_out          = sig_bool;\n//            port_int_out           = sig_int;\n//            port_real_out          = sig_real;\n//            port_char_out          = sig_char;\n//            port_str_out           = sig_str;\n            port_rec_out.a         = sig_rec.a;\n            port_rec_out.b[0]      = sig_rec.b[0];\n            port_rec_out.b[1]      = sig_rec.b[1];\n            port_rec_out.b[2]      = sig_rec.b[2];\n            port_cmplx_out[0].a    = sig_cmplx[0].a;\n            port_cmplx_out[0].b[0] = sig_cmplx[0].b[0];\n            port_cmplx_out[0].b[1] = sig_cmplx[0].b[1];\n            port_cmplx_out[0].b[2] = sig_cmplx[0].b[2];\n            port_cmplx_out[1].a    = sig_cmplx[1].a;\n            port_cmplx_out[1].b[0] = sig_cmplx[1].b[0];\n            port_cmplx_out[1].b[1] = sig_cmplx[1].b[1];\n            port_cmplx_out[1].b[2] = sig_cmplx[1].b[2];\n        end else begin\n            port_logic_out         = param_logic;\n            port_logic_vec_out     = param_logic_vec;\n//            port_bool_out          = param_bool;\n//            port_int_out           = param_int;\n//            port_real_out          = param_real;\n//            port_char_out          = param_char;\n//            port_str_out           = param_str;\n            port_rec_out.a         = sig_rec.a;\n            port_rec_out.b[0]      = sig_rec.b[0];\n            port_rec_out.b[1]      = sig_rec.b[1];\n            port_rec_out.b[2]      = sig_rec.b[2];\n            port_cmplx_out[0].a    = sig_cmplx[0].a;\n            port_cmplx_out[0].b[0] = sig_cmplx[0].b[0];\n            port_cmplx_out[0].b[1] = sig_cmplx[0].b[1];\n            port_cmplx_out[0].b[2] = sig_cmplx[0].b[2];\n            port_cmplx_out[1].a    = sig_cmplx[1].a;\n            port_cmplx_out[1].b[0] = sig_cmplx[1].b[0];\n            port_cmplx_out[1].b[1] = sig_cmplx[1].b[1];\n            port_cmplx_out[1].b[2] = sig_cmplx[1].b[2];\n        end\n    end\nend\n\ngenvar idx1;\ngenerate\nfor (idx1 = 16; idx1 <= 23; idx1=idx1+1) begin:asc_gen\n    localparam OFFSET = 16-0;\n    reg sig;\n    always @(posedge clk) begin\n        sig <= port_asc_in[idx1-OFFSET];\n    end\n    assign sig_asc[idx1] = sig;\n    assign port_asc_out[idx1-OFFSET] = sig_asc[idx1];\nend\nendgenerate\n\ngenvar idx2;\ngenerate\nfor (idx2 = 7; idx2 >= 0; idx2=idx2-1) begin:desc_gen\n    localparam OFFSET = 23-7;\n    reg sig;\n    always @(posedge clk) begin\n        sig <= port_desc_in[idx2];\n    end\n    assign sig_desc[idx2+OFFSET] = sig;\n    assign port_desc_out[idx2] = sig_desc[idx2+OFFSET];\nend\nendgenerate\n\nendmodule\n"
  },
  {
    "path": "tests/designs/array_module/array_module.vhd",
    "content": "-- Copyright cocotb contributors\n-- Copyright (c) 2016 Potential Ventures Ltd\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nlibrary ieee;\n\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nuse work.array_module_pack.all;\n\nentity array_module is\n    generic (\n        param_logic                    :       std_logic                     := '1';\n        param_logic_vec                :       std_logic_vector(7 downto 0)  := X\"DA\";\n        param_bool                     :       boolean                       := TRUE;\n        param_int                      :       integer                       := 6;\n        param_real                     :       real                          := 3.14;\n        param_char                     :       character                     := 'p';\n        param_str                      :       string(1 to 8)                := \"ARRAYMOD\";\n        param_rec                      :       rec_type                      := REC_TYPE_ZERO;\n        param_cmplx                    :       rec_array(0 to 1)             := (others=>REC_TYPE_ZERO)\n    );\n    port (\n        clk                            : in    std_logic;\n\n        select_in                      : in    integer;\n\n        port_desc_in                   : in    std_logic_vector(7 downto 0);\n        port_asc_in                    : in    std_logic_vector(0 to 7);\n        port_ofst_in                   : in    std_logic_vector(1 to 8);\n\n        port_desc_out                  :   out std_logic_vector(7 downto 0);\n        port_asc_out                   :   out std_logic_vector(0 to 7);\n        port_ofst_out                  :   out std_logic_vector(1 to 8);\n\n        port_logic_out                 :   out std_logic;\n        port_logic_vec_out             :   out std_logic_vector(7 downto 0);\n        port_bool_out                  :   out boolean;\n        port_int_out                   :   out integer;\n        port_real_out                  :   out real;\n        port_char_out                  :   out character;\n        port_str_out                   :   out string(1 to 8);\n        port_rec_out                   :   out rec_type;\n        port_cmplx_out                 :   out rec_array(0 to 1)\n    );\nend;\n\narchitecture impl of array_module is\n    constant const_logic               : std_logic                     := '0';\n    constant const_logic_vec           : std_logic_vector(7 downto 0)  := X\"3D\";\n    constant const_bool                : boolean                       := FALSE;\n    constant const_int                 : integer                       := 12;\n    constant const_real                : real                          := 6.28;\n    constant const_char                : character                     := 'c';\n    constant const_str                 : string(1 to 8)                := \"MODARRAY\";\n    constant const_rec                 : rec_type                      := REC_TYPE_ONE;\n    constant const_cmplx               : rec_array(1 to 2)             := (others=>REC_TYPE_ONE);\n\n    signal   sig_desc      : std_logic_vector(23 downto 16);\n    signal   sig_asc       : std_logic_vector(16 to 23);\n\n    signal   \\ext_id\\      : std_logic;\n    signal   \\!\\           : std_logic;\n\n    signal   sig_t1        : t1;\n    signal   sig_t2        : t2;\n    signal   sig_t3a       : t3(1 to 4);\n    signal   sig_t3b       : t3(3 downto 0);\n    signal   sig_t4        : t4;\n    signal   sig_t5        : t5;\n    signal   sig_t6        : t6(0 to 1, 2 to 4);\n\n    signal   sig_logic     : std_logic;\n    signal   sig_logic_vec : std_logic_vector(7 downto 0);\n    signal   sig_bool      : boolean;\n    signal   sig_int       : integer;\n    signal   sig_real      : real;\n    signal   sig_char      : character;\n    signal   sig_str       : string(1 to 8);\n    signal   sig_rec       : rec_type;\n    signal   sig_cmplx     : rec_array(0 to 1);\nbegin\n    port_ofst_out <= port_ofst_in;\n\n    sig_proc : process (clk)\n    begin\n        if (rising_edge(clk)) then\n            if (select_in = 1) then\n                port_logic_out     <= const_logic;\n                port_logic_vec_out <= const_logic_vec;\n                port_bool_out      <= const_bool;\n                port_int_out       <= const_int;\n                port_real_out      <= const_real;\n                port_char_out      <= const_char;\n                port_str_out       <= const_str;\n                port_rec_out       <= const_rec;\n                port_cmplx_out     <= const_cmplx;\n            elsif (select_in = 2) then\n                port_logic_out     <= sig_logic;\n                port_logic_vec_out <= sig_logic_vec;\n                port_bool_out      <= sig_bool;\n                port_int_out       <= sig_int;\n                port_real_out      <= sig_real;\n                port_char_out      <= sig_char;\n                port_str_out       <= sig_str;\n                port_rec_out       <= sig_rec;\n                port_cmplx_out     <= sig_cmplx;\n            else\n                port_logic_out     <= param_logic;\n                port_logic_vec_out <= param_logic_vec;\n                port_bool_out      <= param_bool;\n                port_int_out       <= param_int;\n                port_real_out      <= param_real;\n                port_char_out      <= param_char;\n                port_str_out       <= param_str;\n                port_rec_out       <= param_rec;\n                port_cmplx_out     <= param_cmplx;\n            end if;\n        end if;\n    end process sig_proc;\n\n    asc_gen : for idx1 in sig_asc'range generate\n        constant OFFSET : natural   := sig_asc'left - port_asc_in'left;\n        signal   sig    : std_logic;\n    begin\n        sig                       <= port_asc_in(idx1-OFFSET) when rising_edge(clk);\n        sig_asc(idx1)             <= sig;\n        port_asc_out(idx1-OFFSET) <= sig_asc(idx1);\n    end generate asc_gen;\n\n    desc_gen : for idx2 in port_desc_in'range generate\n        constant OFFSET : natural := sig_desc'left - port_desc_in'left;\n        signal   sig    : std_logic;\n    begin\n        sig                   <= port_desc_in(idx2) when rising_edge(clk);\n        sig_desc(idx2+OFFSET) <= sig;\n        port_desc_out(idx2)   <= sig_desc(idx2+OFFSET);\n    end generate desc_gen;\nend architecture;\n"
  },
  {
    "path": "tests/designs/array_module/array_module_pack.vhd",
    "content": "-- Copyright cocotb contributors\n-- Copyright (c) 2016 Potential Ventures Ltd\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nlibrary ieee;\n\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\npackage array_module_pack is\n    type t1 is array (0 to 3) of std_logic;\n    type t2 is array (7 downto 4) of std_logic_vector(7 downto 0);\n    type t3 is array (natural range <>) of std_logic_vector(7 downto 0);\n    type t4 is array (0 to 3) of t2;\n    type t5 is array (0 to 2, 0 to 3) of std_logic_vector(7 downto 0);\n    type t6 is array (natural range <>, natural range <>) of std_logic_vector(7 downto 0);\n\n    type rec_type is record\n        a : std_logic;\n        b : t3(0 to 2);\n    end record rec_type;\n    type     rec_array is array (natural range <>) of rec_type;\n    constant REC_TYPE_ZERO  : rec_type  := ('0', (others=>(others=>'0')));\n    constant REC_TYPE_ONE   : rec_type  := ('1', (others=>(others=>'1')));\n\nend package array_module_pack;\n\npackage body array_module_pack is\nend package body array_module_pack;\n"
  },
  {
    "path": "tests/designs/basic_hierarchy_module/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nifneq ($(TOPLEVEL_LANG),verilog)\n\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being verilog\"\nclean::\n\nelse\n\nCOCOTB_TOPLEVEL := basic_hierarchy_module\n\nPWD=$(shell pwd)\n\nCOCOTB?=$(PWD)/../../..\n\nVERILOG_SOURCES = $(COCOTB)/tests/designs/basic_hierarchy_module/basic_hierarchy_module.v\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/designs/basic_hierarchy_module/basic_hierarchy_module.v",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`timescale 1 ps / 1 ps\n\nmodule module_a (\n    input clk,\n    input [31:0] data_in,\n    output reg [31:0] data_out);\n\nalways @ (posedge clk)\nbegin\n    data_out <= data_in + 2;\nend\n\nendmodule\n\nmodule module_b (\n    input clk,\n    input [31:0] data_in,\n    output reg [31:0] data_out\n);\n\nalways @ (posedge clk)\nbegin\n    data_out <= data_in + 5;\nend\n\nendmodule\n\nmodule basic_hierarchy_module (\n    input clk,\n    input reset\n);\n\nreg [31:0] counter;\n\nalways @ (posedge clk or negedge reset)\nbegin\n    if (~reset) begin\n        counter <= 0;\n    end else begin\n        counter <= counter + 1;\n    end\nend\n\nwire [31:0] counter_plus_two;\nwire [31:0] counter_plus_five;\n\nmodule_a i_module_a (\n    .clk        (clk),\n    .data_in    (counter),\n    .data_out   (counter_plus_two)\n);\n\nmodule_b i_module_b (\n    .clk        (clk),\n    .data_in    (counter),\n    .data_out   (counter_plus_five)\n);\n\nendmodule\n"
  },
  {
    "path": "tests/designs/multi_dimension_array/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2016 Potential Ventures Ltd\n# Copyright (c) 2016 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nCOCOTB_TOPLEVEL := cocotb_array\n\nifneq ($(TOPLEVEL_LANG),verilog)\n\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being verilog\"\nclean::\n\nelse\n\nPWD=$(shell pwd)\n\nCOCOTB?=$(PWD)/../../..\n\nVERILOG_SOURCES = $(COCOTB)/tests/designs/multi_dimension_array/cocotb_array_pkg.sv \\\n                  $(COCOTB)/tests/designs/multi_dimension_array/cocotb_array.sv\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/designs/multi_dimension_array/cocotb_array.sv",
    "content": "import cocotb_array_pkg::*;\n\nmodule cocotb_array (\n\n  //INPUTS\n\n  //Single dimensions\n  input     logic               [2:0]               in_vect_packed                                      ,\n  input     logic                                   in_vect_unpacked[2:0]                               ,\n  input     test_array_entry_t                      in_arr                                              ,\n\n  //2 dimensions\n  input     logic               [2:0][2:0]          in_2d_vect_packed_packed                            ,\n  input     logic               [2:0]               in_2d_vect_packed_unpacked[2:0]                     ,\n  input     logic                                   in_2d_vect_unpacked_unpacked[2:0][2:0]              ,\n\n  input     test_array_entry_t  [2:0]               in_arr_packed                                       ,\n  input     test_array_entry_t                      in_arr_unpacked[2:0]                                ,\n  input     test_2d_array_t                         in_2d_arr                                           ,\n\n  //3 dimensions\n  input     logic               [2:0][2:0][2:0]     in_vect_packed_packed_packed                        ,\n  input     logic               [2:0][2:0]          in_vect_packed_packed_unpacked[2:0]                 ,\n  input     logic               [2:0]               in_vect_packed_unpacked_unpacked[2:0][2:0]          ,\n  input     logic                                   in_vect_unpacked_unpacked_unpacked[2:0][2:0][2:0]   ,\n\n  input     test_array_entry_t  [2:0][2:0]          in_arr_packed_packed                                ,\n  input     test_array_entry_t  [2:0]               in_arr_packed_unpacked[2:0]                         ,\n  input     test_array_entry_t                      in_arr_unpacked_unpacked[2:0][2:0]                  ,\n\n  input     test_2d_array_t     [2:0]               in_2d_arr_packed                                    ,\n  input     test_2d_array_t                         in_2d_arr_unpacked[2:0]                             ,\n\n  input     test_3d_array_t                         in_3d_arr                                           ,\n\n  //Struct single dimensions\n  input     struct_packed_t                         in_struct_packed                                    ,\n  input     struct_packed_t     [2:0]               in_struct_packed_array_packed                       ,\n  input     struct_packed_t                         in_struct_packed_array_unpacked[2:0]                ,\n\n  //Struct 2 dimensions\n  input     struct_packed_t     [2:0][2:0]          in_struct_packed_arr_packed_packed                  ,\n  input     struct_packed_t     [2:0]               in_struct_packed_arr_packed_unpacked[2:0]           ,\n  input     struct_packed_t                         in_struct_packed_arr_unpacked_unpacked[2:0][2:0]    ,\n\n\n  //OUTPUTS\n  //Single dimensions\n  output    logic               [2:0]               out_vect_packed                                     ,\n  output    logic                                   out_vect_unpacked[2:0]                              ,\n  output    test_array_entry_t                      out_arr                                             ,\n\n  //2 dimensions\n  output    logic               [2:0][2:0]          out_2d_vect_packed_packed                           ,\n  output    logic               [2:0]               out_2d_vect_packed_unpacked[2:0]                    ,\n  output    logic                                   out_2d_vect_unpacked_unpacked[2:0][2:0]             ,\n\n  output    test_array_entry_t  [2:0]               out_arr_packed                                      ,\n  output    test_array_entry_t                      out_arr_unpacked[2:0]                               ,\n  output    test_2d_array_t                         out_2d_arr                                          ,\n\n  //3 dimensions\n  output    logic               [2:0][2:0][2:0]     out_vect_packed_packed_packed                       ,\n  output    logic               [2:0][2:0]          out_vect_packed_packed_unpacked[2:0]                ,\n  output    logic               [2:0]               out_vect_packed_unpacked_unpacked[2:0][2:0]         ,\n  output    logic                                   out_vect_unpacked_unpacked_unpacked[2:0][2:0][2:0]  ,\n\n  output    test_array_entry_t  [2:0][2:0]          out_arr_packed_packed                               ,\n  output    test_array_entry_t  [2:0]               out_arr_packed_unpacked[2:0]                        ,\n  output    test_array_entry_t                      out_arr_unpacked_unpacked[2:0][2:0]                 ,\n\n  output    test_2d_array_t     [2:0]               out_2d_arr_packed                                   ,\n  output    test_2d_array_t                         out_2d_arr_unpacked[2:0]                            ,\n\n  output    test_3d_array_t                         out_3d_arr                                          ,\n\n  //Struct single dimensions\n  output    struct_packed_t                         out_struct_packed                                   ,\n  output    struct_packed_t     [2:0]               out_struct_packed_array_packed                      ,\n  output    struct_packed_t                         out_struct_packed_array_unpacked[2:0]               ,\n\n  //Struct 2 dimensions\n  output    struct_packed_t     [2:0][2:0]          out_struct_packed_arr_packed_packed                 ,\n  output    struct_packed_t     [2:0]               out_struct_packed_arr_packed_unpacked[2:0]          ,\n  output    struct_packed_t                         out_struct_packed_arr_unpacked_unpacked[2:0][2:0]\n\n);\n\n//Fairly simple passthrough of all the values...\n\nassign out_vect_packed                                      = in_vect_packed                                      ;\nassign out_vect_unpacked                                    = in_vect_unpacked                                    ;\nassign out_arr                                              = in_arr                                              ;\n\n\nassign out_2d_vect_packed_packed                            = in_2d_vect_packed_packed                            ;\nassign out_2d_vect_packed_unpacked                          = in_2d_vect_packed_unpacked                          ;\nassign out_2d_vect_unpacked_unpacked                        = in_2d_vect_unpacked_unpacked                        ;\n\nassign out_arr_packed                                       = in_arr_packed                                       ;\nassign out_arr_unpacked                                     = in_arr_unpacked                                     ;\nassign out_2d_arr                                           = in_2d_arr                                           ;\n\n\nassign out_vect_packed_packed_packed                        = in_vect_packed_packed_packed                        ;\nassign out_vect_packed_packed_unpacked                      = in_vect_packed_packed_unpacked                      ;\nassign out_vect_packed_unpacked_unpacked                    = in_vect_packed_unpacked_unpacked                    ;\nassign out_vect_unpacked_unpacked_unpacked                  = in_vect_unpacked_unpacked_unpacked                  ;\n\nassign out_arr_packed_packed                                = in_arr_packed_packed                                ;\nassign out_arr_packed_unpacked                              = in_arr_packed_unpacked                              ;\nassign out_arr_unpacked_unpacked                            = in_arr_unpacked_unpacked                            ;\n\nassign out_2d_arr_packed                                    = in_2d_arr_packed                                    ;\nassign out_2d_arr_unpacked                                  = in_2d_arr_unpacked                                  ;\n\nassign out_3d_arr                                           = in_3d_arr                                           ;\n\nassign out_struct_packed                                    = in_struct_packed                                    ;\nassign out_struct_packed_array_packed                       = in_struct_packed_array_packed                       ;\nassign out_struct_packed_array_unpacked                     = in_struct_packed_array_unpacked                     ;\n\nassign out_struct_packed_arr_packed_packed                  = in_struct_packed_arr_packed_packed                  ;\nassign out_struct_packed_arr_packed_unpacked                = in_struct_packed_arr_packed_unpacked                ;\nassign out_struct_packed_arr_unpacked_unpacked              = in_struct_packed_arr_unpacked_unpacked              ;\n\nendmodule;\n"
  },
  {
    "path": "tests/designs/multi_dimension_array/cocotb_array_pkg.sv",
    "content": "package cocotb_array_pkg;\n\n    typedef logic               [2:0] test_array_entry_t;\n    typedef test_array_entry_t  [2:0] test_2d_array_t;\n    typedef test_2d_array_t     [2:0] test_3d_array_t;\n\n    typedef struct packed {\n        logic [2:0]                 vect_packed;\n        logic [2:0][2:0]            vect_packed_packed;\n        test_array_entry_t          array_packed;\n        test_array_entry_t [2:0]    array_packed_packed;\n    } struct_packed_t;\n\nendpackage\n"
  },
  {
    "path": "tests/designs/plusargs_module/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nCOCOTB_TOPLEVEL := tb_top\n\nPWD=$(shell pwd)\n\nCOCOTB?=$(PWD)/../../..\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    VERILOG_SOURCES = $(COCOTB)/tests/designs/plusargs_module/tb_top.v\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    VHDL_SOURCES =  $(COCOTB)/tests/designs/plusargs_module/tb_top.vhd\nelse\n    $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\nifneq ($(filter $(SIM),ius xcelium),)\n    COMPILE_ARGS += -v93\nendif\n\nifeq ($(shell echo $(SIM) | tr A-Z a-z),verilator)\n    COMPILE_ARGS += --timing\nendif\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "tests/designs/plusargs_module/tb_top.v",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\nmodule tb_top ;\n\n    reg [1000:0] foo_string;\n    integer result;\n\ninitial begin\n    $display(\"SIM: Plusargs test\");\n    result = $value$plusargs(\"foo=%s\", foo_string);\n    $display(\"SIM: Plusarg foo has value %0s\", foo_string);\n    result = $value$plusargs(\"lol=%s\", foo_string);\n    $display(\"SIM: Plusarg lol has value %0s\", foo_string);\n    #1 $display(\"SIM: Test running\");\nend\n\nendmodule //: tb_top\n"
  },
  {
    "path": "tests/designs/plusargs_module/tb_top.vhd",
    "content": "library ieee;\n\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nentity tb_top is\nend;\n\narchitecture impl of tb_top is\n    signal dummy_sig : std_logic := '0';\nbegin\n    process\n    begin\n        wait for 10 ns;\n        dummy_sig <= '1';\n        wait;\n    end process;\nend architecture;\n"
  },
  {
    "path": "tests/designs/runner/runner.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`include \"basic_hierarchy_module.v\"\n\nmodule runner #(\n    parameter WIDTH_IN = 4,\n    parameter WIDTH_OUT = 8\n) (\n    input  [WIDTH_IN-1:0]   data_in,\n    output [WIDTH_OUT-1:0]  data_out,\n    output [`DEFINE-1:0] define_out\n);\n\nbasic_hierarchy_module  basic_hierarchy_module(.clk(1'b0), .reset(1'b0));\n\ninitial begin\n    if (`DEFINE_STR != \"path/to/some/(random quote)/file.wow'\") begin\n        $error();\n    end\nend\n\nendmodule\n"
  },
  {
    "path": "tests/designs/runner/runner.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nentity runner is\ngeneric(\n    WIDTH_IN : integer := 4;\n    WIDTH_OUT : integer := 8);\nport(\n    data_in : in signed(WIDTH_IN-1 downto 0);\n    data_out : out signed(WIDTH_OUT-1 downto 0));\nend entity;\n\narchitecture rtl of runner is\nbegin\n\nend architecture;\n"
  },
  {
    "path": "tests/designs/runner_defines/runner_defines.sv",
    "content": ""
  },
  {
    "path": "tests/designs/sample_module/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nCOCOTB_TOPLEVEL := sample_module\n\nPWD=$(shell pwd)\n\nCOCOTB?=$(PWD)/../../..\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    VERILOG_SOURCES = $(COCOTB)/tests/designs/sample_module/sample_module.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    VHDL_SOURCES =  $(COCOTB)/tests/designs/sample_module/sample_module_package.vhdl $(COCOTB)/tests/designs/sample_module/sample_module_1.vhdl $(COCOTB)/tests/designs/sample_module/sample_module.vhdl\n\n    ifneq ($(filter $(SIM),ius xcelium),)\n        COMPILE_ARGS += -v93\n    endif\nelse\n    $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "tests/designs/sample_module/sample_module.sv",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`ifndef NOTIMESCALE\n`timescale 1 ps / 1 ps\n`endif  // `ifndef NOTIMESCALE\n\n`ifndef __ICARUS__\n\ntypedef struct\n{\n    logic a_in;\n    logic b_out;\n} test_struct_unpacked;\n\ntypedef struct packed\n{\n    logic val_a;\n    logic val_b;\n    logic value;\n} test_struct_packed;\n\n`endif  // `ifndef __ICARUS__\n\ninterface TestInterface ();\n\n   logic [31:0] addr;\n   modport source(input addr);\n\nendinterface\n\nmodule sub;\n   reg subsig1;\n   reg subsig2;\n   // stop icarus optimizing signals away\n   wire redundant = subsig1 | subsig2;\nendmodule : sub\n\nmodule sample_module #(\n    parameter INT_PARAM = 12,\n    parameter REAL_PARAM = 3.14,\n    parameter STRING_PARAM = \"Test\"\n)(\n    input                                       clk,\n\n    output reg                                  stream_in_ready,\n    input                                       stream_in_valid,\n`ifndef __ICARUS__\n    input  real                                 stream_in_real,\n    input  integer                              stream_in_int,\n    output real                                 stream_out_real,\n    output integer                              stream_out_int,\n    input  test_struct_unpacked                 inout_if,\n    input  test_struct_packed                   my_struct,\n    input  string                               stream_in_string,\n`endif  // `ifndef __ICARUS__\n    input  [7:0]                                stream_in_data,\n    input  [31:0]                               stream_in_data_dword,\n    input  [38:0]                               stream_in_data_39bit,\n    input  [63:0]                               stream_in_data_wide,\n    input  [127:0]                              stream_in_data_dqword,\n\n    input                                       stream_out_ready,\n    output reg [7:0]                            stream_out_data_comb,\n    output reg [7:0]                            stream_out_data_registered,\n\n    output                                      and_output\n\n);\n\n`ifndef __ICARUS__\nlocalparam string STRING_LOCALPARAM = \"TESTING_LOCALPARAM\";\n\nvar   string STRING_VAR   = \"TESTING_VAR\";\nconst string STRING_CONST = \"TESTING_CONST\";\n`endif  // `ifndef __ICARUS__\n\nalways @(posedge clk)\n    stream_out_data_registered <= stream_in_data;\n\nalways @(stream_in_data)\n    stream_out_data_comb = stream_in_data;\n\nalways @(stream_out_ready)\n    stream_in_ready      = stream_out_ready;\n\n`ifndef __ICARUS__\nalways @(stream_in_real)\n    stream_out_real      = stream_in_real;\n\nalways @(stream_in_int)\n    stream_out_int = stream_in_int;\n\nvar string stream_in_string_asciival_str;\nvar int stream_in_string_asciival;\nvar int stream_in_string_asciival_sum;\n`ifndef _VCP  // Aldec Riviera-PRO and Active-HDL\n  // workaround for\n  // # ELAB2: Fatal Error: ELAB2_0036 Unresolved hierarchical reference to \"stream_in_string.len.len\" from module \"sample_module\" (module not found).\nalways @(stream_in_string) begin\n    $display(\"%m: stream_in_string has been updated, new value is '%s'\", stream_in_string);\n    stream_in_string_asciival_sum = 0;\n    for (int idx = 0; idx < stream_in_string.len(); idx=idx+1) begin\n        stream_in_string_asciival_str = $sformatf(\"%0d\", stream_in_string[idx]);\n        stream_in_string_asciival = stream_in_string_asciival_str.atoi();\n        stream_in_string_asciival_sum += stream_in_string_asciival;\n        $display(\"%m: idx=%0d, stream_in_string_asciival=%0d -> stream_in_string_asciival_sum=%0d\",\n                 idx, stream_in_string_asciival, stream_in_string_asciival_sum);\n    end\nend\n`endif //  `ifndef _VCP\n\ntest_struct_unpacked struct_var;\n`endif //  `ifndef __ICARUS__\n\nand test_and_gate(and_output, stream_in_ready, stream_in_valid);\n\nparameter NUM_OF_MODULES /*verilator public_flat_rd*/ = 4;\nreg[NUM_OF_MODULES-1:0] temp;\ngenvar idx;\ngenerate\n    for (idx = 0; idx < NUM_OF_MODULES; idx=idx+1) begin\n        always @(posedge clk) begin\n            temp[idx] <= 1'b0;\n        end\n    end\nendgenerate\n\nTestInterface intf_arr[0:1] ();\n\ngenerate\n    if (INT_PARAM == 12) begin : cond_scope\n        localparam int scoped_param = 1;\n        sub scoped_sub ();\n    end else begin : cond_scope_else\n        sub scoped_sub_else ();\n    end\nendgenerate\n\ngenvar i;\ngenerate\n    for (i = 1; i <= 2; i = i + 1) begin : arr\n        sub arr_sub();\n    end\n\n    for (i = 1; i <= 2; i = i + 1) begin : outer_scope\n        localparam int outer_param = i * 2;\n        genvar j;\n        for (j = 1; j <= 2; j = j + 1) begin : inner_scope\n            localparam int inner_param = outer_param + 1;\n            sub inner_sub();\n        end\n    end\nendgenerate\n\nreg [7:0] register_array [1:0];\nalways @(posedge clk) begin\n    // Ensure internal array is not optimized out\n    register_array[0] <= 0;\nend\n\n//For testing arrays\nreg [7:0]  array_7_downto_4[7:4];\nreg [7:0]  array_4_to_7[4:7];\nreg [7:0]  array_4_downto_7[4:7];\nreg [7:0]  array_3_downto_0[3:0];\nreg [7:0]  array_0_to_3[0:3];\nreg [7:0]  array_2d[0:1][31:28];\nalways @(posedge stream_in_valid) begin\n    // Ensure internal array is not optimized out\n    array_7_downto_4[4] <= 0;\n    array_4_to_7[7] <= 0;\n    array_4_downto_7[7] <= 0;\n    array_3_downto_0[0] <= 0;\n    array_0_to_3[3] <= 0;\n    array_2d[1][28] <= 0;\nend\n\n//For testing type assigned to logic\nlogic logic_a, logic_b, logic_c;\nassign logic_a = stream_in_valid;\nalways@* logic_b = stream_in_valid;\nalways@(posedge clk) logic_c <= stream_in_valid;\n\nreg _underscore_name;\n`ifdef __ICARUS__\n    // By default, a variable must be used in some way in order\n    // to be visible to VPI in Icarus Verilog.\n    // See https://github.com/steveicarus/iverilog/issues/322\n    assign _underscore_name = 0;\n`endif  // `ifdef __ICARUS__\n\nbit mybit;\nbit [1:0] mybits;\nbit [1:0] mybits_uninitialized;\nlogic [0:0] one_bit_vector;\ninitial begin\n    mybit = 1;\n    mybits = '1;\n    one_bit_vector = '1;\nend\n\nalways @(mybit) begin\n    $display(\"%m: mybit has been updated, new value is %b\", mybit);\nend\nalways @(mybits) begin\n    $display(\"%m: mybits has been updated, new value is %b\", mybits);\nend\nalways @(mybits_uninitialized) begin\n    $display(\"%m: mybits_uninitialized has been updated, new value is %b\", mybits_uninitialized);\nend\nalways @(one_bit_vector) begin\n    $display(\"%m: one_bit_vector has been updated, new value is %b\", one_bit_vector);\nend\n\n// for testing weird signal names\nreg [3:0] \\weird.signal[1] = 0;\nreg [3:0] \\weird.signal[2] = 0;\nreg [3:0] \\(.*|this_looks_like_a_regex) = 0;\n\n// just to check that extended identifiers are the same as non-extended ones\nalways@* \\weird.signal[1] [0] = \\stream_in_valid ;\n\nendmodule\n"
  },
  {
    "path": "tests/designs/sample_module/sample_module.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Copyright (c) 2014 Potential Ventures Ltd\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\n\n\n\nlibrary ieee;\n\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nuse work.sample_module_package.all;\n\nentity sample_module is\n    generic (\n        INT_PARAM                       : integer   := 123\n    );\n    port (\n        clk                             : in    std_ulogic;\n\n        stream_in_data                  : in    std_ulogic_vector(7 downto 0);\n        stream_in_data_dword            : in    std_ulogic_vector(31 downto 0);\n        stream_in_data_39bit            : in    std_ulogic_vector(38 downto 0);\n        stream_in_data_wide             : in    std_ulogic_vector(63 downto 0);\n        stream_in_data_dqword           : in    std_ulogic_vector(127 downto 0);\n        stream_in_valid                 : in    std_ulogic;\n        stream_in_ready                 : out   std_ulogic;\n        stream_in_real                  : in    real;\n        stream_in_int                   : in    integer;\n        stream_in_string                : in    string(1 to 64);\n        stream_in_bool                  : in    boolean;\n\n        inout_if                        : in    test_record;\n\n        stream_out_data_comb            : out   std_ulogic_vector(7 downto 0);\n        stream_out_data_registered      : out   std_ulogic_vector(7 downto 0);\n        stream_out_data_wide            : out   std_ulogic_vector(63 downto 0);\n        stream_out_ready                : in    std_ulogic;\n        stream_out_real                 : out   real;\n        stream_out_int                  : out   integer;\n        stream_out_string               : out   string(1 to 64);\n        stream_out_bool                 : out   boolean\n    );\nend;\n\narchitecture impl of sample_module is\n\n    component sample_module_1 is\n        generic (\n            EXAMPLE_STRING      : string;\n            EXAMPLE_BOOL        : boolean;\n            EXAMPLE_WIDTH       : integer\n        );\n        port (\n            clk                             : in    std_ulogic;\n            stream_in_data                  : in    std_ulogic_vector(EXAMPLE_WIDTH downto 0);\n            stream_out_data_registered      : buffer   std_ulogic_vector(EXAMPLE_WIDTH downto 0);\n            stream_out_data_valid           : out   std_ulogic\n        );\n    end component sample_module_1;\n\n    type lutType is array (0 to 3, 0 to 6) of signed(10 downto 0);\n\n    signal cosLut0, sinLut0 : lutType;\n    signal cosLut1, sinLut1 : lutType;\n    signal cosLut,  sinLut  : lutType;\n\n    type unsignedArrayType is array (natural range <>) of unsigned(7 downto 0);\n    signal array_7_downto_4 : unsignedArrayType(7 downto 4);\n    signal array_4_to_7     : unsignedArrayType(4 to 7);\n    signal array_4_downto_7 : unsignedArrayType(4 downto 7);\n    signal array_3_downto_0 : unsignedArrayType(3 downto 0);\n    signal array_0_to_3     : unsignedArrayType(0 to 3);\n\n    type twoDimArrayType is array (natural range <>) of unsignedArrayType(31 downto 28);\n    signal array_2d         : twoDimArrayType(0 to 1);\n\n    signal one_bit_vector   : std_ulogic_vector(0 downto 0);\n\n    constant NUM_OF_MODULES : natural := 4;\n    signal temp             : std_logic_vector(NUM_OF_MODULES-1 downto 0);\n\n    signal stream_in_string_asciival_sum : natural;\n\n    -- for testing weird signal names\n    signal \\weird.signal(1)\\              : std_ulogic_vector(3 downto 0);\n    signal \\weird.signal(2)\\              : std_ulogic_vector(3 downto 0);\n    signal \\(.*|this looks like a regex)\\ : std_ulogic_vector(3 downto 0);\n\nbegin\n\n    genblk1: for i in NUM_OF_MODULES - 1 downto 0 generate\n    begin\n        process (clk) begin\n            if rising_edge(clk) then\n                temp(i) <= '0';\n            end if;\n        end process;\n    end generate;\n\n    process (clk) begin\n        if rising_edge(clk) then\n            stream_out_data_registered <= stream_in_data;\n        end if;\n    end process;\n\n    process (stream_in_string) is\n      variable v_cur_char : character;\n      variable v_stream_in_string_asciival : natural;\n      variable v_stream_in_string_asciival_sum : natural;\n    begin\n      report \"stream_in_string has been updated, new value is '\" & stream_in_string & \"'\";\n      v_stream_in_string_asciival_sum := 0;\n      for v_idx in stream_in_string'range loop\n        v_cur_char := stream_in_string(v_idx);\n        if v_cur_char /= ' ' then  -- only work on non-space characters\n          v_stream_in_string_asciival := character'pos(v_cur_char);\n          v_stream_in_string_asciival_sum := v_stream_in_string_asciival_sum + v_stream_in_string_asciival;\n          -- report \"v_idx=\" & integer'image(v_idx) &\n          --   \", v_stream_in_string_asciival=\" & integer'image(v_stream_in_string_asciival) &\n          --   -- \", v_cur_char='\" & v_cur_char & \"'\" &  -- this often ends the report output here\n          --   \" -> v_stream_in_string_asciival_sum=\" & integer'image(v_stream_in_string_asciival_sum);\n        end if;\n      end loop;  -- v_idx\n      stream_in_string_asciival_sum <= v_stream_in_string_asciival_sum;\n    end process;\n\n    process (stream_in_data) is\n    begin\n        stream_out_data_comb <= stream_in_data;\n    end process;\n\n    stream_in_ready      <= stream_out_ready;\n    stream_out_real      <= stream_in_real;\n    stream_out_int       <= stream_in_int;\n    stream_out_string    <= stream_in_string;\n    stream_out_bool      <= stream_in_bool;\n    stream_out_data_wide(3 downto 2) <= stream_in_data_wide(3 downto 2);\n\n    isample_module1 : component sample_module_1\n        generic map (\n            EXAMPLE_STRING => \"TESTING\",\n            EXAMPLE_BOOL => true,\n            EXAMPLE_WIDTH => 7\n        )\n        port map (\n            clk => clk,\n            stream_in_data => stream_in_data,\n            stream_out_data_registered => open,\n            stream_out_data_valid => open\n        );\n\nend architecture;\n"
  },
  {
    "path": "tests/designs/sample_module/sample_module_1.sv",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013, 2018 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`ifndef NOTIMESCALE\n`timescale 1 ps / 1 ps\n`endif  // `ifndef NOTIMESCALE\n\nmodule sample_module_1 #(\n    parameter int EXAMPLE_WIDTH\n)(\n    input logic clk,\n    input logic rst,\n    input logic [EXAMPLE_WIDTH:0] stream_in_data,\n    input logic stream_in_valid,\n    output logic stream_in_ready,\n    output logic [EXAMPLE_WIDTH:0] stream_out_data,\n    output logic stream_out_valid,\n    input logic stream_out_ready\n);\n\n    initial begin\n        stream_in_ready  = 1'b0;\n        stream_out_valid = 1'b0;\n        stream_out_data  = 16'h0000;\n    end\n\n    always_ff @(posedge clk or posedge rst) begin\n        if (rst) begin\n            stream_in_ready  <= 1'b0;\n            stream_out_valid <= 1'b0;\n            stream_out_data  <= 16'h0000;\n        end else begin\n            stream_in_ready  <= 1'b1;\n            if (stream_in_valid && stream_in_ready) begin\n                stream_out_data  <= stream_in_data + 16'h0001;\n                stream_out_valid <= 1'b1;\n            end\n            if (stream_out_valid && stream_out_ready) begin\n                stream_out_valid <= 1'b0;\n            end\n        end\n    end\nendmodule : sample_module_1\n"
  },
  {
    "path": "tests/designs/sample_module/sample_module_1.vhdl",
    "content": "library ieee;\n\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nentity sample_module_1 is\n    generic (\n        EXAMPLE_STRING      : string;\n        EXAMPLE_BOOL        : boolean;\n        EXAMPLE_WIDTH       : integer\n    );\n    port (\n        clk                             : in     std_ulogic;\n        stream_in_data                  : in     std_ulogic_vector(EXAMPLE_WIDTH downto 0);\n        stream_out_data_registered      : buffer std_ulogic_vector(EXAMPLE_WIDTH downto 0);\n        stream_out_data_valid           : out    std_ulogic\n    );\nend;\n\narchitecture impl of sample_module_1 is\nbegin\n    process (clk) begin\n        if rising_edge(clk) then\n            stream_out_data_registered <= stream_in_data;\n        end if;\n    end process;\n\n    stream_out_data_valid  <= '1' when (stream_out_data_registered(EXAMPLE_WIDTH) = '1') else '0';\n\n    SAMPLE_BLOCK : block\n        signal clk_inv : std_ulogic;\n    begin\n        clk_inv <= not clk;\n    end block;\n\nend architecture;\n"
  },
  {
    "path": "tests/designs/sample_module/sample_module_package.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Copyright (c) 2014 Potential Ventures Ltd\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\n\nlibrary ieee;\n\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\npackage sample_module_package is\n\n    type test_record is record\n        a_in  : std_logic;\n        b_out : std_logic;\n    end record test_record;\n\nend package sample_module_package;\n\npackage body sample_module_package is\nend package body sample_module_package;\n"
  },
  {
    "path": "tests/designs/uart2bus/Makefile",
    "content": "TOPLEVEL_LANG ?= verilog\n\nifneq ($(TOPLEVEL_LANG),verilog)\n\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being verilog\"\nclean::\n\nelse\n\nPWD=$(shell pwd)\n\nCOCOTB?=$(PWD)/../../..\n\nSRC_BASE = $(COCOTB)/tests/designs/uart2bus\n\nVHDL_SOURCES =      $(SRC_BASE)/vhdl/uart2BusTop_pkg.vhd \\\n                    $(SRC_BASE)/vhdl/baudGen.vhd \\\n                    $(SRC_BASE)/vhdl/uartParser.vhd \\\n                    $(SRC_BASE)/vhdl/uartRx.vhd \\\n                    $(SRC_BASE)/vhdl/uartTx.vhd \\\n                    $(SRC_BASE)/vhdl/uartTop.vhd \\\n                    $(SRC_BASE)/vhdl/uart2BusTop.vhd\n\nVERILOG_SOURCES =   $(SRC_BASE)/verilog/baud_gen.v \\\n                    $(SRC_BASE)/verilog/uart_parser.v \\\n                    $(SRC_BASE)/verilog/uart_rx.v \\\n                    $(SRC_BASE)/verilog/uart_tx.v \\\n                    $(SRC_BASE)/verilog/uart_top.v \\\n                    $(SRC_BASE)/verilog/uart2bus_top.v\n\nVERILOG_SOURCES += $(SRC_BASE)/top/verilog_toplevel.sv\nCOCOTB_TOPLEVEL = verilog_toplevel\n\nifeq ($(SIM),$(filter $(SIM),ius xcelium))\n    COMPILE_ARGS += -v93\nendif\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/designs/uart2bus/README",
    "content": "UART to bus design from [OpenCores](http://opencores.org/project,uart2bus)\n\nBSD Licensed.\n\nContains a VHDL and Verilog implementation, suitable for testing mixed\nlanguage simulations.\n"
  },
  {
    "path": "tests/designs/uart2bus/top/verilog_toplevel.sv",
    "content": "// We simply connect two UARTs together in different languages\n//\n// Also define a few different structs etc. to help the testcase\n\nmodule verilog_toplevel (\n    input               clk,\n    input               reset\n);\n\n\n// Verilog design\nlogic                   serial_v2h, serial_h2v;\nlogic [7:0]             verilog_rd_data, vhdl_rd_data;\n\ntypedef struct packed {\n    logic [15:0]        address;\n    logic [7:0]         wr_data;\n    logic               read;\n    logic               write;\n} bus_struct_t;\n\nbus_struct_t bus_verilog, bus_vhdl;\n\nuart2bus_top i_verilog (\n    .clock              (clk),\n    .reset              (reset),\n\n    .ser_in             (serial_h2v),\n    .ser_out            (serial_v2h),\n\n    .int_address        (bus_verilog.address),\n    .int_wr_data        (bus_verilog.wr_data),\n    .int_write          (bus_verilog.write),\n    .int_read           (bus_verilog.read),\n    .int_rd_data        (verilog_rd_data),\n\n    .int_req            (),\n    .int_gnt            ()\n);\n\nuart2BusTop i_vhdl (\n    .clk                (clk),\n    .clr                (reset),\n\n    .serIn              (serial_v2h),\n    .serOut             (serial_h2v),\n\n    .intAddress         (bus_vhdl.address),\n    .intWrData          (bus_vhdl.wr_data),\n    .intWrite           (bus_vhdl.write),\n    .intRead            (bus_vhdl.read),\n    .intRdData          (vhdl_rd_data),\n\n    .intAccessReq       (),\n    .intAccessGnt       ()\n);\n\nendmodule\n"
  },
  {
    "path": "tests/designs/uart2bus/top/vhdl_toplevel.vhdl",
    "content": ""
  },
  {
    "path": "tests/designs/uart2bus/verilog/baud_gen.v",
    "content": "//---------------------------------------------------------------------------------------\n// baud rate generator for uart\n//\n// this module has been changed to receive the baud rate dividing counter from registers.\n// the two registers should be calculated as follows:\n// first register:\n// \t\tbaud_freq = 16*baud_rate / gcd(global_clock_freq, 16*baud_rate)\n// second register:\n// \t\tbaud_limit = (global_clock_freq / gcd(global_clock_freq, 16*baud_rate)) - baud_freq\n//\n//---------------------------------------------------------------------------------------\n\nmodule baud_gen\n(\n\tclock, reset,\n\tce_16, baud_freq, baud_limit\n);\n//---------------------------------------------------------------------------------------\n// modules inputs and outputs\ninput \t\t\tclock;\t\t// global clock input\ninput \t\t\treset;\t\t// global reset input\noutput\t\t\tce_16;\t\t// baud rate multiplied by 16\ninput\t[11:0]\tbaud_freq;\t// baud rate setting registers - see header description\ninput\t[15:0]\tbaud_limit;\n\n// internal registers\nreg ce_16;\nreg [15:0]\tcounter;\n//---------------------------------------------------------------------------------------\n// module implementation\n// baud divider counter\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tcounter <= 16'b0;\n\telse if (counter >= baud_limit)\n\t\tcounter <= counter - baud_limit;\n\telse\n\t\tcounter <= counter + baud_freq;\nend\n\n// clock divider output\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tce_16 <= 1'b0;\n\telse if (counter >= baud_limit)\n\t\tce_16 <= 1'b1;\n\telse\n\t\tce_16 <= 1'b0;\nend\n\nendmodule\n//---------------------------------------------------------------------------------------\n//\t\t\t\t\t\tTh.. Th.. Th.. That's all folks !!!\n//---------------------------------------------------------------------------------------\n"
  },
  {
    "path": "tests/designs/uart2bus/verilog/uart2bus_top.v",
    "content": "//---------------------------------------------------------------------------------------\n// uart to internal bus top module\n//\n//---------------------------------------------------------------------------------------\n\nmodule uart2bus_top\n(\n\t// global signals\n\tclock, reset,\n\t// uart serial signals\n\tser_in, ser_out,\n\t// internal bus to register file\n\tint_address, int_wr_data, int_write,\n\tint_rd_data, int_read,\n\tint_req, int_gnt\n);\n//---------------------------------------------------------------------------------------\n// modules inputs and outputs\ninput \t\t\tclock;\t\t\t// global clock input\ninput \t\t\treset;\t\t\t// global reset input\ninput\t\t\tser_in;\t\t\t// serial data input\noutput\t\t\tser_out;\t\t// serial data output\noutput\t[15:0]\tint_address;\t// address bus to register file\noutput\t[7:0]\tint_wr_data;\t// write data to register file\noutput\t\t\tint_write;\t\t// write control to register file\noutput\t\t\tint_read;\t\t// read control to register file\ninput\t[7:0]\tint_rd_data;\t// data read from register file\noutput\t\t\tint_req;\t\t// bus access request signal\ninput\t\t\tint_gnt;\t\t// bus access grant signal\n\n// baud rate configuration, see baud_gen.v for more details.\n// baud rate generator parameters for 115200 baud on 40MHz clock\n`define D_BAUD_FREQ\t\t\t12'h90\n`define D_BAUD_LIMIT\t\t16'h0ba5\n// baud rate generator parameters for 115200 baud on 44MHz clock\n// `define D_BAUD_FREQ\t\t\t12'd23\n// `define D_BAUD_LIMIT\t\t16'd527\n// baud rate generator parameters for 9600 baud on 66MHz clock\n//`define D_BAUD_FREQ\t\t12'h10\n//`define D_BAUD_LIMIT\t\t16'h1ACB\n\n// internal wires\nwire\t[7:0]\ttx_data;\t\t// data byte to transmit\nwire\t\t\tnew_tx_data;\t// asserted to indicate that there is a new data byte for transmission\nwire \t\t\ttx_busy;\t\t// signs that transmitter is busy\nwire\t[7:0]\trx_data;\t\t// data byte received\nwire \t\t\tnew_rx_data;\t// signs that a new byte was received\nwire\t[11:0]\tbaud_freq;\nwire\t[15:0]\tbaud_limit;\nwire\t\t\tbaud_clk;\n\n//---------------------------------------------------------------------------------------\n// module implementation\n// uart top module instance\nuart_top uart1\n(\n\t.clock(clock), .reset(reset),\n\t.ser_in(ser_in), .ser_out(ser_out),\n\t.rx_data(rx_data), .new_rx_data(new_rx_data),\n\t.tx_data(tx_data), .new_tx_data(new_tx_data), .tx_busy(tx_busy),\n\t.baud_freq(baud_freq), .baud_limit(baud_limit),\n\t.baud_clk(baud_clk)\n);\n\n// assign baud rate default values\nassign baud_freq = `D_BAUD_FREQ;\nassign baud_limit = `D_BAUD_LIMIT;\n\n// uart parser instance\nuart_parser #(16) uart_parser1\n(\n\t.clock(clock), .reset(reset),\n\t.rx_data(rx_data), .new_rx_data(new_rx_data),\n\t.tx_data(tx_data), .new_tx_data(new_tx_data), .tx_busy(tx_busy),\n\t.int_address(int_address), .int_wr_data(int_wr_data), .int_write(int_write),\n\t.int_rd_data(int_rd_data), .int_read(int_read),\n\t.int_req(int_req), .int_gnt(int_gnt)\n);\n\nendmodule\n//---------------------------------------------------------------------------------------\n//\t\t\t\t\t\tTh.. Th.. Th.. That's all folks !!!\n//---------------------------------------------------------------------------------------\n"
  },
  {
    "path": "tests/designs/uart2bus/verilog/uart_parser.v",
    "content": "//---------------------------------------------------------------------------------------\n// uart parser module\n//\n//---------------------------------------------------------------------------------------\n\nmodule uart_parser\n(\n\t// global signals\n\tclock, reset,\n\t// transmit and receive internal interface signals from uart interface\n\trx_data, new_rx_data,\n\ttx_data, new_tx_data, tx_busy,\n\t// internal bus to register file\n\tint_address, int_wr_data, int_write,\n\tint_rd_data, int_read,\n\tint_req, int_gnt\n);\n//---------------------------------------------------------------------------------------\n// parameters\nparameter\t\tAW = 8;\t\t\t// address bus width parameter\n\n// modules inputs and outputs\ninput \t\t\tclock;\t\t\t// global clock input\ninput \t\t\treset;\t\t\t// global reset input\noutput\t[7:0]\ttx_data;\t\t// data byte to transmit\noutput\t\t\tnew_tx_data;\t// asserted to indicate that there is a new data byte for\n\t\t\t\t\t\t\t\t// transmission\ninput \t\t\ttx_busy;\t\t// signs that transmitter is busy\ninput\t[7:0]\trx_data;\t\t// data byte received\ninput \t\t\tnew_rx_data;\t// signs that a new byte was received\noutput\t[AW-1:0] int_address;\t// address bus to register file\noutput\t[7:0]\tint_wr_data;\t// write data to register file\noutput\t\t\tint_write;\t\t// write control to register file\noutput\t\t\tint_read;\t\t// read control to register file\ninput\t[7:0]\tint_rd_data;\t// data read from register file\noutput\t\t\tint_req;\t\t// bus access request signal\ninput\t\t\tint_gnt;\t\t// bus access grant signal\n\n// registered outputs\nreg\t[7:0] tx_data;\nreg new_tx_data;\nreg\t[AW-1:0] int_address;\nreg\t[7:0] int_wr_data;\nreg write_req, read_req, int_write, int_read;\n\n// internal constants\n// define characters used by the parser\n`define CHAR_CR\t\t\t8'h0d\n`define CHAR_LF\t\t\t8'h0a\n`define CHAR_SPACE\t\t8'h20\n`define CHAR_TAB\t\t8'h09\n`define CHAR_COMMA\t\t8'h2C\n`define CHAR_R_UP\t\t8'h52\n`define CHAR_r_LO\t\t8'h72\n`define CHAR_W_UP\t\t8'h57\n`define CHAR_w_LO\t\t8'h77\n`define CHAR_0\t\t\t8'h30\n`define CHAR_1\t\t\t8'h31\n`define CHAR_2\t\t\t8'h32\n`define CHAR_3\t\t\t8'h33\n`define CHAR_4\t\t\t8'h34\n`define CHAR_5\t\t\t8'h35\n`define CHAR_6\t\t\t8'h36\n`define CHAR_7\t\t\t8'h37\n`define CHAR_8\t\t\t8'h38\n`define CHAR_9\t\t\t8'h39\n`define CHAR_A_UP\t\t8'h41\n`define CHAR_B_UP\t\t8'h42\n`define CHAR_C_UP\t\t8'h43\n`define CHAR_D_UP\t\t8'h44\n`define CHAR_E_UP\t\t8'h45\n`define CHAR_F_UP\t\t8'h46\n`define CHAR_a_LO\t\t8'h61\n`define CHAR_b_LO\t\t8'h62\n`define CHAR_c_LO\t\t8'h63\n`define CHAR_d_LO\t\t8'h64\n`define CHAR_e_LO\t\t8'h65\n`define CHAR_f_LO\t\t8'h66\n\n// main (receive) state machine states\n`define MAIN_IDLE\t\t4'b0000\n`define MAIN_WHITE1\t\t4'b0001\n`define MAIN_DATA\t\t4'b0010\n`define MAIN_WHITE2\t\t4'b0011\n`define MAIN_ADDR\t\t4'b0100\n`define MAIN_EOL\t\t4'b0101\n// binary mode extension states\n`define MAIN_BIN_CMD\t4'b1000\n`define MAIN_BIN_ADRH\t4'b1001\n`define MAIN_BIN_ADRL\t4'b1010\n`define MAIN_BIN_LEN    4'b1011\n`define MAIN_BIN_DATA   4'b1100\n\n// transmit state machine\n`define TX_IDLE\t\t\t3'b000\n`define TX_HI_NIB\t\t3'b001\n`define TX_LO_NIB\t\t3'b100\n`define TX_CHAR_CR\t\t3'b101\n`define TX_CHAR_LF\t\t3'b110\n\n// binary extension mode commands - the command is indicated by bits 5:4 of the command byte\n`define BIN_CMD_NOP\t\t2'b00\n`define BIN_CMD_READ\t2'b01\n`define BIN_CMD_WRITE\t2'b10\n\n// internal wires and registers\nreg [3:0] main_sm;\t\t\t// main state machine\nreg read_op;\t\t\t\t// read operation flag\nreg write_op;\t\t\t\t// write operation flag\nreg data_in_hex_range;\t\t// indicates that the received data is in the range of hex number\nreg [7:0] data_param;\t\t// operation data parameter\nreg [15:0] addr_param;\t\t// operation address parameter\nreg [3:0] data_nibble;\t\t// data nibble from received character\nreg read_done;\t\t\t\t// internally generated read done flag\nreg read_done_s;\t\t\t// sampled read done\nreg [7:0] read_data_s;\t\t// sampled read data\nreg [3:0] tx_nibble;\t\t// nibble value for transmission\nreg [7:0] tx_char;\t\t\t// transmit byte from nibble to character conversion\nreg [2:0] tx_sm;\t\t\t// transmit state machine\nreg s_tx_busy;\t\t\t\t// sampled tx_busy for falling edge detection\nreg bin_read_op;\t\t\t// binary mode read operation flag\nreg bin_write_op;\t\t\t// binary mode write operation flag\nreg addr_auto_inc;\t\t\t// address auto increment mode\nreg send_stat_flag;\t\t\t// send status flag\nreg [7:0] bin_byte_count;\t// binary mode byte counter\nwire bin_last_byte;\t\t\t// last byte flag indicates that the current byte in the command is the last\nwire tx_end_p;\t\t\t\t// transmission end pulse\n\n//---------------------------------------------------------------------------------------\n// module implementation\n// main state machine\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tmain_sm <= `MAIN_IDLE;\n\telse if (new_rx_data)\n\tbegin\n\t\tcase (main_sm)\n\t\t\t// wait for a read ('r') or write ('w') command\n\t\t\t// binary extension - an all zeros byte enabled binary commands\n\t\t\t`MAIN_IDLE:\n\t\t\t\t// check received character\n\t\t\t\tif (rx_data == 8'h0)\n\t\t\t\t\t// an all zeros received byte enters binary mode\n\t\t\t\t\tmain_sm <= `MAIN_BIN_CMD;\n\t\t\t\telse if ((rx_data == `CHAR_r_LO) | (rx_data == `CHAR_R_UP))\n\t\t\t\t\t// on read wait to receive only address field\n\t\t\t\t\tmain_sm <= `MAIN_WHITE2;\n\t\t\t\telse if ((rx_data == `CHAR_w_LO) | (rx_data == `CHAR_W_UP))\n\t\t\t\t\t// on write wait to receive data and address\n\t\t\t\t\tmain_sm <= `MAIN_WHITE1;\n\t\t\t\telse if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF))\n\t\t\t\t\t// on new line sta in idle\n\t\t\t\t\tmain_sm <= `MAIN_IDLE;\n\t\t\t\telse\n\t\t\t\t\t// any other character wait to end of line (EOL)\n\t\t\t\t\tmain_sm <= `MAIN_EOL;\n\n\t\t\t// wait for white spaces till first data nibble\n\t\t\t`MAIN_WHITE1:\n\t\t\t\t// wait in this case until any white space character is received. in any\n\t\t\t\t// valid character for data value switch to data state. a new line or carriage\n\t\t\t\t// return should reset the state machine to idle.\n\t\t\t\t// any other character transitions the state machine to wait for EOL.\n\t\t\t\tif ((rx_data == `CHAR_SPACE) | (rx_data == `CHAR_TAB))\n\t\t\t\t\tmain_sm <= `MAIN_WHITE1;\n\t\t\t\telse if (data_in_hex_range)\n\t\t\t\t\tmain_sm <= `MAIN_DATA;\n\t\t\t\telse if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF))\n\t\t\t\t\tmain_sm <= `MAIN_IDLE;\n\t\t\t\telse\n\t\t\t\t\tmain_sm <= `MAIN_EOL;\n\n\t\t\t// receive data field\n\t\t\t`MAIN_DATA:\n\t\t\t\t// wait while data in hex range. white space transition to wait white 2 state.\n\t\t\t\t// CR and LF resets the state machine. any other value cause state machine to\n\t\t\t\t// wait til end of line.\n\t\t\t\tif (data_in_hex_range)\n\t\t\t\t\tmain_sm <= `MAIN_DATA;\n\t\t\t\telse if ((rx_data == `CHAR_SPACE) | (rx_data == `CHAR_TAB))\n\t\t\t\t\tmain_sm <= `MAIN_WHITE2;\n\t\t\t\telse if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF))\n\t\t\t\t\tmain_sm <= `MAIN_IDLE;\n\t\t\t\telse\n\t\t\t\t\tmain_sm <= `MAIN_EOL;\n\n\t\t\t// wait for white spaces till first address nibble\n\t\t\t`MAIN_WHITE2:\n\t\t\t\t// similar to MAIN_WHITE1\n\t\t\t\tif ((rx_data == `CHAR_SPACE) | (rx_data == `CHAR_TAB))\n\t\t\t\t\tmain_sm <= `MAIN_WHITE2;\n\t\t\t\telse if (data_in_hex_range)\n\t\t\t\t\tmain_sm <= `MAIN_ADDR;\n\t\t\t\telse if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF))\n\t\t\t\t\tmain_sm <= `MAIN_IDLE;\n\t\t\t\telse\n\t\t\t\t\tmain_sm <= `MAIN_EOL;\n\n\t\t\t// receive address field\n\t\t\t`MAIN_ADDR:\n\t\t\t\t// similar to MAIN_DATA\n\t\t\t\tif (data_in_hex_range)\n\t\t\t\t\tmain_sm <= `MAIN_ADDR;\n\t\t\t\telse if ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF))\n\t\t\t\t\tmain_sm <= `MAIN_IDLE;\n\t\t\t\telse\n\t\t\t\t\tmain_sm <= `MAIN_EOL;\n\n\t\t\t// wait to EOL\n\t\t\t`MAIN_EOL:\n\t\t\t\t// wait for CR or LF to move back to idle\n\t\t\t\tif ((rx_data == `CHAR_CR) | (rx_data == `CHAR_LF))\n\t\t\t\t\tmain_sm <= `MAIN_IDLE;\n\n\t\t\t// binary extension\n\t\t\t// wait for command - one byte\n\t\t\t`MAIN_BIN_CMD:\n\t\t\t\t// check if command is a NOP command\n\t\t\t\tif (rx_data[5:4] == `BIN_CMD_NOP)\n\t\t\t\t\t// if NOP command then switch back to idle state\n\t\t\t\t\tmain_sm <= `MAIN_IDLE;\n\t\t\t\telse\n\t\t\t\t\t// not a NOP command, continue receiving parameters\n\t\t\t\t\tmain_sm <= `MAIN_BIN_ADRH;\n\n\t\t\t// wait for address parameter - two bytes\n\t\t\t// high address byte\n\t\t\t`MAIN_BIN_ADRH:\n\t\t\t\t// switch to next state\n\t\t\t\tmain_sm <= `MAIN_BIN_ADRL;\n\n\t\t\t// low address byte\n\t\t\t`MAIN_BIN_ADRL:\n\t\t\t\t// switch to next state\n\t\t\t\tmain_sm <= `MAIN_BIN_LEN;\n\n\t\t\t// wait for length parameter - one byte\n\t\t\t`MAIN_BIN_LEN:\n\t\t\t\t// check if write command else command reception ended\n\t\t\t\tif (bin_write_op)\n\t\t\t\t\t// wait for write data\n\t\t\t\t\tmain_sm <= `MAIN_BIN_DATA;\n\t\t\t\telse\n\t\t\t\t\t// command reception has ended\n\t\t\t\t\tmain_sm <= `MAIN_IDLE;\n\n\t\t\t// on write commands wait for data till end of buffer as specified by length parameter\n\t\t\t`MAIN_BIN_DATA:\n\t\t\t\t// if this is the last data byte then return to idle\n\t\t\t\tif (bin_last_byte)\n\t\t\t\t\tmain_sm <= `MAIN_IDLE;\n\n\t\t\t// go to idle\n\t\t\tdefault:\n\t\t\t\tmain_sm <= `MAIN_IDLE;\n\t\tendcase\n\tend\nend\n\n// indicates that the received data is in the range of hex number\nalways @ (rx_data)\nbegin\n\tif (((rx_data >= `CHAR_0   ) && (rx_data <= `CHAR_9   )) ||\n\t    ((rx_data >= `CHAR_A_UP) && (rx_data <= `CHAR_F_UP)) ||\n\t    ((rx_data >= `CHAR_a_LO) && (rx_data <= `CHAR_f_LO)))\n\t\tdata_in_hex_range <= 1'b1;\n\telse\n\t\tdata_in_hex_range <= 1'b0;\nend\n\n// read operation flag\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tread_op <= 1'b0;\n\telse if ((main_sm == `MAIN_IDLE) && new_rx_data)\n\tbegin\n\t\t// the read operation flag is set when a read command is received in idle state and cleared\n\t\t// if any other character is received during that state.\n\t\tif ((rx_data == `CHAR_r_LO) | (rx_data == `CHAR_R_UP))\n\t\t\tread_op <= 1'b1;\n\t\telse\n\t\t\tread_op <= 1'b0;\n\tend\nend\n\n// write operation flag\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\twrite_op <= 1'b0;\n\telse if ((main_sm == `MAIN_IDLE) & new_rx_data)\n\tbegin\n\t\t// the write operation flag is set when a write command is received in idle state and cleared\n\t\t// if any other character is received during that state.\n\t\tif ((rx_data == `CHAR_w_LO) | (rx_data == `CHAR_W_UP))\n\t\t\twrite_op <= 1'b1;\n\t\telse\n\t\t\twrite_op <= 1'b0;\n\tend\nend\n\n// binary mode read operation flag\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tbin_read_op <= 1'b0;\n\telse if ((main_sm == `MAIN_BIN_CMD) && new_rx_data && (rx_data[5:4] == `BIN_CMD_READ))\n\t\t// read command is started on reception of a read command\n\t\tbin_read_op <= 1'b1;\n\telse if (bin_read_op && tx_end_p && bin_last_byte)\n\t\t// read command ends on transmission of the last byte read\n\t\tbin_read_op <= 1'b0;\nend\n\n// binary mode write operation flag\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tbin_write_op <= 1'b0;\n\telse if ((main_sm == `MAIN_BIN_CMD) && new_rx_data && (rx_data[5:4] == `BIN_CMD_WRITE))\n\t\t// write command is started on reception of a write command\n\t\tbin_write_op <= 1'b1;\n\telse if ((main_sm == `MAIN_BIN_DATA) && new_rx_data && bin_last_byte)\n\t\tbin_write_op <= 1'b0;\nend\n\n// send status flag - used only in binary extension mode\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tsend_stat_flag <= 1'b0;\n\telse if ((main_sm == `MAIN_BIN_CMD) && new_rx_data)\n\tbegin\n\t\t// check if a status byte should be sent at the end of the command\n\t\tif (rx_data[0] == 1'b1)\n\t\t\tsend_stat_flag <= 1'b1;\n\t\telse\n\t\t\tsend_stat_flag <= 1'b0;\n\tend\nend\n\n// address auto increment - used only in binary extension mode\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\taddr_auto_inc <= 1'b0;\n\telse if ((main_sm == `MAIN_BIN_CMD) && new_rx_data)\n\tbegin\n\t\t// check if address should be automatically incremented or not.\n\t\t// Note that when rx_data[1] is set, address auto increment is disabled.\n\t\tif (rx_data[1] == 1'b0)\n\t\t\taddr_auto_inc <= 1'b1;\n\t\telse\n\t\t\taddr_auto_inc <= 1'b0;\n\tend\nend\n\n// operation data parameter\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tdata_param <= 8'h0;\n\telse if ((main_sm == `MAIN_WHITE1) & new_rx_data & data_in_hex_range)\n\t\tdata_param <= {4'h0, data_nibble};\n\telse if ((main_sm == `MAIN_DATA) & new_rx_data & data_in_hex_range)\n\t\tdata_param <= {data_param[3:0], data_nibble};\nend\n\n// operation address parameter\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\taddr_param <= 0;\n\telse if ((main_sm == `MAIN_WHITE2) & new_rx_data & data_in_hex_range)\n\t\taddr_param <= {12'b0, data_nibble};\n\telse if ((main_sm == `MAIN_ADDR) & new_rx_data & data_in_hex_range)\n\t\taddr_param <= {addr_param[11:0], data_nibble};\n\t// binary extension\n\telse if (main_sm == `MAIN_BIN_ADRH)\n\t\taddr_param[15:8] <= rx_data;\n\telse if (main_sm == `MAIN_BIN_ADRL)\n\t\taddr_param[7:0] <= rx_data;\nend\n\n// binary mode command byte counter is loaded with the length parameter and counts down to zero.\n// NOTE: a value of zero for the length parameter indicates a command of 256 bytes.\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tbin_byte_count <= 8'b0;\n\telse if ((main_sm == `MAIN_BIN_LEN) && new_rx_data)\n\t\tbin_byte_count <= rx_data;\n\telse if ((bin_write_op && (main_sm == `MAIN_BIN_DATA) && new_rx_data) ||\n\t\t\t (bin_read_op && tx_end_p))\n\t\t// byte counter is updated on every new data received in write operations and for every\n\t\t// byte transmitted for read operations.\n\t\tbin_byte_count <= bin_byte_count - 1;\nend\n// last byte in command flag\nassign bin_last_byte = (bin_byte_count == 8'h01) ? 1'b1 : 1'b0;\n\n// internal write control and data\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\tbegin\n\t\twrite_req <= 1'b0;\n\t\tint_write <= 1'b0;\n\t\tint_wr_data <= 0;\n\tend\n\telse if (write_op && (main_sm == `MAIN_ADDR) && new_rx_data && !data_in_hex_range)\n\tbegin\n\t\twrite_req <= 1'b1;\n\t\tint_wr_data <= data_param;\n\tend\n\t// binary extension mode\n\telse if (bin_write_op && (main_sm == `MAIN_BIN_DATA) && new_rx_data)\n\tbegin\n\t\twrite_req <= 1'b1;\n\t\tint_wr_data <= rx_data;\n\tend\n\telse if (int_gnt && write_req)\n\tbegin\n\t\t// set internal bus write and clear the write request flag\n\t\tint_write <= 1'b1;\n\t\twrite_req <= 1'b0;\n\tend\n\telse\n\t\tint_write <= 1'b0;\nend\n\n// internal read control\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\tbegin\n\t\tint_read <= 1'b0;\n\t\tread_req <= 1'b0;\n\tend\n\telse if (read_op && (main_sm == `MAIN_ADDR) && new_rx_data && !data_in_hex_range)\n\t\tread_req <= 1'b1;\n\t// binary extension\n\telse if (bin_read_op && (main_sm == `MAIN_BIN_LEN) && new_rx_data)\n\t\t// the first read request is issued on reception of the length byte\n\t\tread_req <= 1'b1;\n\telse if (bin_read_op && tx_end_p && !bin_last_byte)\n\t\t// the next read requests are issued after the previous read value was transmitted and\n\t\t// this is not the last byte to be read.\n\t\tread_req <= 1'b1;\n\telse if (int_gnt && read_req)\n\tbegin\n\t\t// set internal bus read and clear the read request flag\n\t\tint_read <= 1'b1;\n\t\tread_req <= 1'b0;\n\tend\n\telse\n\t\tint_read <= 1'b0;\nend\n\n// external request signal is active on read or write request\nassign int_req = write_req | read_req;\n\n// internal address\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tint_address <= 0;\n\telse if ((main_sm == `MAIN_ADDR) && new_rx_data && !data_in_hex_range)\n\t\tint_address <= addr_param[AW-1:0];\n\t// binary extension\n\telse if ((main_sm == `MAIN_BIN_LEN) && new_rx_data)\n\t\t// sample address parameter on reception of length byte\n\t\tint_address <= addr_param[AW-1:0];\n\telse if (addr_auto_inc &&\n\t\t\t ((bin_read_op && tx_end_p && !bin_last_byte) ||\n\t\t\t  (bin_write_op && int_write)))\n\t\t// address is incremented on every read or write if enabled\n\t\tint_address <= int_address + 1;\nend\n\n// read done flag and sampled data read\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset) begin\n\t\tread_done <= 1'b0;\n\t\tread_done_s <= 1'b0;\n\t\tread_data_s <= 8'h0;\n\tend\n\telse\n\tbegin\n\t\t// read done flag\n\t\tif (int_read)\n\t\t\tread_done <= 1'b1;\n\t\telse\n\t\t\tread_done <= 1'b0;\n\n\t\t// sampled read done\n\t\tread_done_s <= read_done;\n\n\t\t// sampled data read\n\t\tif (read_done)\n\t\t\tread_data_s <= int_rd_data;\n\tend\nend\n\n// transmit state machine and control\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset) begin\n\t\ttx_sm <= `TX_IDLE;\n\t\ttx_data <= 8'h0;\n\t\tnew_tx_data <= 1'b0;\n\tend\n\telse\n\t\tcase (tx_sm)\n\t\t\t// wait for read done indication\n\t\t\t`TX_IDLE:\n\t\t\t\t// on end of every read operation check how the data read should be transmitted\n\t\t\t\t// according to read type: ascii or binary.\n\t\t\t\tif (read_done_s)\n\t\t\t\t\t// on binary mode read transmit byte value\n\t\t\t\t\tif (bin_read_op)\n\t\t\t\t\tbegin\n\t\t\t\t\t\t// note that there is no need to change state\n\t\t\t\t\t\ttx_data <= read_data_s;\n\t\t\t\t\t\tnew_tx_data <= 1'b1;\n\t\t\t\t\tend\n\t\t\t\t\telse\n\t\t\t\t\tbegin\n\t\t\t\t\t\ttx_sm <= `TX_HI_NIB;\n\t\t\t\t\t\ttx_data <= tx_char;\n\t\t\t\t\t\tnew_tx_data <= 1'b1;\n\t\t\t\t\tend\n\t\t\t\t// check if status byte should be transmitted\n\t\t\t\telse if ((send_stat_flag && bin_read_op && tx_end_p && bin_last_byte) ||\t// end of read command\n\t\t\t\t\t(send_stat_flag && bin_write_op && new_rx_data && bin_last_byte) ||\t// end of write command\n\t\t\t\t\t((main_sm == `MAIN_BIN_CMD) && new_rx_data && (rx_data[5:4] == `BIN_CMD_NOP)))\t// NOP\n\t\t\t\tbegin\n\t\t\t\t\t// send status byte - currently a constant\n\t\t\t\t\ttx_data <= 8'h5a;\n\t\t\t\t\tnew_tx_data <= 1'b1;\n\t\t\t\tend\n\t\t\t\telse\n\t\t\t\t\tnew_tx_data <= 1'b0;\n\n\t\t\t// wait for transmit to end\n\t\t\t`TX_HI_NIB:\n\t\t\t\tif (tx_end_p)\n\t\t\t\tbegin\n\t\t\t\t\ttx_sm <= `TX_LO_NIB;\n\t\t\t\t\ttx_data <= tx_char;\n\t\t\t\t\tnew_tx_data <= 1'b1;\n\t\t\t\tend\n\t\t\t\telse\n\t\t\t\t\tnew_tx_data <= 1'b0;\n\n\t\t\t// wait for transmit to end\n\t\t\t`TX_LO_NIB:\n\t\t\t\tif (tx_end_p)\n\t\t\t\tbegin\n\t\t\t\t\ttx_sm <= `TX_CHAR_CR;\n\t\t\t\t\ttx_data <= `CHAR_CR;\n\t\t\t\t\tnew_tx_data <= 1'b1;\n\t\t\t\tend\n\t\t\t\telse\n\t\t\t\t\tnew_tx_data <= 1'b0;\n\n\t\t\t// wait for transmit to end\n\t\t\t`TX_CHAR_CR:\n\t\t\t\tif (tx_end_p)\n\t\t\t\tbegin\n\t\t\t\t\ttx_sm <= `TX_CHAR_LF;\n\t\t\t\t\ttx_data <= `CHAR_LF;\n\t\t\t\t\tnew_tx_data <= 1'b1;\n\t\t\t\tend\n\t\t\t\telse\n\t\t\t\t\tnew_tx_data <= 1'b0;\n\n\t\t\t// wait for transmit to end\n\t\t\t`TX_CHAR_LF:\n\t\t\t\tbegin\n\t\t\t\t\tif (tx_end_p)\n\t\t\t\t\t\ttx_sm <= `TX_IDLE;\n\t\t\t\t\t// clear tx new data flag\n\t\t\t\t\tnew_tx_data <= 1'b0;\n\t\t\t\tend\n\n\t\t\t// return to idle\n\t\t\tdefault:\n\t\t\t\ttx_sm <= `TX_IDLE;\n\t\tendcase\nend\n\n// select the nibble to the nibble to character conversion\nalways @ (tx_sm or read_data_s)\nbegin\n\tcase (tx_sm)\n\t\t`TX_IDLE:\t\ttx_nibble = read_data_s[7:4];\n\t\t`TX_HI_NIB:\t\ttx_nibble = read_data_s[3:0];\n\t\tdefault:\t\ttx_nibble = read_data_s[7:4];\n\tendcase\nend\n\n// sampled tx_busy\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\ts_tx_busy <= 1'b0;\n\telse\n\t\ts_tx_busy <= tx_busy;\nend\n// tx end pulse\nassign tx_end_p = ~tx_busy & s_tx_busy;\n\n// character to nibble conversion\nalways @ (rx_data)\nbegin\n\tcase (rx_data)\n\t\t`CHAR_0:\t\t\t\tdata_nibble = 4'h0;\n\t\t`CHAR_1:\t\t\t\tdata_nibble = 4'h1;\n\t\t`CHAR_2:\t\t\t\tdata_nibble = 4'h2;\n\t\t`CHAR_3:\t\t\t\tdata_nibble = 4'h3;\n\t\t`CHAR_4:\t\t\t\tdata_nibble = 4'h4;\n\t\t`CHAR_5:\t\t\t\tdata_nibble = 4'h5;\n\t\t`CHAR_6:\t\t\t\tdata_nibble = 4'h6;\n\t\t`CHAR_7:\t\t\t\tdata_nibble = 4'h7;\n\t\t`CHAR_8:\t\t\t\tdata_nibble = 4'h8;\n\t\t`CHAR_9:\t\t\t\tdata_nibble = 4'h9;\n\t\t`CHAR_A_UP, `CHAR_a_LO:\tdata_nibble = 4'ha;\n\t\t`CHAR_B_UP, `CHAR_b_LO:\tdata_nibble = 4'hb;\n\t\t`CHAR_C_UP, `CHAR_c_LO:\tdata_nibble = 4'hc;\n\t\t`CHAR_D_UP, `CHAR_d_LO:\tdata_nibble = 4'hd;\n\t\t`CHAR_E_UP, `CHAR_e_LO:\tdata_nibble = 4'he;\n\t\t`CHAR_F_UP, `CHAR_f_LO:\tdata_nibble = 4'hf;\n\t\tdefault:\t\t\t\tdata_nibble = 4'hf;\n\tendcase\nend\n\n// nibble to character conversion\nalways @ (tx_nibble)\nbegin\n\tcase (tx_nibble)\n\t\t4'h0:\ttx_char = `CHAR_0;\n\t\t4'h1:\ttx_char = `CHAR_1;\n\t\t4'h2:\ttx_char = `CHAR_2;\n\t\t4'h3:\ttx_char = `CHAR_3;\n\t\t4'h4:\ttx_char = `CHAR_4;\n\t\t4'h5:\ttx_char = `CHAR_5;\n\t\t4'h6:\ttx_char = `CHAR_6;\n\t\t4'h7:\ttx_char = `CHAR_7;\n\t\t4'h8:\ttx_char = `CHAR_8;\n\t\t4'h9:\ttx_char = `CHAR_9;\n\t\t4'ha:\ttx_char = `CHAR_A_UP;\n\t\t4'hb:\ttx_char = `CHAR_B_UP;\n\t\t4'hc:\ttx_char = `CHAR_C_UP;\n\t\t4'hd:\ttx_char = `CHAR_D_UP;\n\t\t4'he:\ttx_char = `CHAR_E_UP;\n\t\tdefault: tx_char = `CHAR_F_UP;\n\tendcase\nend\n\nendmodule\n//---------------------------------------------------------------------------------------\n//\t\t\t\t\t\tTh.. Th.. Th.. That's all folks !!!\n//---------------------------------------------------------------------------------------\n"
  },
  {
    "path": "tests/designs/uart2bus/verilog/uart_rx.v",
    "content": "//---------------------------------------------------------------------------------------\n// uart receive module\n//\n//---------------------------------------------------------------------------------------\n\nmodule uart_rx\n(\n\tclock, reset,\n\tce_16, ser_in,\n\trx_data, new_rx_data\n);\n//---------------------------------------------------------------------------------------\n// modules inputs and outputs\ninput \t\t\tclock;\t\t\t// global clock input\ninput \t\t\treset;\t\t\t// global reset input\ninput\t\t\tce_16;\t\t\t// baud rate multiplied by 16 - generated by baud module\ninput\t\t\tser_in;\t\t\t// serial data input\noutput\t[7:0]\trx_data;\t\t// data byte received\noutput \t\t\tnew_rx_data;\t// signs that a new byte was received\n\n// internal wires\nwire ce_1;\t\t// clock enable at bit rate\nwire ce_1_mid;\t// clock enable at the middle of each bit - used to sample data\n\n// internal registers\nreg\t[7:0] rx_data;\nreg\tnew_rx_data;\nreg [1:0] in_sync;\nreg rx_busy;\nreg [3:0]\tcount16;\nreg [3:0]\tbit_count;\nreg [7:0]\tdata_buf;\n//---------------------------------------------------------------------------------------\n// module implementation\n// input async input is sampled twice\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tin_sync <= 2'b11;\n\telse\n\t\tin_sync <= {in_sync[0], ser_in};\nend\n\n// a counter to count 16 pulses of ce_16 to generate the ce_1 and ce_1_mid pulses.\n// this counter is used to detect the start bit while the receiver is not receiving and\n// signs the sampling cycle during reception.\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tcount16 <= 4'b0;\n\telse if (ce_16)\n\tbegin\n\t\tif (rx_busy | (in_sync[1] == 1'b0))\n\t\t\tcount16 <= count16 + 4'b1;\n\t\telse\n\t\t\tcount16 <= 4'b0;\n\tend\nend\n\n// ce_1 pulse indicating expected end of current bit\nassign ce_1 = (count16 == 4'b1111) & ce_16;\n// ce_1_mid pulse indication the sampling clock cycle of the current data bit\nassign ce_1_mid = (count16 == 4'b0111) & ce_16;\n\n// receiving busy flag\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\trx_busy <= 1'b0;\n\telse if (~rx_busy & ce_1_mid)\n\t\trx_busy <= 1'b1;\n\telse if (rx_busy & (bit_count == 4'h8) & ce_1_mid)\n\t\trx_busy <= 1'b0;\nend\n\n// bit counter\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tbit_count <= 4'h0;\n\telse if (~rx_busy)\n\t\tbit_count <= 4'h0;\n\telse if (rx_busy & ce_1_mid)\n\t\tbit_count <= bit_count + 4'h1;\nend\n\n// data buffer shift register\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tdata_buf <= 8'h0;\n\telse if (rx_busy & ce_1_mid)\n\t\tdata_buf <= {in_sync[1], data_buf[7:1]};\nend\n\n// data output and flag\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\tbegin\n\t\trx_data <= 8'h0;\n\t\tnew_rx_data <= 1'b0;\n\tend\n\telse if (rx_busy & (bit_count == 4'h8) & ce_1)\n\tbegin\n\t\trx_data <= data_buf;\n\t\tnew_rx_data <= 1'b1;\n\tend\n\telse\n\t\tnew_rx_data <= 1'b0;\nend\n\nendmodule\n//---------------------------------------------------------------------------------------\n//\t\t\t\t\t\tTh.. Th.. Th.. That's all folks !!!\n//---------------------------------------------------------------------------------------\n"
  },
  {
    "path": "tests/designs/uart2bus/verilog/uart_top.v",
    "content": "//---------------------------------------------------------------------------------------\n// uart top level module\n//\n//---------------------------------------------------------------------------------------\n\nmodule uart_top\n(\n\t// global signals\n\tclock, reset,\n\t// uart serial signals\n\tser_in, ser_out,\n\t// transmit and receive internal interface signals\n\trx_data, new_rx_data,\n\ttx_data, new_tx_data, tx_busy,\n\t// baud rate configuration register - see baud_gen.v for details\n\tbaud_freq, baud_limit,\n\tbaud_clk\n);\n//---------------------------------------------------------------------------------------\n// modules inputs and outputs\ninput \t\t\tclock;\t\t\t// global clock input\ninput \t\t\treset;\t\t\t// global reset input\ninput\t\t\tser_in;\t\t\t// serial data input\noutput\t\t\tser_out;\t\t// serial data output\ninput\t[7:0]\ttx_data;\t\t// data byte to transmit\ninput\t\t\tnew_tx_data;\t// asserted to indicate that there is a new data byte for transmission\noutput \t\t\ttx_busy;\t\t// signs that transmitter is busy\noutput\t[7:0]\trx_data;\t\t// data byte received\noutput \t\t\tnew_rx_data;\t// signs that a new byte was received\ninput\t[11:0]\tbaud_freq;\t// baud rate setting registers - see header description\ninput\t[15:0]\tbaud_limit;\noutput\t\t\tbaud_clk;\n\n// internal wires\nwire ce_16;\t\t// clock enable at bit rate\n\nassign baud_clk = ce_16;\n//---------------------------------------------------------------------------------------\n// module implementation\n// baud rate generator module\nbaud_gen baud_gen_1\n(\n\t.clock(clock), .reset(reset),\n\t.ce_16(ce_16), .baud_freq(baud_freq), .baud_limit(baud_limit)\n);\n\n// uart receiver\nuart_rx uart_rx_1\n(\n\t.clock(clock), .reset(reset),\n\t.ce_16(ce_16), .ser_in(ser_in),\n\t.rx_data(rx_data), .new_rx_data(new_rx_data)\n);\n\n// uart transmitter\nuart_tx  uart_tx_1\n(\n\t.clock(clock), .reset(reset),\n\t.ce_16(ce_16), .tx_data(tx_data), .new_tx_data(new_tx_data),\n\t.ser_out(ser_out), .tx_busy(tx_busy)\n);\n\nendmodule\n//---------------------------------------------------------------------------------------\n//\t\t\t\t\t\tTh.. Th.. Th.. That's all folks !!!\n//---------------------------------------------------------------------------------------\n"
  },
  {
    "path": "tests/designs/uart2bus/verilog/uart_tx.v",
    "content": "//---------------------------------------------------------------------------------------\n// uart transmit module\n//\n//---------------------------------------------------------------------------------------\n\nmodule uart_tx\n(\n\tclock, reset,\n\tce_16, tx_data, new_tx_data,\n\tser_out, tx_busy\n);\n//---------------------------------------------------------------------------------------\n// modules inputs and outputs\ninput \t\t\tclock;\t\t\t// global clock input\ninput \t\t\treset;\t\t\t// global reset input\ninput\t\t\tce_16;\t\t\t// baud rate multiplied by 16 - generated by baud module\ninput\t[7:0]\ttx_data;\t\t// data byte to transmit\ninput\t\t\tnew_tx_data;\t// asserted to indicate that there is a new data byte for transmission\noutput\t\t\tser_out;\t\t// serial data output\noutput \t\t\ttx_busy;\t\t// signs that transmitter is busy\n\n// internal wires\nwire ce_1;\t\t// clock enable at bit rate\n\n// internal registers\nreg ser_out;\nreg tx_busy;\nreg [3:0]\tcount16;\nreg [3:0]\tbit_count;\nreg [8:0]\tdata_buf;\n//---------------------------------------------------------------------------------------\n// module implementation\n// a counter to count 16 pulses of ce_16 to generate the ce_1 pulse\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tcount16 <= 4'b0;\n\telse if (tx_busy & ce_16)\n\t\tcount16 <= count16 + 4'b1;\n\telse if (~tx_busy)\n\t\tcount16 <= 4'b0;\nend\n\n// ce_1 pulse indicating output data bit should be updated\nassign ce_1 = (count16 == 4'b1111) & ce_16;\n\n// tx_busy flag\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\ttx_busy <= 1'b0;\n\telse if (~tx_busy & new_tx_data)\n\t\ttx_busy <= 1'b1;\n\telse if (tx_busy & (bit_count == 4'h9) & ce_1)\n\t\ttx_busy <= 1'b0;\nend\n\n// output bit counter\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tbit_count <= 4'h0;\n\telse if (tx_busy & ce_1)\n\t\tbit_count <= bit_count + 4'h1;\n\telse if (~tx_busy)\n\t\tbit_count <= 4'h0;\nend\n\n// data shift register\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tdata_buf <= 9'b0;\n\telse if (~tx_busy)\n\t\tdata_buf <= {tx_data, 1'b0};\n\telse if (tx_busy & ce_1)\n\t\tdata_buf <= {1'b1, data_buf[8:1]};\nend\n\n// output data bit\nalways @ (posedge clock or posedge reset)\nbegin\n\tif (reset)\n\t\tser_out <= 1'b1;\n\telse if (tx_busy)\n\t\tser_out <= data_buf[0];\n\telse\n\t\tser_out <= 1'b1;\nend\n\nendmodule\n//---------------------------------------------------------------------------------------\n//\t\t\t\t\t\tTh.. Th.. Th.. That's all folks !!!\n//---------------------------------------------------------------------------------------\n"
  },
  {
    "path": "tests/designs/uart2bus/vhdl/baudGen.vhd",
    "content": "-----------------------------------------------------------------------------------------\n-- baud rate generator for uart\n--\n-- this module has been changed to receive the baud rate dividing counter from registers.\n-- the two registers should be calculated as follows:\n-- first register:\n--              baud_freq = 16*baud_rate / gcd(global_clock_freq, 16*baud_rate)\n-- second register:\n--              baud_limit = (global_clock_freq / gcd(global_clock_freq, 16*baud_rate)) - baud_freq\n--\n-----------------------------------------------------------------------------------------\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.std_logic_unsigned.all;\n\nentity baudGen is\n  port ( clr       : in  std_logic;                     -- global reset input\n         clk       : in  std_logic;                     -- global clock input\n         -- baudFreq = 16 * baudRate / gcd(clkFreq, 16 * baudRate)\n         baudFreq  : in  std_logic_vector(11 downto 0); -- baud rate setting registers - see header description\n         -- baudLimit = clkFreq / gcd(clkFreq, 16 * baudRate) - baudFreq\n         baudLimit : in  std_logic_vector(15 downto 0); -- baud rate setting registers - see header description\n         ce16      : out std_logic);                    -- baud rate multiplied by 16\nend baudGen;\n\narchitecture Behavioral of baudGen is\n\n  signal counter : std_logic_vector(15 downto 0);\n\n  begin\n    -- baud divider counter\n    -- clock divider output\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        counter <= (others => '0');\n        ce16 <= '0';\n      elsif (rising_edge(clk)) then\n        if (counter >= baudLimit) then\n          counter <= counter - baudLimit;\n          ce16 <= '1';\n        else\n          counter <= counter + baudFreq;\n          ce16 <= '0';\n        end if;\n      end if;\n    end process;\n  end Behavioral;\n"
  },
  {
    "path": "tests/designs/uart2bus/vhdl/uart2BusTop.vhd",
    "content": "-----------------------------------------------------------------------------------------\n-- uart to internal bus top module\n--\n-----------------------------------------------------------------------------------------\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n\nuse work.uart2BusTop_pkg.all;\n\nentity uart2BusTop is\n  generic ( AW : integer := 16);\n  port ( -- global signals\n         clr          : in  STD_LOGIC;                          -- global reset input\n         clk          : in  STD_LOGIC;                          -- global clock input\n         -- uart serial signals\n         serIn        : in  STD_LOGIC;                          -- serial data input\n         serOut       : out STD_LOGIC;                          -- serial data output\n         -- internal bus to register file\n         intAccessReq : out std_logic;                          --\n         intAccessGnt : in  std_logic;                          --\n         intRdData    : in  STD_LOGIC_VECTOR (7 downto 0);      -- data read from register file\n         intAddress   : out STD_LOGIC_VECTOR (AW - 1 downto 0); -- address bus to register file\n         intWrData    : out STD_LOGIC_VECTOR (7 downto 0);      -- write data to register file\n         intWrite     : out STD_LOGIC;                          -- write control to register file\n         intRead      : out STD_LOGIC);                         -- read control to register file\nend uart2BusTop;\n\narchitecture Behavioral of uart2BusTop is\n\n  -- baud rate configuration, see baudGen.vhd for more details.\n  -- baud rate generator parameters for 115200 baud on 25MHz clock\n  constant baudFreq     : std_logic_vector(11 downto 0) := x\"480\";\n  constant baudLimit    : std_logic_vector(15 downto 0) := x\"3889\";\n  signal   txData       : std_logic_vector(7 downto 0); -- data byte to transmit\n  signal   newTxData    : std_logic;                    -- asserted to indicate that there is a new data byte for transmission\n  signal   txBusy       : std_logic;                    -- signs that transmitter is busy\n  signal   rxData       : std_logic_vector(7 downto 0); -- data byte received\n  signal   newRxData    : std_logic;                    -- signs that a new byte was received\n\n  begin\n    -- uart top module instance\n    ut : uartTop\n      port map (\n        clr => clr,\n        clk => clk,\n        serIn => serIn,\n        txData => txData,\n        newTxData => newTxData,\n        baudFreq => baudFreq,\n        baudLimit => baudLimit,\n        serOut => serOut,\n        txBusy => txBusy,\n        rxData => rxData,\n        newRxData => newRxData,\n        baudClk => open);\n    -- uart parser instance\n    up : uartParser\n      generic map (\n        AW => AW)\n      port map (\n        clr => clr,\n        clk => clk,\n        txBusy => txBusy,\n        rxData => rxData,\n        newRxData => newRxData,\n        intRdData => intRdData,\n        txData => txData,\n        newTxData => newTxData,\n        intReq => intAccessReq,\n        intGnt => intAccessGnt,\n        intAddress => intAddress,\n        intWrData => intWrData,\n        intWrite => intWrite,\n        intRead => intRead);\n\n  end Behavioral;\n"
  },
  {
    "path": "tests/designs/uart2bus/vhdl/uart2BusTop_pkg.vhd",
    "content": "library ieee;\nuse ieee.std_logic_1164.all;\n\npackage uart2BusTop_pkg is\n\n  component baudGen\n    port (\n      clr       : in  std_logic;\n      clk       : in  std_logic;\n      baudFreq  : in  std_logic_vector(11 downto 0);\n      baudLimit : in  std_logic_vector(15 downto 0);\n      ce16      : out std_logic);\n  end component;\n\n  component uartTx\n    port (\n      clr : in  std_logic;\n      clk : in  std_logic;\n      ce16 : in  std_logic;\n      txData : in  std_logic_vector(7 downto 0);\n      newTxData : in  std_logic;\n      serOut : out  std_logic;\n      txBusy : out  std_logic);\n  end component;\n\n  component uartRx\n    port (\n      clr       : in  std_logic;\n      clk       : in  std_logic;\n      ce16      : in  std_logic;\n      serIn     : in  std_logic;\n      rxData    : out std_logic_vector(7 downto 0);\n      newRxData : out std_logic);\n  end component;\n\n  component uartTop\n    port ( clr       : in  std_logic;\n           clk       : in  std_logic;\n           serIn     : in  std_logic;\n           txData    : in  std_logic_vector(7 downto 0);\n           newTxData : in  std_logic;\n           baudFreq  : in  std_logic_vector(11 downto 0);\n           baudLimit : in  std_logic_vector(15 downto 0);\n           serOut    : out std_logic;\n           txBusy    : out std_logic;\n           rxData    : out std_logic_vector(7 downto 0);\n           newRxData : out std_logic;\n           baudClk   : out std_logic);\n  end component;\n\n  component uartParser\n    generic ( AW : integer := 8);\n    port ( clr        : in  std_logic;\n           clk        : in  std_logic;\n           txBusy     : in  std_logic;\n           rxData     : in  std_logic_vector(7 downto 0);\n           newRxData  : in  std_logic;\n           intRdData  : in  std_logic_vector(7 downto 0);\n           txData     : out std_logic_vector(7 downto 0);\n           newTxData  : out std_logic;\n           intReq     : out std_logic;\n           intGnt     : in  std_logic;\n           intAddress : out std_logic_vector(AW - 1 downto 0);\n           intWrData  : out std_logic_vector(7 downto 0);\n           intWrite   : out std_logic;\n           intRead    : out std_logic);\n  end component;\n\n  component uart2BusTop\n    generic\n    (\n      AW : integer := 8\n    );\n    port\n    (\n      clr          : in  std_logic;\n      clk          : in  std_logic;\n      serIn        : in  std_logic;\n      serOut       : out std_logic;\n      intAccessReq : out std_logic;\n      intAccessGnt : in  std_logic;\n      intRdData    : in  std_logic_vector(7 downto 0);\n      intAddress   : out std_logic_vector(AW - 1 downto 0);\n      intWrData    : out std_logic_vector(7 downto 0);\n      intWrite     : out std_logic;\n      intRead      : out std_logic\n    );\n  end component;\n\nend uart2BusTop_pkg;\n"
  },
  {
    "path": "tests/designs/uart2bus/vhdl/uartParser.vhd",
    "content": "-----------------------------------------------------------------------------------------\n-- uart parser module\n--\n-----------------------------------------------------------------------------------------\nlibrary ieee;\nuse ieee.std_logic_1164.ALL;\nuse ieee.std_logic_unsigned.ALL;\n\nentity uartParser is\n  generic ( -- parameters\n            AW : integer := 8);\n  port ( -- global signals\n         clr        : in  std_logic;                         -- global reset input\n         clk        : in  std_logic;                         -- global clock input\n\t -- transmit and receive internal interface signals from uart interface\n         txBusy     : in  std_logic;                         -- signs that transmitter is busy\n         rxData     : in  std_logic_vector(7 downto 0);      -- data byte received\n         newRxData  : in  std_logic;                         -- signs that a new byte was received\n         txData     : out std_logic_vector(7 downto 0);      -- data byte to transmit\n         newTxData  : out std_logic;                         -- asserted to indicate that there is a new data byte for transmission\n\t -- internal bus to register file\n         intReq     : out std_logic;                         --\n         intGnt     : in  std_logic;                         --\n         intRdData  : in  std_logic_vector(7 downto 0);      -- data read from register file\n         intAddress : out std_logic_vector(AW - 1 downto 0); -- address bus to register file\n         intWrData  : out std_logic_vector(7 downto 0);      -- write data to register file\n         intWrite   : out std_logic;                         -- write control to register file\n         intRead    : out std_logic);                        -- read control to register file\nend uartParser;\n\narchitecture Behavioral of uartParser is\n\n  -- internal constants\n  -- main (receive) state machine states\n  signal   mainSm         : std_logic_vector(3 downto 0); -- main state machine\n  constant mainIdle       : std_logic_vector(mainSm'range) := \"0000\";\n  constant mainWhite1     : std_logic_vector(mainSm'range) := \"0001\";\n  constant mainData       : std_logic_vector(mainSm'range) := \"0010\";\n  constant mainWhite2     : std_logic_vector(mainSm'range) := \"0011\";\n  constant mainAddr       : std_logic_vector(mainSm'range) := \"0100\";\n  constant mainEol        : std_logic_vector(mainSm'range) := \"0101\";\n  -- binary mode extension states\n  constant mainBinCmd     : std_logic_vector(mainSm'range) := \"1000\";\n  constant mainBinAdrh    : std_logic_vector(mainSm'range) := \"1001\";\n  constant mainBinAdrl    : std_logic_vector(mainSm'range) := \"1010\";\n  constant mainBinLen     : std_logic_vector(mainSm'range) := \"1011\";\n  constant mainBinData    : std_logic_vector(mainSm'range) := \"1100\";\n\n  -- transmit state machine\n  signal   txSm           : std_logic_vector(2 downto 0); -- transmit state machine\n  constant txIdle         : std_logic_vector(txSm'range) := \"000\";\n  constant txHiNib        : std_logic_vector(txSm'range) := \"001\";\n  constant txLoNib        : std_logic_vector(txSm'range) := \"100\";\n  constant txCharCR       : std_logic_vector(txSm'range) := \"101\";\n  constant txCharLF       : std_logic_vector(txSm'range) := \"110\";\n\n  -- define characters used by the parser\n  constant charNul        : std_logic_vector(7 downto 0) := x\"00\";\n  constant charTab        : std_logic_vector(7 downto 0) := x\"09\";\n  constant charLF         : std_logic_vector(7 downto 0) := x\"0A\";\n  constant charCR         : std_logic_vector(7 downto 0) := x\"0D\";\n  constant charSpace      : std_logic_vector(7 downto 0) := x\"20\";\n  constant charZero       : std_logic_vector(7 downto 0) := x\"30\";\n  constant charOne        : std_logic_vector(7 downto 0) := x\"31\";\n  constant charTwo        : std_logic_vector(7 downto 0) := x\"32\";\n  constant charThree      : std_logic_vector(7 downto 0) := x\"33\";\n  constant charFour       : std_logic_vector(7 downto 0) := x\"34\";\n  constant charFive       : std_logic_vector(7 downto 0) := x\"35\";\n  constant charSix        : std_logic_vector(7 downto 0) := x\"36\";\n  constant charSeven      : std_logic_vector(7 downto 0) := x\"37\";\n  constant charEight      : std_logic_vector(7 downto 0) := x\"38\";\n  constant charNine       : std_logic_vector(7 downto 0) := x\"39\";\n  constant charAHigh      : std_logic_vector(7 downto 0) := x\"41\";\n  constant charBHigh      : std_logic_vector(7 downto 0) := x\"42\";\n  constant charCHigh      : std_logic_vector(7 downto 0) := x\"43\";\n  constant charDHigh      : std_logic_vector(7 downto 0) := x\"44\";\n  constant charEHigh      : std_logic_vector(7 downto 0) := x\"45\";\n  constant charFHigh      : std_logic_vector(7 downto 0) := x\"46\";\n  constant charRHigh      : std_logic_vector(7 downto 0) := x\"52\";\n  constant charWHigh      : std_logic_vector(7 downto 0) := x\"57\";\n  constant charALow       : std_logic_vector(7 downto 0) := x\"61\";\n  constant charBLow       : std_logic_vector(7 downto 0) := x\"62\";\n  constant charCLow       : std_logic_vector(7 downto 0) := x\"63\";\n  constant charDLow       : std_logic_vector(7 downto 0) := x\"64\";\n  constant charELow       : std_logic_vector(7 downto 0) := x\"65\";\n  constant charFLow       : std_logic_vector(7 downto 0) := x\"66\";\n  constant charRLow       : std_logic_vector(7 downto 0) := x\"72\";\n  constant charWLow       : std_logic_vector(7 downto 0) := x\"77\";\n\n  -- binary extension mode commands - the command is indicated by bits 5:4 of the command byte\n  constant binCmdNop      : std_logic_vector(1 downto 0) := \"00\";\n  constant binCmdRead     : std_logic_vector(1 downto 0) := \"01\";\n  constant binCmdWrite    : std_logic_vector(1 downto 0) := \"10\";\n\n  signal   dataInHexRange : std_logic;                          -- indicates that the received data is in the range of hex number\n  signal   binLastByte    : std_logic;                          -- last byte flag indicates that the current byte in the command is the last\n  signal   txEndP         : std_logic;                          -- transmission end pulse\n  signal   readOp         : std_logic;                          -- read operation flag\n  signal   writeOp        : std_logic;                          -- write operation flag\n  signal   binReadOp      : std_logic;                          -- binary mode read operation flag\n  signal   binWriteOp     : std_logic;                          -- binary mode write operation flag\n  signal   sendStatFlag   : std_logic;                          -- send status flag\n  signal   addrAutoInc    : std_logic;                          -- address auto increment mode\n  signal   dataParam      : std_logic_vector(7 downto 0);       -- operation data parameter\n  signal   dataNibble     : std_logic_vector(3 downto 0);       -- data nibble from received character\n  signal   addrParam      : std_logic_vector(15 downto 0);      -- operation address parameter\n  signal   addrNibble     : std_logic_vector(3 downto 0);       -- data nibble from received character\n  signal   binByteCount   : std_logic_vector(7 downto 0);       -- binary mode byte counter\n  signal   iIntAddress    : std_logic_vector(intAddress'range); --\n  signal   iWriteReq      : std_logic;                          --\n  signal   iIntWrite      : std_logic;                          --\n  signal   readDone       : std_logic;                          -- internally generated read done flag\n  signal   readDoneS      : std_logic;                          -- sampled read done\n  signal   readDataS      : std_logic_vector(7 downto 0);       -- sampled read data\n  signal   iReadReq       : std_logic;                          --\n  signal   iIntRead       : std_logic;                          --\n  signal   txChar         : std_logic_vector(7 downto 0);       -- transmit byte from nibble to character conversion\n  signal   sTxBusy        : std_logic;                          -- sampled tx_busy for falling edge detection\n  signal   txNibble       : std_logic_vector(3 downto 0);       -- nibble value for transmission\n\n  -- module implementation\n  -- main state machine\n  begin\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        mainSm <= mainIdle;\n      elsif (rising_edge(clk)) then\n        if (newRxData = '1') then\n          case mainSm is\n            -- wait for a read ('r') or write ('w') command\n            -- binary extension - an all zeros byte enabled binary commands\n            when mainIdle =>\n              -- check received character\n              if (rxData = charNul) then\n                -- an all zeros received byte enters binary mode\n                mainSm <= mainBinCmd;\n              elsif ((rxData = charRLow) or (rxData = charRHigh)) then\n                -- on read wait to receive only address field\n                mainSm <= mainWhite2;\n              elsif ((rxData = charWLow) or (rxData = charWHigh)) then\n                -- on write wait to receive data and address\n                mainSm <= mainWhite1;\n              elsif ((rxData = charCR) or (rxData = charLF)) then\n                -- on new line sta in idle\n                mainSm <= mainIdle;\n              else\n                -- any other character wait to end of line (EOL)\n                mainSm <= mainEol;\n              end if;\n            -- wait for white spaces till first data nibble\n            when mainWhite1 =>\n              -- wait in this case until any white space character is received. in any\n              -- valid character for data value switch to data state. a new line or carriage\n              -- return should reset the state machine to idle.\n              -- any other character transitions the state machine to wait for EOL.\n              if ((rxData = charSpace) or (rxData = charTab)) then\n                mainSm <= mainWhite1;\n              elsif (dataInHexRange = '1') then\n                mainSm <= mainData;\n              elsif ((rxData = charCR) or (rxData = charLF)) then\n                mainSm <= mainIdle;\n              else\n                mainSm <= mainEol;\n              end if;\n            -- receive data field\n            when mainData =>\n              -- wait while data in hex range. white space transition to wait white 2 state.\n              -- CR and LF resets the state machine. any other value cause state machine to\n              -- wait til end of line.\n              if (dataInHexRange = '1') then\n                mainSm <= mainData;\n              elsif ((rxData = charSpace) or (rxData = charTab)) then\n                mainSm <= mainWhite2;\n              elsif ((rxData = charCR) or (rxData = charLF)) then\n                mainSm <= mainIdle;\n              else\n                mainSm <= mainEol;\n              end if;\n            -- wait for white spaces till first address nibble\n            when mainWhite2 =>\n              -- similar to MAIN_WHITE1\n              if ((rxData = charSpace) or (rxData = charTab)) then\n                mainSm <= mainWhite2;\n              elsif (dataInHexRange = '1') then\n                mainSm <= mainAddr;\n              elsif ((rxData = charCR) or (rxData = charLF)) then\n                mainSm <= mainIdle;\n              else\n                mainSm <= mainEol;\n              end if;\n            -- receive address field\n            when mainAddr =>\n              -- similar to MAIN_DATA\n              if (dataInHexRange = '1') then\n                mainSm <= mainAddr;\n              elsif ((rxData = charCR) or (rxData = charLF)) then\n                mainSm <= mainIdle;\n              else\n                mainSm <= mainEol;\n              end if;\n            -- wait to EOL\n            when mainEol =>\n              -- wait for CR or LF to move back to idle\n              if ((rxData = charCR) or (rxData = charLF)) then\n                mainSm <= mainIdle;\n              end if;\n            -- binary extension\n            -- wait for command - one byte\n            when mainBinCmd =>\n              -- check if command is a NOP command\n              if (rxData(5 downto 4) = binCmdNop) then\n                -- if NOP command then switch back to idle state\n                mainSm <= mainIdle;\n              else\n                -- not a NOP command, continue receiving parameters\n                mainSm <= mainBinAdrh;\n              end if;\n            -- wait for address parameter - two bytes\n            -- high address byte\n            when mainBinAdrh =>\n              -- switch to next state\n              mainSm <= mainBinAdrl;\n            -- low address byte\n            when mainBinAdrl =>\n              -- switch to next state\n              mainSm <= mainBinLen;\n            -- wait for length parameter - one byte\n            when mainBinLen =>\n              -- check if write command else command reception ended\n              if (binWriteOp = '1') then\n                -- wait for write data\n                mainSm <= mainBinData;\n              else\n                -- command reception has ended\n                mainSm <= mainIdle;\n              end if;\n            -- on write commands wait for data till end of buffer as specified by length parameter\n            when mainBinData =>\n              -- if this is the last data byte then return to idle\n              if (binLastByte = '1') then\n                mainSm <= mainIdle;\n              end if;\n            -- go to idle\n            when others =>\n              mainSm <= mainIdle;\n          end case;\n        end if;\n      end if;\n    end process;\n    -- read operation flag\n    -- write operation flag\n    -- binary mode read operation flag\n    -- binary mode write operation flag\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        readOp <= '0';\n        writeOp <= '0';\n        binReadOp <= '0';\n        binWriteOp <= '0';\n      elsif (rising_edge(clk)) then\n        if ((mainSm = mainIdle) and (newRxData = '1')) then\n          -- the read operation flag is set when a read command is received in idle state and cleared\n          -- if any other character is received during that state.\n          if ((rxData = charRLow) or (rxData = charRHigh)) then\n            readOp <= '1';\n          else\n            readOp <= '0';\n          end if;\n          -- the write operation flag is set when a write command is received in idle state and cleared\n          -- if any other character is received during that state.\n          if ((rxData = charWLow) or (rxData = charWHigh)) then\n            writeOp <= '1';\n          else\n            writeOp <= '0';\n          end if;\n        end if;\n        if ((mainSm = mainBinCmd) and (newRxData = '1') and (rxData(5 downto 4) = binCmdRead)) then\n          -- read command is started on reception of a read command\n          binReadOp <= '1';\n        elsif ((binReadOp = '1') and (txEndP = '1') and (binLastByte = '1')) then\n          -- read command ends on transmission of the last byte read\n          binReadOp <= '0';\n        end if;\n        if ((mainSm = mainBinCmd) and (newRxData = '1') and (rxData(5 downto 4) = binCmdWrite)) then\n          -- write command is started on reception of a write command\n          binWriteOp <= '1';\n        elsif ((mainSm = mainBinData) and (newRxData = '1') and (binLastByte = '1')) then\n          binWriteOp <= '0';\n        end if;\n      end if;\n    end process;\n    -- send status flag - used only in binary extension mode\n    -- address auto increment - used only in binary extension mode\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        sendStatFlag <= '0';\n        addrAutoInc <= '0';\n      elsif (rising_edge(clk)) then\n        if ((mainSm = mainBinCmd) and (newRxData = '1')) then\n          -- check if a status byte should be sent at the end of the command\n          sendStatFlag <= rxData(0);\n          -- check if address should be automatically incremented or not.\n          -- Note that when rx_data[1] is set, address auto increment is disabled.\n          addrAutoInc <= not(rxData(1));\n        end if;\n      end if;\n    end process;\n    -- operation data parameter\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        dataParam <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if ((mainSm = mainWhite1) and (newRxData = '1') and (dataInHexRange = '1')) then\n          dataParam <= \"0000\" & dataNibble;\n        elsif ((mainSm = mainData) and (newRxData = '1') and (dataInHexRange = '1')) then\n          dataParam <= dataParam(3 downto 0) & dataNibble;\n        end if;\n      end if;\n    end process;\n    -- operation address parameter\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        addrParam <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if ((mainSm = mainWhite2) and (newRxData = '1') and (dataInHexRange = '1')) then\n          addrParam <= x\"000\" & dataNibble;\n        elsif ((mainSm = mainAddr) and (newRxData = '1') and (dataInHexRange = '1')) then\n          addrParam <= addrParam(11 downto 0) & dataNibble;\n        -- binary extension\n        elsif (mainSm = mainBinAdrh) then\n          addrParam(15 downto 8) <= rxData;\n        elsif (mainSm = mainBinAdrl) then\n          addrParam(7 downto 0) <= rxData;\n        end if;\n      end if;\n    end process;\n    -- binary mode command byte counter is loaded with the length parameter and counts down to zero.\n    -- NOTE: a value of zero for the length parameter indicates a command of 256 bytes.\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        binByteCount <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if ((mainSm = mainBinLen) and (newRxData = '1')) then\n          binByteCount <= rxData;\n        elsif (((mainSm = mainBinData) and (binWriteOp = '1') and (newRxData = '1')) or ((binReadOp = '1') and (txEndP = '1'))) then\n          -- byte counter is updated on every new data received in write operations and for every\n          -- byte transmitted for read operations.\n          binByteCount <= binByteCount - 1;\n        end if;\n      end if;\n    end process;\n    -- internal write control and data\n    -- internal read control\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        iReadReq <= '0';\n        iIntRead <= '0';\n        iWriteReq <= '0';\n        iIntWrite <= '0';\n        intWrData <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if ((mainSm = mainAddr) and (writeOp = '1') and (newRxData = '1') and (dataInHexRange = '0')) then\n          iWriteReq <= '1';\n          intWrData <= dataParam;\n        -- binary extension mode\n        elsif ((mainSm = mainBinData) and (binWriteOp = '1') and (newRxData = '1')) then\n          iWriteReq <= '1';\n          intWrData <= rxData;\n        elsif ((intGnt = '1') and (iWriteReq = '1')) then\n          iWriteReq <= '0';\n          iIntWrite <= '1';\n        else\n          iIntWrite <= '0';\n        end if;\n        if ((mainSm = mainAddr) and (readOp = '1') and (newRxData = '1') and (dataInHexRange = '0')) then\n          iReadReq <= '1';\n        -- binary extension\n        elsif ((mainSm = mainBinLen) and (binReadOp = '1') and (newRxData = '1')) then\n          -- the first read request is issued on reception of the length byte\n          iReadReq <= '1';\n        elsif ((binReadOp = '1') and (txEndP = '1') and (binLastByte = '0')) then\n          -- the next read requests are issued after the previous read value was transmitted and\n          -- this is not the last byte to be read.\n          iReadReq <= '1';\n        elsif ((intGnt = '1') and (iReadReq = '1')) then\n          iReadReq <= '0';\n          iIntRead <= '1';\n        else\n          iIntRead <= '0';\n        end if;\n      end if;\n    end process;\n    -- internal address\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        iIntAddress <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if ((mainSm = mainAddr) and (newRxData = '1') and (dataInHexRange = '0')) then\n          iIntAddress <= addrParam(AW - 1 downto 0);\n        -- binary extension\n        elsif ((mainSm = mainBinLen) and (newRxData = '1')) then\n          -- sample address parameter on reception of length byte\n          iIntAddress <= addrParam(AW - 1 downto 0);\n        elsif ((addrAutoInc = '1') and (((binReadOp = '1') and (txEndP = '1') and (binLastByte = '0')) or ((binWriteOp = '1') and (iIntWrite = '1')))) then\n          -- address is incremented on every read or write if enabled\n          iIntAddress <= iIntAddress + 1;\n        end if;\n      end if;\n    end process;\n    -- read done flag and sampled data read\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        readDone <= '0';\n        readDoneS <= '0';\n        readDataS <= (others => '0');\n      elsif (rising_edge(clk)) then\n        -- read done flag\n        readDone <= iIntRead;\n        -- sampled read done\n        readDoneS <= readDone;\n        -- sampled data read\n        if (readDone = '1') then\n          readDataS <= intRdData;\n        end if;\n      end if;\n    end process;\n    -- transmit state machine and control\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        txSm <= txIdle;\n        txData <= (others => '0');\n        newTxData <= '0';\n      elsif (rising_edge(clk)) then\n        case txSm is\n          -- wait for read done indication\n          when txIdle =>\n            -- on end of every read operation check how the data read should be transmitted\n            -- according to read type: ascii or binary.\n            if (readDoneS = '1') then\n              -- on binary mode read transmit byte value\n              if (binReadOp = '1') then\n                -- note that there is no need to change state\n                txData <= readDataS;\n                newTxData <= '1';\n              else\n                txSm <= txHiNib;\n                txData <= txChar;\n                newTxData <= '1';\n              end if;\n            -- check if status byte should be transmitted\n            elsif (((sendStatFlag = '1') and (binReadOp = '1') and (txEndP = '1') and (binLastByte = '1')) or ((sendStatFlag = '1') and (binWriteOp = '1') and (newRxData = '1') and (binLastByte = '1')) or ((mainSm = mainBinCmd) and (newRxData = '1') and (rxData(5 downto 4) = binCmdNop))) then\n              -- send status byte - currently a constant\n              txData <= x\"5A\";\n              newTxData <= '1';\n            else\n              newTxData <= '0';\n            end if;\n          when txHiNib =>\n            -- wait for transmit to end\n            if (txEndP = '1') then\n              txSm <= txLoNib;\n              txData <= txChar;\n              newTxData <= '1';\n            else\n              newTxData <= '0';\n            end if;\n          -- wait for transmit to end\n          when txLoNib =>\n            if (txEndP = '1') then\n              txSm <= txCharCR;\n              txData <= charCR;\n              newTxData <= '1';\n            else\n              newTxData <= '0';\n            end if;\n          -- wait for transmit to end\n          when txCharCR =>\n            if (txEndP = '1') then\n              txSm <= txCharLF;\n              txData <= charLF;\n              newTxData <= '1';\n            else\n              newTxData <= '0';\n            end if;\n          -- wait for transmit to end\n          when txCharLF =>\n            if (txEndP = '1') then\n              txSm <= txIdle;\n            end if;\n            -- clear tx new data flag\n            newTxData <= '0';\n          -- return to idle\n          when others =>\n            txSm <= txIdle;\n        end case;\n      end if;\n    end process;\n    -- sampled tx_busy\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        sTxBusy <= '1';\n      elsif (rising_edge(clk)) then\n        sTxBusy <= txBusy;\n      end if;\n    end process;\n    -- indicates that the received data is in the range of hex number\n    dataInHexRange <= '1' when (((rxData >= charZero) and (rxData <= charNine)) or\n                               ((rxData >= charAHigh) and (rxData <= charFHigh)) or\n                               ((rxData >= charALow) and (rxData <= charFLow))) else '0';\n    -- last byte in command flag\n    binLastByte <= '1' when (binByteCount = x\"01\") else '0';\n    -- select the nibble to the nibble to character conversion\n    txNibble <= readDataS(3 downto 0) when (txSm = txHiNib) else readDataS(7 downto 4);\n    -- tx end pulse\n    txEndP <= '1' when ((txBusy = '0') and (sTxBusy = '1')) else '0';\n    -- character to nibble conversion\n    with rxData select\n      dataNibble <= x\"0\" when charZero,\n                    x\"1\" when charOne,\n                    x\"2\" when charTwo,\n                    x\"3\" when charThree,\n                    x\"4\" when charFour,\n                    x\"5\" when charFive,\n                    x\"6\" when charSix,\n                    x\"7\" when charSeven,\n                    x\"8\" when charEight,\n                    x\"9\" when charNine,\n                    x\"A\" when charALow,\n                    x\"A\" when charAHigh,\n                    x\"B\" when charBLow,\n                    x\"B\" when charBHigh,\n                    x\"C\" when charCLow,\n                    x\"C\" when charCHigh,\n                    x\"D\" when charDLow,\n                    x\"D\" when charDHigh,\n                    x\"E\" when charELow,\n                    x\"E\" when charEHigh,\n                    x\"F\" when charFLow,\n                    x\"F\" when charFHigh,\n                    x\"F\" when others;\n    -- nibble to character conversion\n    with txNibble select\n      txChar <= charZero when x\"0\",\n                charOne when x\"1\",\n                charTwo when x\"2\",\n                charThree when x\"3\",\n                charFour when x\"4\",\n                charFive when x\"5\",\n                charSix when x\"6\",\n                charSeven when x\"7\",\n                charEight when x\"8\",\n                charNine when x\"9\",\n                charAHigh when x\"A\",\n                charBHigh when x\"B\",\n                charCHigh when x\"C\",\n                charDHigh when x\"D\",\n                charEHigh when x\"E\",\n                charFHigh when x\"F\",\n                charFHigh when others;\n    intAddress <= iIntAddress;\n    intWrite <= iIntWrite;\n    intRead <= iIntRead;\n    intReq <= '1' when (iReadReq = '1') else\n              '1' when (iWriteReq = '1') else '0';\n  end Behavioral;\n"
  },
  {
    "path": "tests/designs/uart2bus/vhdl/uartRx.vhd",
    "content": "-----------------------------------------------------------------------------------------\n-- uart receive module\n--\n-----------------------------------------------------------------------------------------\nlibrary ieee;\nuse ieee.std_logic_1164.ALL;\nuse ieee.std_logic_unsigned.ALL;\n\nentity uartRx is\n  port ( clr       : in  std_logic;                    -- global reset input\n         clk       : in  std_logic;                    -- global clock input\n         ce16      : in  std_logic;                    -- baud rate multiplied by 16 - generated by baud module\n         serIn     : in  std_logic;                    -- serial data input\n         rxData    : out std_logic_vector(7 downto 0); -- data byte received\n         newRxData : out std_logic);                   -- signs that a new byte was received\nend uartRx;\n\narchitecture Behavioral of uartRx is\n\n  signal ce1      : std_logic;                    -- clock enable at bit rate\n  signal ce1Mid   : std_logic;                    -- clock enable at the middle of each bit - used to sample data\n  signal inSync   : std_logic_vector(1 downto 0);\n  signal count16  : std_logic_vector(3 downto 0);\n  signal rxBusy   : std_logic;\n  signal bitCount : std_logic_vector(3 downto 0);\n  signal dataBuf  : std_logic_vector(7 downto 0);\n\n  begin\n    -- input async input is sampled twice\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        inSync <= (others => '1');\n      elsif (rising_edge(clk)) then\n        inSync <= inSync(0) & serIn;\n      end if;\n    end process;\n    -- a counter to count 16 pulses of ce_16 to generate the ce_1 and ce_1_mid pulses.\n    -- this counter is used to detect the start bit while the receiver is not receiving and\n    -- signs the sampling cycle during reception.\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        count16 <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if (ce16 = '1') then\n          if ((rxBusy = '1') or (inSync(1) = '0')) then\n            count16 <= count16 + 1;\n          else\n            count16 <= (others => '0');\n          end if;\n        end if;\n      end if;\n    end process;\n    -- receiving busy flag\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        rxBusy <= '0';\n      elsif (rising_edge(clk)) then\n        if ((rxBusy = '0') and (ce1Mid = '1')) then\n          rxBusy <= '1';\n        elsif ((rxBusy = '1') and (bitCount = \"1000\") and (ce1Mid = '1')) then\n          rxBusy <= '0';\n        end if;\n      end if;\n    end process;\n    -- bit counter\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        bitCount <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if (rxBusy = '0') then\n          bitCount <= (others => '0');\n        elsif ((rxBusy = '1') and (ce1Mid = '1')) then\n          bitCount <= bitCount + 1;\n        end if;\n      end if;\n    end process;\n    -- data buffer shift register\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        dataBuf <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if ((rxBusy = '1') and (ce1Mid = '1')) then\n          dataBuf <= inSync(1) & dataBuf(7 downto 1);\n        end if;\n      end if;\n    end process;\n    -- data output and flag\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        rxData <= (others => '0');\n        newRxData <= '0';\n      elsif (rising_edge(clk)) then\n        if ((rxBusy = '1') and (bitCount = \"1000\") and (ce1 = '1')) then\n          rxData <= dataBuf;\n          newRxData <= '1';\n        else\n          newRxData <= '0';\n        end if;\n      end if;\n    end process;\n    -- ce_1 pulse indicating expected end of current bit\n    ce1 <= '1' when ((count16 = \"1111\") and (ce16 = '1')) else '0';\n    -- ce_1_mid pulse indication the sampling clock cycle of the current data bit\n    ce1Mid <= '1' when ((count16 = \"0111\") and (ce16 = '1')) else '0';\n  end Behavioral;\n"
  },
  {
    "path": "tests/designs/uart2bus/vhdl/uartTop.vhd",
    "content": "-----------------------------------------------------------------------------------------\n-- uart top level module\n--\n-----------------------------------------------------------------------------------------\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n\nuse work.uart2BusTop_pkg.all;\n\nentity uartTop is\n  port ( -- global signals\n         clr       : in  std_logic;                     -- global reset input\n         clk       : in  std_logic;                     -- global clock input\n         -- uart serial signals\n         serIn     : in  std_logic;                     -- serial data input\n         serOut    : out std_logic;                     -- serial data output\n         -- transmit and receive internal interface signals\n         txData    : in  std_logic_vector(7 downto 0);  -- data byte to transmit\n         newTxData : in  std_logic;                     -- asserted to indicate that there is a new data byte for transmission\n         txBusy    : out std_logic;                     -- signs that transmitter is busy\n         rxData    : out std_logic_vector(7 downto 0);  -- data byte received\n         newRxData : out std_logic;                     -- signs that a new byte was received\n         -- baud rate configuration register - see baudGen.vhd for details\n         baudFreq  : in  std_logic_vector(11 downto 0); -- baud rate setting registers - see header description\n         baudLimit : in  std_logic_vector(15 downto 0); -- baud rate setting registers - see header description\n         baudClk   : out std_logic);                    --\nend uartTop;\n\narchitecture Behavioral of uartTop is\n\n  signal ce16 : std_logic; -- clock enable at bit rate\n\n  begin\n    -- baud rate generator module\n    bg : baudGen\n      port map (\n        clr => clr,\n        clk => clk,\n        baudFreq => baudFreq,\n        baudLimit => baudLimit,\n        ce16 => ce16);\n    -- uart receiver\n    ut : uartTx\n      port map (\n        clr => clr,\n        clk => clk,\n        ce16 => ce16,\n        txData => txData,\n        newTxData => newTxData,\n        serOut => serOut,\n        txBusy => txBusy);\n    -- uart transmitter\n    ur : uartRx\n      port map (\n        clr => clr,\n        clk => clk,\n        ce16 => ce16,\n        serIn => serIn,\n        rxData => rxData,\n        newRxData => newRxData);\n    baudClk <= ce16;\n  end Behavioral;\n"
  },
  {
    "path": "tests/designs/uart2bus/vhdl/uartTx.vhd",
    "content": "-----------------------------------------------------------------------------------------\n-- uart transmit module\n--\n-----------------------------------------------------------------------------------------\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.std_logic_unsigned.all;\n\nentity uartTx is\n  port ( clr       : in  std_logic;                    -- global reset input\n         clk       : in  std_logic;                    -- global clock input\n         ce16      : in  std_logic;                    -- baud rate multiplied by 16 - generated by baud module\n         txData    : in  std_logic_vector(7 downto 0); -- data byte to transmit\n         newTxData : in  std_logic;                    -- asserted to indicate that there is a new data byte for transmission\n         serOut    : out std_logic;                    -- serial data output\n         txBusy    : out std_logic);                   -- signs that transmitter is busy\nend uartTx;\n\narchitecture Behavioral of uartTx is\n\n  signal iTxBusy  : std_logic;\n  signal ce1      : std_logic; -- clock enable at bit rate\n  signal count16  : std_logic_vector(3 downto 0);\n  signal bitCount : std_logic_vector(3 downto 0);\n  signal dataBuf  : std_logic_vector(8 downto 0);\n\n  begin\n    -- a counter to count 16 pulses of ce_16 to generate the ce_1 pulse\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        count16 <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if ((iTxBusy = '1') and (ce16 = '1')) then\n          count16 <= count16 + 1;\n        elsif (iTxBusy = '0') then\n          count16 <= (others => '0');\n        end if;\n      end if;\n    end process;\n    -- tx_busy flag\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        iTxBusy <= '0';\n      elsif (rising_edge(clk)) then\n        if ((iTxBusy = '0') and (newTxData = '1')) then\n          iTxBusy <= '1';\n        elsif ((iTxBusy = '1') and (bitCount = \"1001\") and (ce1 = '1')) then\n          iTxBusy <= '0';\n        end if;\n      end if;\n    end process;\n    -- output bit counter\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        bitCount <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if ((iTxBusy = '1') and (ce1 = '1')) then\n          bitCount <= bitCount + 1;\n        elsif (iTxBusy = '0') then\n          bitCount <= (others => '0');\n        end if;\n      end if;\n    end process;\n    -- data shift register\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        dataBuf <= (others => '0');\n      elsif (rising_edge(clk)) then\n        if (iTxBusy = '0') then\n          dataBuf <= txData & '0';\n        elsif ((iTxBusy = '1') and (ce1 = '1')) then\n          dataBuf <= '1' & dataBuf(8 downto 1);\n        end if;\n      end if;\n    end process;\n    -- output data bit\n    process (clr, clk)\n    begin\n      if (clr = '1') then\n        serOut <= '1';\n      elsif (rising_edge(clk)) then\n        if (iTxBusy = '1') then\n          serOut <= dataBuf(0);\n        else\n          serOut <= '1';\n        end if;\n      end if;\n    end process;\n    -- ce_1 pulse indicating output data bit should be updated\n    ce1 <= '1' when ((count16 = \"1111\") and (ce16 = '1')) else '0';\n    txBusy <= iTxBusy;\n  end Behavioral;\n"
  },
  {
    "path": "tests/designs/verilator_timing/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCURRENT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))\n\nTOPLEVEL_LANG ?= verilog\nSIM ?= verilator\n\nVERILOG_SOURCES := $(CURRENT_DIR)/test_verilator_timing.sv\nCOCOTB_TOPLEVEL := test_verilator_timing\n"
  },
  {
    "path": "tests/designs/verilator_timing/README.md",
    "content": "## Motivation\n\nThese test cases provided are meant to validate behavior of `cocotb` with `verilator` simulations, if timing statements are used in HDL code. Here, the term 'timing statements' refers to HDL statements which control the simulation time. The simplest example of such a statement is:\n\n    initial begin: proc_delay\n        #(10)\n            clk = ~clk;\n    end\n\nStarting with Verilator 5, if timing statements are present in code, [the simulator expects the user to specify their desired method of processing timing statements with additional flags](https://veripool.org/guide/latest/exe_verilator.html#cmdoption-no-timing). This is a result of changes made to [Verilator's Model Evaluation Loop](https://veripool.org/guide/latest/connecting.html#wrappers-and-model-evaluation-loop). The issue with Verilating was first reported in [#3254](https://github.com/cocotb/cocotb/issues/3254) and fixed by PR [#verilator_timing](https://github.com/cocotb/cocotb/pull/verilator_timing).\n\n## Test implementation\nIn `test_verilator_timing_[a-d].py`, 2 cocotb tests are defined: `clk_in_coroutine` and `clk_in_hdl`. The first one provides a clock generator in the coroutine, but the other one expects that a clock generator is placed in the HDL code (c.f. `test_verilator_timing.sv`). Additionally, test behavior is controlled with 2 settings: verilator's `--timing` option and `TEST_CLK_EXTERNAL` macro. The `--timing` option determines how Verilator should process timing statements. The Verilog macro is used to control whether the clock generator is present in the Verilog code. A table below summarizes all used test configurations and the expected test behavior.\n\n### `clk_in_coroutine`\n\n| Case  |     Flag:external_clock     | timing_option |  Clock generator  |                  Description                  |\n| :---: | :-------------------------: | :-----------: | :---------------: | :-------------------------------------------: |\n|   A   |            None             |     None      | HDL AND Coroutine | Expected fail: Verilator needs timing options |\n|   B   | +define+TEST_CLK_EXTERNAL=1 |     None      |     Coroutine     |        Expected pass: regression case         |\n|   C   |            None             |   --timing    | HDL AND Coroutine |     Expected pass: since #verilator_timing is merged      |\n|   D   | +define+TEST_CLK_EXTERNAL=1 |   --timing    |     Coroutine     |        Expected pass: regression case         |\n\n### `clk_in_hdl`\n\n| Case  |     Flag:external_clock     | timing_option | Clock generator |                  Description                   |\n| :---: | :-------------------------: | :-----------: | :-------------: | :--------------------------------------------: |\n|   A   |            None             |     None      |       HDL       | Expected fail: Verilator needs timing options  |\n|   B   | +define+TEST_CLK_EXTERNAL=1 |     None      |      None       | Expected fail: No events driving the simulator |\n|   C   |            None             |   --timing    |       HDL       |      Expected pass: since #verilator_timing is merged      |\n|   D   | +define+TEST_CLK_EXTERNAL=1 |   --timing    |      None       | Expected fail: No events driving the simulator |\n"
  },
  {
    "path": "tests/designs/verilator_timing/test_verilator_timing.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\nmodule test_verilator_timing (\n`ifdef TEST_CLK_EXTERNAL\n    input  logic clk,\n`endif  // `ifdef TEST_CLK_EXTERNAL\n    input  logic d,\n    output logic q\n);\n\n`ifndef TEST_CLK_EXTERNAL\n  // Clocking\n  bit clk;\n  initial clk = 0;\n  always #5 clk = ~clk;\n`endif  // `ifndef TEST_CLK_EXTERNAL\n\n  always_ff @(posedge clk) begin : proc_dff\n    q <= d;\n  end\n\nendmodule : test_verilator_timing\n"
  },
  {
    "path": "tests/designs/vhdl_configurations/Makefile",
    "content": "TOPLEVEL_LANG ?= vhdl\n\nifneq ($(TOPLEVEL_LANG),vhdl)\n\n# Currently, there is an issue with file dependency when dealing with a Mixed Language Simulation like this.\n# With the current process, all the VHDL is compiled first and then all the Verilog which doesn't work with a\n# dependency like below.  Compile order would need to be:\n#    1. dut.vhd\n#    2. testbench.vhd or testbench.v\n#    3. configurations.vhd\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being vhdl\"\nclean::\n\nelse\n\nCOCOTB_TOPLEVEL = testbench\n\nPWD=$(shell pwd)\n\nCOCOTB?=$(PWD)/../../..\n\nVHDL_SOURCES = $(COCOTB)/tests/designs/vhdl_configurations/dut.vhd\nifeq ($(TOPLEVEL_LANG),verilog)\n    VERILOG_SOURCES = $(COCOTB)/tests/designs/vhdl_configurations/testbench.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    VHDL_SOURCES += $(COCOTB)/tests/designs/vhdl_configurations/testbench.vhd\nelse\n    $(error A valid value (verilog or vhdl) was not provided for TOPLEVEL_LANG=$(TOPLEVEL_LANG))\nendif\nVHDL_SOURCES += $(COCOTB)/tests/designs/vhdl_configurations/configurations.vhd\n\nifneq ($(filter $(SIM),ius xcelium),)\n    COMPILE_ARGS += -v93\nendif\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/designs/vhdl_configurations/configurations.vhd",
    "content": "configuration config_single of testbench is\n    for myconfig\n        for dut_inst : dut\n                use entity work.dut(single);\n        end for;\n    end for;\nend configuration config_single;\n\nconfiguration config_double of testbench is\n    for myconfig\n        for dut_inst : dut\n                use entity work.dut(double);\n        end for;\n    end for;\nend configuration config_double;\n"
  },
  {
    "path": "tests/designs/vhdl_configurations/dut.vhd",
    "content": "library ieee;\nuse ieee.std_logic_1164.all;\n\nentity dut is\n    port(\n        clk      : in  std_ulogic;\n        data_in  : in  std_ulogic;\n        data_out : out std_ulogic\n    );\nend entity dut;\n\narchitecture single of dut is begin\n\n    report_p : process begin\n        report \"this is dut(single)\";\n        wait;\n    end process;\n\n    clocked_p : process(clk) is begin\n        if rising_edge(clk) then\n            data_out <=  data_in;\n        end if;\n    end process;\nend architecture single;\n\n\narchitecture double of dut is\n    signal data_in_r  : std_ulogic;\nbegin\n\n    report_p : process begin\n        report \"this is dut(double)\";\n        wait;\n    end process;\n\n    clocked_p : process(clk) is begin\n        if rising_edge(clk) then\n            data_in_r <=  data_in;\n            data_out  <=  data_in_r;\n        end if;\n    end process;\nend architecture double;\n"
  },
  {
    "path": "tests/designs/vhdl_configurations/testbench.sv",
    "content": "module testbench (\n    input  logic        clk,\n    input  logic        data_in,\n    output logic        data_out\n);\n\ndut dut_inst (\n    .clk                (clk),\n    .data_in            (data_in),\n    .data_out           (data_out)\n);\n\nendmodule\n"
  },
  {
    "path": "tests/designs/vhdl_configurations/testbench.vhd",
    "content": "library ieee;\nuse ieee.std_logic_1164.all;\n\nentity testbench is\nend entity testbench;\n\narchitecture myconfig of testbench is\n    component dut\n        port(\n            clk      : in  std_ulogic;\n            data_in  : in  std_ulogic;\n            data_out : out std_ulogic);\n    end component dut;\n\n    signal clk          : std_ulogic;\n    signal data_in      : std_ulogic;\n    signal data_out     : std_ulogic;\n\nbegin\n\n    dut_inst : component dut\n        port map(\n            clk         => clk,\n            data_in     => data_in,\n            data_out    => data_out\n        );\nend architecture myconfig;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= vhdl\n\nifneq ($(TOPLEVEL_LANG),vhdl)\n\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being vhdl\"\nclean::\n\nelse\n\nCOCOTB_TOPLEVEL = dec_viterbi_ent\n\nPWD=$(shell pwd)\n\nCOCOTB?=$(PWD)/../../..\n\nSRC_BASE = $(COCOTB)/tests/designs/viterbi_decoder_axi4s\n\nTOPLEVEL_LIBRARY = dec_viterbi\n\nVHDL_SOURCES = $(SRC_BASE)/packages/pkg_helper.vhd \\\n\t       $(SRC_BASE)/packages/pkg_param.vhd \\\n\t       $(SRC_BASE)/packages/pkg_param_derived.vhd \\\n\t       $(SRC_BASE)/packages/pkg_types.vhd \\\n\t       $(SRC_BASE)/packages/pkg_components.vhd \\\n\t       $(SRC_BASE)/packages/pkg_trellis.vhd \\\n\t       $(SRC_BASE)/src/generic_sp_ram.vhd \\\n\t       $(SRC_BASE)/src/axi4s_buffer.vhd \\\n\t       $(SRC_BASE)/src/branch_distance.vhd \\\n\t       $(SRC_BASE)/src/traceback.vhd \\\n\t       $(SRC_BASE)/src/acs.vhd \\\n\t       $(SRC_BASE)/src/ram_ctrl.vhd \\\n\t       $(SRC_BASE)/src/reorder.vhd \\\n\t       $(SRC_BASE)/src/recursion.vhd \\\n\t       $(SRC_BASE)/src/dec_viterbi.vhd\n\nifneq ($(filter $(SIM),ius xcelium),)\n    COMPILE_ARGS += -v93\nendif\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/gpl-2.0.txt",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/packages/pkg_components.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Component declarations for Viterbi decoder\n--! @author Markus Fehrenz\n--! @date   2011/04/07\n--!\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\nuse dec_viterbi.pkg_types.all;\n\npackage pkg_components is\n\n\tcomponent axi4s_buffer is\n\t\tgeneric (\n\t\t\tDATA_WIDTH : natural := 1\n\t\t);\n\t\tport (\n\t\tclk            : in  std_logic;\n\t\trst            : in  std_logic;\n\n\t\tinput          : in  std_logic_vector(DATA_WIDTH - 1 downto 0);\n\t\tinput_valid    : in  std_logic;\n\t\tinput_last     : in  std_logic;\n\t\tinput_accept   : out std_logic;\n\n\t\toutput         : out std_logic_vector(DATA_WIDTH - 1 downto 0);\n\t\toutput_valid   : out std_logic;\n\t\toutput_last    : out std_logic;\n\t\toutput_accept  : in  std_logic\n\t\t);\n\tend component axi4s_buffer;\n\n\tcomponent branch_distance is\n\t\tgeneric(\n\t\t\tEDGE_WEIGHT : in std_logic_vector(NUMBER_PARITY_BITS - 1 downto 0)\n\t\t);\n\t\tport(\n\t\t\tclk : in std_logic;\n\t\t\trst : in std_logic;\n\n\t\t\ts_axis_input_tvalid : in  std_logic;\n\t\t\ts_axis_input_tdata  : in  t_input_block;\n\t\t\ts_axis_input_tlast  : in  std_logic;\n\t\t\ts_axis_input_tready : out std_logic;\n\n\t\t\tm_axis_output_tvalid : out std_logic;\n\t\t\tm_axis_output_tdata  : out std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);\n\t\t\tm_axis_output_tlast  : out std_logic;\n\t\t\tm_axis_output_tready : in  std_logic\n\n\t\t);\n\tend component branch_distance;\n\n\tcomponent acs is\n\t\tgeneric(\n\t\t\tINITIALIZE_VALUE : in signed(BW_MAX_PROBABILITY - 1 downto 0)\n\t\t);\n\t\tport(\n\t\t\tclk                    : in std_logic;\n\t\t\trst                    : in std_logic;\n\n\t\t\ts_axis_inbranch_tvalid     : in  std_logic;\n\t\t\ts_axis_inbranch_tdata_low  : in  std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);\n\t\t\ts_axis_inbranch_tdata_high : in  std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);\n\t\t\ts_axis_inbranch_tlast      : in  std_logic;\n\t\t\ts_axis_inbranch_tready     : out std_logic;\n\n\t\t\ts_axis_inprev_tvalid     : in  std_logic;\n\t\t\ts_axis_inprev_tdata_low  : in  std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);\n\t\t\ts_axis_inprev_tdata_high : in  std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);\n\t\t\ts_axis_inprev_tready     : out std_logic;\n\n\t\t\tm_axis_outprob_tvalid  : out std_logic;\n\t\t\tm_axis_outprob_tdata   : out std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);\n\t\t\tm_axis_outprob_tready  : in  std_logic;\n\n\t\t\tm_axis_outdec_tvalid   : out std_logic;\n\t\t\tm_axis_outdec_tdata    : out std_logic;\n\t\t\tm_axis_outdec_tlast    : out std_logic;\n\t\t\tm_axis_outdec_tready   : in  std_logic\n\t\t);\n\tend component acs;\n\n\tcomponent ram_ctrl is\n\t\tport(\n\t\t\tclk       : in std_logic;\n\t\t\trst       : in std_logic;\n\n\t\t\ts_axis_input_tvalid : in  std_logic;\n\t\t\ts_axis_input_tdata  : in  std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\t\t\ts_axis_input_tlast  : in  std_logic;\n\t\t\ts_axis_input_tready : out std_logic;\n\n\t\t\tm_axis_output_tvalid       : out std_logic_vector(1 downto 0);\n\t\t\tm_axis_output_tdata        : out t_ram_rd_data;\n\t\t\tm_axis_output_tlast        : out std_logic_vector(1 downto 0);\n\t\t\tm_axis_output_tready       : in  std_logic_vector(1 downto 0);\n\t\t\tm_axis_output_window_tuser : out std_logic_vector(1 downto 0);\n\t\t\tm_axis_output_last_tuser   : out std_logic_vector(1 downto 0);\n\n\t\t\ts_axis_ctrl_tvalid : in  std_logic;\n\t\t\ts_axis_ctrl_tdata  : in  std_logic_vector(31 downto 0);\n\t\t\ts_axis_ctrl_tready : out std_logic\n\t\t);\n\tend component ram_ctrl;\n\n\tcomponent generic_sp_ram is\n\t\tgeneric(\n\t\t\tDISTR_RAM : boolean;\n\t\t\tWORDS     : integer;\n\t\t\tBITWIDTH  : integer\n\t\t);\n\t\tport(\n\t\t\tclk : in std_logic;\n\t\t\trst : in std_logic;\n\n\t\t\twen : in std_logic;\n\t\t\ten  : in std_logic;\n\n\t\t\ta   : in std_logic_vector(BW_MAX_WINDOW_LENGTH - 1 downto 0);\n\t\t\td   : in  std_logic_vector(BITWIDTH - 1 downto 0 );\n\t\t\tq   : out std_logic_vector(BITWIDTH - 1 downto 0)\n\t\t);\n\tend component generic_sp_ram;\n\n\tcomponent trellis_traceback is\n\t\tport(\n\t\t\tclk : in std_logic;\n\t\t\trst : in std_logic;\n\n\t\t\ts_axis_input_tvalid       : in std_logic;\n\t\t\ts_axis_input_tdata        : in std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\t\t\ts_axis_input_tlast        : in std_logic;\n\t\t\ts_axis_input_tready       : out std_logic;\n\t\t\ts_axis_input_window_tuser : in std_logic;\n\t\t\ts_axis_input_last_tuser   : in std_logic;\n\n\t\t\tm_axis_output_tvalid     : out std_logic;\n\t\t\tm_axis_output_tdata      : out std_logic;\n\t\t\tm_axis_output_tlast      : out std_logic;\n\t\t\tm_axis_output_last_tuser : out std_logic;\n\t\t\tm_axis_output_tready     : in  std_logic\n\t\t);\n\tend component trellis_traceback;\n\n\tcomponent reorder is\n\t\tport(\n\t\t\tclk : in std_logic;\n\t\t\trst : in std_logic;\n\n\t\t\ts_axis_input_tvalid     : in  std_logic;\n\t\t\ts_axis_input_tdata      : in  std_logic;\n\t\t\ts_axis_input_tlast      : in  std_logic;\n\t\t\ts_axis_input_last_tuser : in  std_logic;\n\t\t\ts_axis_input_tready     : out std_logic;\n\n\t\t\tm_axis_output_tvalid     : out std_logic;\n\t\t\tm_axis_output_tdata      : out std_logic;\n\t\t\tm_axis_output_tlast      : out std_logic;\n\t\t\tm_axis_output_last_tuser : out std_logic;\n\t\t\tm_axis_output_tready     : in  std_logic\n\t\t);\n\tend component reorder;\n\n\tcomponent recursionx is\n\t\tport(\n\t\t\tclk : in std_logic;\n\t\t\trst : in std_logic;\n\n\t\t\ts_axis_input_tvalid     : in  std_logic;\n\t\t\ts_axis_input_tdata      : in  std_logic;\n\t\t\ts_axis_input_tlast      : in  std_logic;\n\t\t\ts_axis_input_tready     : out std_logic;\n\n\t\t\tm_axis_output_tvalid     : out std_logic;\n\t\t\tm_axis_output_tdata      : out std_logic;\n\t\t\tm_axis_output_tlast      : out std_logic;\n\t\t\tm_axis_output_tready     : in  std_logic\n\t\t);\n\tend component recursionx;\n\nend package pkg_components;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/packages/pkg_helper.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Helper package with useful functions\n--! @author Markus Fehrenz\n--! @date   2011/12/02\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\n\npackage pkg_helper is\n\n\t--!\n\t--! Return the log_2 of an natural value, i.e. the number of bits required\n\t--! to represent this unsigned value.\n\t--!\n\tfunction no_bits_natural(value_in : natural) return natural;\n\n\t--! Return maximum of two input values\n\tfunction max(value_in_a, value_in_b : natural) return natural;\n\nend pkg_helper;\n\n\npackage body pkg_helper is\n\n\tfunction no_bits_natural(value_in: natural) return natural is\n\t\tvariable v_n_bit : unsigned(31 downto 0);\n\tbegin\n\t\tif value_in = 0 then\n\t\t\treturn 0;\n\t\tend if;\n\t\tv_n_bit := to_unsigned(value_in, 32);\n\t\tfor i in 31 downto 0 loop\n\t\t\tif v_n_bit(i) = '1' then\n\t\t\t\treturn i + 1;\n\t\t\tend if;\n\t\tend loop;\n\t\treturn 1;\n\tend no_bits_natural;\n\n\tfunction max(value_in_a, value_in_b : natural) return natural is\n\tbegin\n\t\tif value_in_a > value_in_b then\n\t\t\treturn value_in_a;\n\t\telse\n\t\t\treturn value_in_b;\n\t\tend if;\n\tend function;\n\nend pkg_helper;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/packages/pkg_param.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief Parameters\n--! @author Markus Fehrenz\n--! @date 2011/07/01\n--!\n--! @details This is the configuration file of the Viterbi decoder.\n--!          Any changes for parameters should be done here.\n--!          Changing parameters somewhere else may result in a malicious\n--!          behavior.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\n\npackage pkg_param is\n\t-----------------------------------\n\t-- Convolutional Code Parameters --\n\t-----------------------------------\n\n\n\t--\n\t-- Set the number of parity values\n\t-- This has to correspond to PARITY_POLYNOMIALS\n\t--\n\tconstant NUMBER_PARITY_BITS : natural := 2;\n\ttype t_parity is array (NUMBER_PARITY_BITS - 1 downto 0) of natural;\n\n\t--\n\t-- Set parity polynoms in decimal notation\n\t-- NUMBER_PARITY_BITS has to correspond to the number of elements\n\t-- Examples: WiFi : [121,91] or [121,91,101]\n\t--           CDMA : [491,369] or [367,435,369] or [501,441,331,315]\n\t--           GSM  : [27,19] or [27,21,31]\n\t--           DAB  : [91,121,101,91]\n\t--           WiMAX: [91,121,117]\n\t--\n\tconstant PARITY_POLYNOMIALS   : t_parity := (121,91);\n\n\n\t--\n\t-- Set a recursive polynomial\n\t-- Set to 0 if no recursion is used\n\t-- Setting this arbitrary may result in a worse error correction ability\n\t--\n\tconstant FEEDBACK_POLYNOMIAL : natural := 0;\n\n\n\t-----------------------------\n\t-- Architecture Parameters --\n\t-----------------------------\n\n\t--\n\t-- Set bit width of LLR input\n\t-- Recommended values: 3 or 4\n\t--\n\tconstant BW_LLR_INPUT : natural := 4;\n\n\t--\n\t-- Set the maximum window length which shall be allowed at runtime.\n\t-- Recommended: at least 6 * constraint length\n\t--\n\tconstant MAX_WINDOW_LENGTH : natural := 96;\n\n\t--\n\t-- Set to 'true' if distributed RAM shall be used\n\t-- Set to 'false' if block RAM shall be used\n\t--\n\tconstant DISTRIBUTED_RAM : boolean := true;\n\nend package pkg_param;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/packages/pkg_param_derived.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Derived parameters\n--! @author Markus Fehrenz\n--! @date   2011/07/04\n--!\n--! @details This constants are derived from constants defined in pkg_param.\n--!          In order to prevent errors, there is no user choice for these parameters.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_helper.all;\n\n\npackage pkg_param_derived is\n\n\t-- Calculation of constraint length.\n\tfunction calc_constraint_length return natural;\n\n\t-- Memory depth of the encoder shift register.\n\tconstant ENCODER_MEMORY_DEPTH : natural;\n\n\t-- Number of trellis states corresponds to the number of ACS units.\n\tconstant NUMBER_TRELLIS_STATES : natural;\n\n\t-- Number of branch units for a single polynomial set\n\tconstant NUMBER_BRANCH_UNITS : natural;\n\n\t-- Bitwidth constants are needed for type conversions\n\tconstant BW_TRELLIS_STATES    : natural;\n\tconstant BW_MAX_WINDOW_LENGTH : natural;\n\tconstant BW_BRANCH_RESULT     : natural;\n\tconstant BW_MAX_PROBABILITY   : natural;\n\nend package pkg_param_derived;\n\n\npackage body pkg_param_derived is\n\n\tfunction calc_constraint_length return natural is\n\t\tvariable v_maximum : natural := 0;\n\tbegin\n\n\t\t-- Find the position of the leftmost bit in the polynomials.\n\t\tfor i in NUMBER_PARITY_BITS - 1 downto 0 loop\n\t\t\tv_maximum := max(v_maximum, no_bits_natural(PARITY_POLYNOMIALS(i)));\n\t\tend loop;\n\t\tv_maximum := max(v_maximum, no_bits_natural(FEEDBACK_POLYNOMIAL));\n\t\treturn v_maximum;\n\tend function calc_constraint_length;\n\n\n\tconstant ENCODER_MEMORY_DEPTH : natural := calc_constraint_length - 1;\n\n\tconstant NUMBER_TRELLIS_STATES : natural := 2 ** ENCODER_MEMORY_DEPTH;\n\n\tconstant NUMBER_BRANCH_UNITS : natural := 2 ** NUMBER_PARITY_BITS;\n\n\tconstant BW_TRELLIS_STATES    : natural := no_bits_natural(NUMBER_TRELLIS_STATES - 1);\n\tconstant BW_MAX_WINDOW_LENGTH : natural := no_bits_natural(MAX_WINDOW_LENGTH - 1);\n\tconstant BW_BRANCH_RESULT     : natural := no_bits_natural((2 ** (BW_LLR_INPUT - 1)) * NUMBER_PARITY_BITS) + 1;\n\tconstant BW_MAX_PROBABILITY   : natural := no_bits_natural(((2 ** (BW_LLR_INPUT - 1)) * NUMBER_PARITY_BITS) * 4 * ENCODER_MEMORY_DEPTH);\nend package body pkg_param_derived;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/packages/pkg_trellis.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Trellis parameter calculations (e.g., transitions, init values).\n--! @author Markus Fehrenz\n--! @date   2011/07/27\n--!\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\nuse dec_viterbi.pkg_types.all;\n\n\npackage pkg_trellis is\n\n\ttype t_prev_base       is array (1 downto 0) of std_logic_vector(BW_TRELLIS_STATES - 1 downto 0);\n\ttype t_previous_states is array (NUMBER_TRELLIS_STATES - 1 downto 0) of t_prev_base;\n\n\ttype t_trans_base  is array (1 downto 0) of std_logic_vector(NUMBER_PARITY_BITS - 1 downto 0);\n\ttype t_transitions is array (NUMBER_TRELLIS_STATES - 1 downto 0) of t_trans_base;\n\n\ttype t_trans_base_signed  is array (1 downto 0) of std_logic_vector(NUMBER_PARITY_BITS downto 0);\n\ttype t_transitions_signed is array (NUMBER_TRELLIS_STATES - 1 downto 0) of t_trans_base_signed;\n\n\n\t--\n\t-- This function calculates the previous states of each state.\n\t-- The values are used to connect the ACS units.\n\t--\n\tfunction calc_previous_states return t_previous_states;\n\n\n\t--\n\t-- This function calculates corresponding transitions to a trellis state.\n\t-- The values are used to connect branch units to ACS units.\n\t--\n\tfunction calc_transitions     return t_transitions;\n\n\n\t--\n\t-- This function calculates the initialization values for trellis metrics.\n\t-- The values are used as a constant and written to the ACS unit, every time a new block arrives.\n\t--\n\tfunction calc_initialize      return t_node_s;\n\n\tconstant PREVIOUS_STATES    : t_previous_states;\n\tconstant TRANSITIONS        : t_transitions;\n\tconstant INITIALIZE_TRELLIS : t_node_s;\n\nend package pkg_trellis;\n\n\npackage body pkg_trellis is\n\n\n\tfunction calc_previous_states return t_previous_states is\n\t\tvariable v_prev_states       : t_previous_states := (others=>(others=>(others => '0')));\n\t\tvariable v_state0, v_state1  : std_logic_vector(BW_TRELLIS_STATES - 1 downto 0);\n\tbegin\n\t\tfor i in NUMBER_TRELLIS_STATES - 1 downto 0 loop\n\t\t\tv_state0 := std_logic_vector(to_unsigned(i,BW_TRELLIS_STATES));\n\t\t\tv_state1 := v_state0(BW_TRELLIS_STATES - 2 downto 0) & '0';\n\t\t\tv_prev_states(i)(0) := v_state1;\n\t\t\tv_state1 := v_state0(BW_TRELLIS_STATES - 2 downto 0) & '1';\n\t\t\tv_prev_states(i)(1) := v_state1;\n\t\tend loop;\n\treturn v_prev_states;\n\tend function calc_previous_states;\n\n\n\tfunction calc_transitions return t_transitions is\n\t\tvariable v_transitions     : t_transitions_signed := (others => (others => (others => '0')));\n\t\tvariable v_transitions_out : t_transitions := (others => (others => (others => '0')));\n\t\tvariable v_one_transition  : std_logic_vector(NUMBER_PARITY_BITS - 1 downto 0);\n\t\tvariable v_next_state      : unsigned(ENCODER_MEMORY_DEPTH - 1 downto 0) := (others => '0');\n\t\tvariable v_state, v_states : unsigned(ENCODER_MEMORY_DEPTH downto 0);\n\t\tvariable v_bit             : std_logic := '0';\n\tbegin\n\n\t\t--\n\t\t-- It is possible to reduce code size at this stage, if feedback is handled differently,\n\t\t-- but the complexity will increase.\n\t\t--\n\n\t\tfor i in NUMBER_TRELLIS_STATES - 1 downto 0 loop\n\n\t\t\t--\n\t\t\t-- for input : 0\n\t\t\t-- determine correct input with feedback\n\t\t\t--\n\t\t\tv_next_state := to_unsigned(i,ENCODER_MEMORY_DEPTH) and to_unsigned(FEEDBACK_POLYNOMIAL, ENCODER_MEMORY_DEPTH);\n\t\t\tfor k in ENCODER_MEMORY_DEPTH - 1 downto 0 loop\n\t\t\t\tv_bit := v_bit xor v_next_state(k);\n\t\t\tend loop;\n\t\t\tv_state(ENCODER_MEMORY_DEPTH)              := v_bit;\n\t\t\tv_state(ENCODER_MEMORY_DEPTH - 1 downto 0) := to_unsigned(i,ENCODER_MEMORY_DEPTH);\n\t\t\tv_next_state := v_state(ENCODER_MEMORY_DEPTH downto 1);\n\t\t\tv_bit := '0';\n\n\t\t\t-- determine paritybits\n\t\t\tfor j in NUMBER_PARITY_BITS - 1 downto 0 loop\n\t\t\t\tv_states := v_state and to_unsigned(PARITY_POLYNOMIALS(j), ENCODER_MEMORY_DEPTH + 1);\n\t\t\t\tfor k in ENCODER_MEMORY_DEPTH downto 0 loop\n\t\t\t\t\tv_bit := v_bit xor v_states(k);\n\t\t\t\tend loop;\n\t\t\t\tv_one_transition(j) := v_bit;\n\t\t\t\tv_bit := '0';\n\t\t\tend loop;\n\n\t\t\t-- decide where to save the parity result\n\t\t\tif v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS) = '0' then\n\t\t\t\t v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS) := '1';\n\t\t\t\t v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS - 1 downto 0) := v_one_transition;\n\t\t\telse\n\t\t\t\t v_transitions(to_integer(v_next_state))(0)(NUMBER_PARITY_BITS - 1 downto 0) := v_one_transition;\n\t\t\tend if;\n\n\t\t\t--\n\t\t\t-- for input: 1\n\t\t\t-- determine correct input with feedback\n\t\t\t--\n\t\t\tv_next_state := to_unsigned(i,ENCODER_MEMORY_DEPTH) and to_unsigned(FEEDBACK_POLYNOMIAL, ENCODER_MEMORY_DEPTH);\n\t\t\tfor k in ENCODER_MEMORY_DEPTH - 1 downto 0 loop\n\t\t\t\tv_bit := v_bit xor v_next_state(k);\n\t\t\tend loop;\n\t\t\tv_state(ENCODER_MEMORY_DEPTH)              := '1' xor v_bit;\n\t\t\tv_state(ENCODER_MEMORY_DEPTH - 1 downto 0) := to_unsigned(i,ENCODER_MEMORY_DEPTH);\n\t\t\tv_next_state := v_state(ENCODER_MEMORY_DEPTH downto 1);\n\t\t\tv_bit := '0';\n\n\t\t\t-- determine paritybits\n\t\t\tfor j in NUMBER_PARITY_BITS - 1 downto 0 loop\n\t\t\t\tv_states := v_state and to_unsigned(PARITY_POLYNOMIALS(j), ENCODER_MEMORY_DEPTH + 1);\n\t\t\t\tfor k in ENCODER_MEMORY_DEPTH downto 0 loop\n\t\t\t\t\tv_bit := v_bit xor v_states(k);\n\t\t\t\tend loop;\n\t\t\t\tv_one_transition(j) := v_bit;\n\t\t\t\tv_bit := '0';\n\t\t\tend loop;\n\n\t\t\t-- decide where to save parity result\n\t\t\tif v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS) = '0' then\n\t\t\t\t v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS) := '1';\n\t\t\t\t v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS - 1 downto 0) := v_one_transition;\n\t\t\telse\n\t\t\t\t v_transitions(to_integer(v_next_state))(0)(NUMBER_PARITY_BITS - 1 downto 0) := v_one_transition;\n\t\t\tend if;\n\t\tend loop;\n\n\t\t-- truncate, the bit, used to decide where to save parity result\n\t\tfor i in NUMBER_TRELLIS_STATES - 1 downto 0 loop\n\t\t\tv_transitions_out(i)(1) := v_transitions(i)(1)(NUMBER_PARITY_BITS - 1 downto 0);\n\t\t\tv_transitions_out(i)(0) := v_transitions(i)(0)(NUMBER_PARITY_BITS - 1 downto 0);\n\t\tend loop;\n\n\t\treturn v_transitions_out;\n\tend function calc_transitions;\n\n\n\tfunction calc_initialize return t_node_s is\n\t\tvariable v_initialize : t_node_s;\n\tbegin\n\t\tv_initialize(0) := to_signed(0, BW_MAX_PROBABILITY);\n\t\tfor i in NUMBER_TRELLIS_STATES - 1 downto 1 loop\n\t\t\tv_initialize(i) := to_signed(- 2 ** (BW_MAX_PROBABILITY - 2), BW_MAX_PROBABILITY);\n\t\tend loop;\n\treturn v_initialize;\n\tend function calc_initialize;\n\n\n\tconstant PREVIOUS_STATES    : t_previous_states := calc_previous_states;\n\tconstant TRANSITIONS        : t_transitions     := calc_transitions;\n\tconstant INITIALIZE_TRELLIS : t_node_s          := calc_initialize;\n\nend package body pkg_trellis;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/packages/pkg_types.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Global types for the Viterbi decoder\n--! @author Markus Fehrenz\n--! @date   2011/07/04\n--!\n--! @details Most types are shared and used in different context.\n--!          Changing single types should be done with adding an additional type.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\n\npackage pkg_types is\n\n\t-- Parity structure: p1_bit, p2_bit, ..., pN_bit\n\ttype t_input_block is array (NUMBER_PARITY_BITS - 1 downto 0) of signed(BW_LLR_INPUT - 1 downto 0);\n\n\t-- Types are used for bulk information to ACS and branch unit.\n\ttype t_node_s is array (NUMBER_TRELLIS_STATES - 1 downto 0) of signed(BW_MAX_PROBABILITY - 1 downto 0);\n\ttype t_node   is array (NUMBER_TRELLIS_STATES - 1 downto 0) of std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);\n\ttype t_branch is array (NUMBER_BRANCH_UNITS - 1 downto 0)   of std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);\n\n\t-- RAM Data\n\ttype t_ram_rd_data is array (1 downto 0) of std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\nend package pkg_types;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/src/acs.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Add-compare-select unit for trellis processing.\n--! @author Markus Fehrenz\n--! @date   2011/07/04\n--!\n--! @details The ACS decides which path is the the surviving trellis path.\n--! In the design there are 2^{K-1} ACS instances.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\nuse dec_viterbi.pkg_types.all;\nuse dec_viterbi.pkg_helper.all;\n\n\nentity acs is\n\tgeneric(\n\n\t\t-- Reset value\n\t\tINITIALIZE_VALUE : in signed(BW_MAX_PROBABILITY - 1 downto 0)\n\t);\n\tport(\n\t\tclk : in std_logic;\n\t\trst : in std_logic;\n\n\t\t--\n\t\t-- Values from branch distance, signed values in std_logic_vector\n\t\t-- high is located in the upper half.\n\t\t--\n\t\ts_axis_inbranch_tvalid     : in  std_logic;\n\t\ts_axis_inbranch_tdata_low  : in  std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);\n\t\ts_axis_inbranch_tdata_high : in  std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);\n\t\ts_axis_inbranch_tlast      : in  std_logic;\n\t\ts_axis_inbranch_tready     : out std_logic;\n\n\t\t--\n\t\t-- Probabilities from previous nodes, signed values in std_logic_vector\n\t\t-- high is located in the upper half.\n\t\t--\n\t\ts_axis_inprev_tvalid     : in  std_logic;\n\t\ts_axis_inprev_tdata_low  : in  std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);\n\t\ts_axis_inprev_tdata_high : in  std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);\n\t\ts_axis_inprev_tready     : out std_logic;\n\n\t\t-- probability result of the add compare and select\n\t\tm_axis_outprob_tvalid  : out std_logic;\n\t\tm_axis_outprob_tdata   : out std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);\n\t\tm_axis_outprob_tready  : in  std_logic;\n\n\t\t-- decision result of the add compare and select\n\t\tm_axis_outdec_tvalid   : out std_logic;\n\t\tm_axis_outdec_tdata    : out std_logic;\n\t\tm_axis_outdec_tlast    : out std_logic;\n\t\tm_axis_outdec_tready   : in  std_logic\n\t);\nend entity acs;\n\n\narchitecture rtl of acs is\n\n\tsignal s_axis_inbranch_tlast_d : std_logic;\n\tsignal m_axis_outdec_tvalid_int : std_logic;\n\tsignal s_axis_inbranch_tready_int : std_logic;\n\nbegin\n\n\ts_axis_inbranch_tready_int <= '1' when m_axis_outdec_tready = '1' or m_axis_outdec_tvalid_int = '0' else\n\t                              '0';\n\ts_axis_inbranch_tready <= s_axis_inbranch_tready_int;\n\tm_axis_outdec_tvalid   <= m_axis_outdec_tvalid_int;\n\n\t-- Add branch to previous, compare both paths and select survivor.\n\tpr_add_compare : process(clk) is\n\t\tvariable v_diff, v_high, v_low : signed(BW_MAX_PROBABILITY - 1 downto 0);\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\tm_axis_outdec_tvalid_int <= '0';\n\t\t\tm_axis_outdec_tdata      <= '0';\n\t\t\tm_axis_outdec_tlast      <= '0';\n\t\t\tm_axis_outprob_tvalid    <= '0';\n\t\t\ts_axis_inprev_tready     <= '0';\n\t\t\ts_axis_inbranch_tlast_d  <= '0';\n\t\t\tm_axis_outprob_tdata     <= std_logic_vector(INITIALIZE_VALUE);\n\t\telse\n\t\t\t-- If this is the last value, prepare for processing of next incoming value.\n\t\t\tif s_axis_inbranch_tlast_d = '1' then\n\t\t\t\tm_axis_outprob_tdata     <= std_logic_vector(INITIALIZE_VALUE);\n\t\t\t\ts_axis_inbranch_tlast_d  <= '0';\n\t\t\t\tm_axis_outdec_tvalid_int <= '0';\n\t\t\tend if;\n\t\t\tif m_axis_outdec_tvalid_int = '1' and m_axis_outdec_tready = '1' then\n\t\t\t\tm_axis_outdec_tvalid_int <= '0';\n\t\t\tend if;\n\n\t\t\t-- Process only if we receive valid data.\n\t\t\tif s_axis_inbranch_tvalid = '1' and s_axis_inbranch_tready_int = '1' then\n\t\t\t\ts_axis_inbranch_tlast_d <= s_axis_inbranch_tlast;\n\n\t\t\t\t-- Add.\n\t\t\t\tv_low  := signed(s_axis_inbranch_tdata_low)  + signed(s_axis_inprev_tdata_low);\n\t\t\t\tv_high := signed(s_axis_inbranch_tdata_high) + signed(s_axis_inprev_tdata_high);\n\n\t\t\t\t-- Use modulo normalization, do not extend the sign here!\n\t\t\t\tv_diff := v_low - v_high;\n\n\t\t\t\t-- Compare, select the correct path.\n\t\t\t\tif v_diff < 0 then\n\t\t\t\t\tm_axis_outdec_tdata  <= '1';\n\t\t\t\t\tm_axis_outprob_tdata <= std_logic_vector(v_high);\n\t\t\t\telse\n\t\t\t\t\tm_axis_outdec_tdata  <= '0';\n\t\t\t\t\tm_axis_outprob_tdata <= std_logic_vector(v_low);\n\t\t\t\tend if;\n\t\t\t\tm_axis_outdec_tvalid_int <= '1';\n\t\t\tend if;\n\n\t\t\tm_axis_outdec_tlast    <= s_axis_inbranch_tlast;\n\t\tend if;\n\tend if;\n\tend process pr_add_compare;\n\nend architecture rtl;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/src/axi4s_buffer.vhd",
    "content": "--!\n--! Copyright (C) 2012 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  AXI4-Stream buffer that allows to buffer the accept-signal.\n--! @author Matthias Alles\n--! @date   2012/04/18\n--!\n--! @details\n--! One problem when concatenating multiple AXI4-Stream builind blocks is that\n--! the accept signal has to pass from the very last component to the input\n--! of the very first component. Only then it is possible to have an interruption\n--! free data processing within the whole chain. The drawback of this approach is\n--! that the accept signal has a long path and high fanouts.\n--! This entity allows to use registers on the accept signals by introducing buffers\n--! for storing the input values. It should improve timing of bigger building blocks.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n\n\nentity axi4s_buffer is\n\tgeneric (\n\t\tDATA_WIDTH : natural := 1\n\t);\n\tport (\n\n\tclk            : in  std_logic;\n\trst            : in  std_logic;\n\n\t-- Input data handling\n\t----------------------\n\n\tinput          : in  std_logic_vector(DATA_WIDTH - 1 downto 0);\n\tinput_valid    : in  std_logic;\n\tinput_last     : in  std_logic;\n\tinput_accept   : out std_logic;\n\n\n\t-- Output data handling\n\t-----------------------\n\toutput         : out std_logic_vector(DATA_WIDTH - 1 downto 0);\n\toutput_valid   : out std_logic;\n\toutput_last    : out std_logic;\n\toutput_accept  : in  std_logic\n);\nend entity axi4s_buffer;\n\n\narchitecture rtl of axi4s_buffer is\n\n\n\tsignal input_accept_int : std_logic;\n\n\tsignal output_reg        : std_logic_vector(DATA_WIDTH - 1 downto 0);\n\tsignal output_last_reg   : std_logic;\n\tsignal output_valid_reg  : std_logic;\n\n\tsignal buffer_full : std_logic;\n\tsignal buffer_data : std_logic_vector(DATA_WIDTH - 1 downto 0);\n\tsignal buffer_last : std_logic;\n\nbegin\n\n\tinput_accept <= input_accept_int;\n\n\toutput       <= output_reg;\n\toutput_last  <= output_last_reg;\n\toutput_valid <= output_valid_reg;\n\n\t--\n\t-- This process registers all signals.\n\t-- No combinatorial logic is bypassed from input to output and vice versa.\n\t--\n\tpr_reg: process(clk) is\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\toutput_reg        <= (others => '0');\n\t\t\toutput_last_reg   <= '0';\n\t\t\toutput_valid_reg  <= '0';\n\n\t\t\tinput_accept_int <= '1';\n\n\t\t\tbuffer_full <= '0';\n\t\t\tbuffer_data <= (others => '0');\n\t\t\tbuffer_last <= '0';\n\t\telse\n\n\t\t\t--\n\t\t\t-- Data is coming, buf output data can't be sent => Store input data in buffer\n\t\t\t-- and remove input_accept signal!\n\t\t\t--\n\t\t\tif input_valid = '1' and input_accept_int = '1' and output_valid_reg = '1' and output_accept = '0' then\n\t\t\t\tbuffer_data      <= input;\n\t\t\t\tbuffer_last      <= input_last;\n\t\t\t\tbuffer_full      <= '1';\n\t\t\t\tinput_accept_int <= '0';\n\t\t\tend if;\n\n\t\t\t--\n\t\t\t-- Output data is being read but there is data in the buffer waiting for being sent\n\t\t\t-- => Use the buffer data!\n\t\t\t--\n\t\t\tif output_accept = '1' and output_valid_reg = '1' and buffer_full = '1' then\n\t\t\t\toutput_reg       <= buffer_data;\n\t\t\t\toutput_last_reg  <= buffer_last;\n\t\t\t\toutput_valid_reg <= '1';\n\t\t\t\tbuffer_full      <= '0';\n\t\t\t\tinput_accept_int <= '1';\n\n\t\t\t--\n\t\t\t-- Data is being read and buffer is empty => Use input data directly!\n\t\t\t-- Output register is empty => Use input data directly!\n\t\t\t--\n\t\t\telsif (output_accept = '1' and output_valid_reg = '1') or output_valid_reg = '0' then\n\t\t\t\toutput_reg       <= input;\n\t\t\t\toutput_last_reg  <= input_last;\n\t\t\t\toutput_valid_reg <= input_valid;\n\t\t\tend if;\n\n\t\tend if;\n\tend if;\n\tend process pr_reg;\n\nend architecture rtl;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/src/branch_distance.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Branch distance calculation unit.\n--! @author Markus Fehrenz\n--! @date   2011/08/04\n--!\n--! @details Each branch has to be calculated only once.\n--!          The branch calculations are configured with a generic.\n--!          There is no limitation in branch calculations.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\nuse dec_viterbi.pkg_types.all;\n\n\nentity branch_distance is\n\tgeneric(\n\t\tEDGE_WEIGHT : in std_logic_vector(0 to NUMBER_PARITY_BITS - 1)\n\t);\n\tport(\n\t\tclk                 : in std_logic;\n\t\trst                 : in std_logic;\n\n\t\t--\n\t\t-- Input LLR values\n\t\t--\n\t\ts_axis_input_tvalid : in  std_logic;\n\t\ts_axis_input_tdata  : in  t_input_block;\n\t\ts_axis_input_tlast  : in  std_logic;\n\t\ts_axis_input_tready : out std_logic;\n\n\n\t\t--\n\t\t-- Output branch metrics, going to ACS unit.\n\t\t--\n\t\tm_axis_output_tvalid : out std_logic;\n\t\tm_axis_output_tdata  : out std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);\n\t\tm_axis_output_tlast  : out std_logic;\n\t\tm_axis_output_tready : in  std_logic\n\t);\nend entity branch_distance;\n\n\narchitecture rtl of branch_distance is\n\n\tsignal m_axis_output_tvalid_int : std_logic;\n\tsignal s_axis_input_tready_int  : std_logic;\n\nbegin\n\n\t-- We are ready, when we are allowed to write to the output, or the output is idle.\n\ts_axis_input_tready_int <= '1' when m_axis_output_tready = '1' else\n\t                           '0';\n\n\t-- Connect internal versions of signal to output port.\n\ts_axis_input_tready   <= s_axis_input_tready_int;\n\tm_axis_output_tvalid  <= m_axis_output_tvalid_int;\n\n\n\t-- Calculation of specific branch distance with a geometric distance function.\n\tpr_branch : process(clk) is\n\t\tvariable v_branch_result : integer;\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\tm_axis_output_tvalid_int <= '0';\n\t\t\tm_axis_output_tdata      <= (others => '0');\n\t\t\tm_axis_output_tlast      <= '0';\n\t\telse\n\n\t\t\tif m_axis_output_tvalid_int = '1' and m_axis_output_tready = '1' then\n\t\t\t\tm_axis_output_tvalid_int <= '0';\n\t\t\t\tm_axis_output_tlast      <= '0';\n\t\t\tend if;\n\n\t\t\tif s_axis_input_tready_int = '1' and s_axis_input_tvalid = '1' then\n\t\t\t\tv_branch_result := 0;\n\n\t\t\t\tfor i in NUMBER_PARITY_BITS - 1 downto 0 loop\n\n\t\t\t\t\t--\n\t\t\t\t\t-- Either the value is added or subtracted, depending on\n\t\t\t\t\t-- the current branch metric we are computing.\n\t\t\t\t\t--\n\t\t\t\t\tif EDGE_WEIGHT(i) = '0' then\n\t\t\t\t\t\tv_branch_result := v_branch_result + to_integer(s_axis_input_tdata(i));\n\t\t\t\t\telse\n\t\t\t\t\t\tv_branch_result := v_branch_result - to_integer(s_axis_input_tdata(i));\n\t\t\t\t\tend if;\n\t\t\t\tend loop;\n\t\t\t\tm_axis_output_tdata <= std_logic_vector(to_signed(v_branch_result, BW_BRANCH_RESULT));\n\t\t\t\tm_axis_output_tvalid_int <= '1';\n\t\t\t\tm_axis_output_tlast      <= s_axis_input_tlast;\n\t\t\tend if;\n\n\t\tend if;\n\tend if;\n\tend process pr_branch;\n\nend architecture rtl;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/src/dec_viterbi.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Viterbi decoder top entity, connecting all decoder units.\n--! @author Markus Fehrenz\n--! @date   2011/12/05\n--!\n--! @details\n--! The AXI std_logic_vector input is mapped to an internal information type.\n--! Further the correct output order is handled.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\nuse dec_viterbi.pkg_types.all;\nuse dec_viterbi.pkg_components.all;\nuse dec_viterbi.pkg_trellis.all;\n\n\nentity dec_viterbi_ent is\n\tport(\n\n\t--\n\t-- The core only uses AXI4-Stream interfaces,\n\t-- based on AMBA4 AXI4-Stream Protocol with restrictions according to\n\t-- Xilinx Migration, described in Xilinx AXI Reference UG761 (v13.3).\n\t--\n\n\taclk      : in std_logic;\n\n\t-- Synchronous reset, active low.\n\taresetn   : in std_logic;\n\n\n\t--\n\t-- Slave (input) data signals\n\t-- Delivers the parity LLR values, one byte per LLR value.\n\t--\n\ts_axis_input_tvalid : in std_logic;\n\ts_axis_input_tdata  : in std_logic_vector(31 downto 0);\n\ts_axis_input_tlast  : in std_logic;\n\ts_axis_input_tready : out std_logic;\n\n\n\t--\n\t-- Master (output) data signals\n\t-- Delivers the decoded systematic (payload) bits.\n\t--\n\tm_axis_output_tvalid : out std_logic;\n\tm_axis_output_tdata  : out std_logic;\n\tm_axis_output_tlast  : out std_logic;\n\tm_axis_output_tready : in  std_logic;\n\n\n\t--\n\t-- Slave (input) configuration signals\n\t-- Configures window length and acquisition length.\n\t--\n\ts_axis_ctrl_tvalid : in std_logic;\n\ts_axis_ctrl_tdata  : in std_logic_vector(31 downto 0);\n\ts_axis_ctrl_tlast  : in std_logic;\n\ts_axis_ctrl_tready : out std_logic\n);\nend entity dec_viterbi_ent;\n\n\narchitecture rtl of dec_viterbi_ent is\n\n\talias clk is aclk;\n\tsignal rst : std_logic;\n\n\t-- split tdata into input array\n\tsignal input : t_input_block;\n\n\t-- buffer signals\n\tsignal buffer_tdata  : std_logic_vector(31 downto 0);\n\tsignal buffer_tvalid : std_logic;\n\tsignal buffer_tlast  : std_logic;\n\n\t-- branch signals\n\tsignal branch_tvalid  : std_logic_vector(NUMBER_BRANCH_UNITS - 1 downto 0);\n\tsignal branch_tdata   : t_branch;\n\tsignal branch_tlast   : std_logic_vector(NUMBER_BRANCH_UNITS - 1 downto 0);\n\tsignal branch_tready  : std_logic_vector(NUMBER_BRANCH_UNITS - 1 downto 0);\n\n\t-- acs signals\n\tsignal acs_tvalid     : std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\tsignal acs_tlast      : std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\tsignal acs_tready     : std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\tsignal acs_dec_tdata  : std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\tsignal acs_prob_tdata : t_node;\n\n\t-- ram signals\n\tsignal ram_tready                             : std_logic;\n\tsignal ram_tvalid, ram_tlast, ram_window_tuser, ram_last_tuser : std_logic_vector(1 downto 0);\n\tsignal ram_tdata                                               : t_ram_rd_data;\n\n\t-- traceback signals\n\tsignal traceback_tvalid, traceback_tdata : std_logic_vector(1 downto 0);\n\tsignal traceback_tready, traceback_tlast : std_logic_vector(1 downto 0);\n\tsignal traceback_last_tuser              : std_logic_vector(1 downto 0);\n\n\t-- reorder signals\n\tsignal reorder_tready, reorder_tvalid : std_logic_vector(1 downto 0);\n\tsignal reorder_tdata, reorder_tlast   : std_logic_vector(1 downto 0);\n\tsignal reorder_last_tuser             : std_logic_vector(1 downto 0);\n\n\t-- output signals\n\tsignal output_tready : std_logic_vector(1 downto 0);\n\tsignal current_active : integer range 1 downto 0;\n\nbegin\n\n\t--\n\t-- There is always one byte of data for each LLR value, even though each\n\t-- LLR value is represented with BW_LLR_INPUT bits. Hence, only\n\t-- BW_LLR_INPUT bits are extracted from the byte.\n\t--\n\tgen_input_assignment: for i in NUMBER_PARITY_BITS - 1 downto 0 generate\n\tbegin\n\t\tinput(i) <= signed(buffer_tdata(8 * i + BW_LLR_INPUT - 1 downto 8 * i));\n\tend generate gen_input_assignment;\n\n\trst <= not aresetn;\n\n\t------------------------------\n\t--- Portmapping components ---\n\t------------------------------\n\n\t-------------------------------------\n\t-- AXI4S input buffer\n\t--------------------------------------\n\n\tinst_axi4s_buffer: axi4s_buffer\n\tgeneric map(\n\t\tDATA_WIDTH => 32\n\t)\n\tport map(\n\t\tclk => clk,\n\t\trst => rst,\n\n\t\tinput        => s_axis_input_tdata,\n\t\tinput_valid  => s_axis_input_tvalid,\n\t\tinput_last   => s_axis_input_tlast,\n\t\tinput_accept => s_axis_input_tready,\n\n\t\toutput        => buffer_tdata,\n\t\toutput_valid  => buffer_tvalid,\n\t\toutput_last   => buffer_tlast,\n\t\toutput_accept => branch_tready(0)\n\t);\n\n\t-------------------------------------\n\t-- Branch metric unit\n\t--------------------------------------\n\n\tgen_branch_distance : for i in NUMBER_BRANCH_UNITS - 1 downto 0 generate\n\tbegin\n\t\tinst_branch_distance : branch_distance\n\t\tgeneric map(\n\t\t\tEDGE_WEIGHT => std_logic_vector(to_unsigned(i, NUMBER_PARITY_BITS))\n\t\t)\n\t\tport map(\n\t\t\tclk => clk,\n\t\t\trst => rst,\n\n\t\t\ts_axis_input_tvalid  => buffer_tvalid,\n\t\t\ts_axis_input_tdata   => input,\n\t\t\ts_axis_input_tlast   => buffer_tlast,\n\t\t\ts_axis_input_tready  => branch_tready(i),\n\n\t\t\tm_axis_output_tvalid => branch_tvalid(i),\n\t\t\tm_axis_output_tdata  => branch_tdata(i),\n\t\t\tm_axis_output_tlast  => branch_tlast(i),\n\t\t\tm_axis_output_tready => acs_tready(0)\n\t\t);\n\tend generate gen_branch_distance;\n\n\n\t-------------------------------------\n\t-- ACS unit (path metric calculation)\n\t--------------------------------------\n\n\tgen_acs : for i in 0 to NUMBER_TRELLIS_STATES - 1 generate\n\t\tsignal inbranch_tdata_low  : std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);\n\t\tsignal inbranch_tdata_high : std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);\n\t\tsignal inprev_tdata_low  : std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);\n\t\tsignal inprev_tdata_high : std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);\n\tbegin\n\t\tinbranch_tdata_low  <= branch_tdata(to_integer(unsigned(TRANSITIONS(i)(0))));\n\t\tinbranch_tdata_high <= branch_tdata(to_integer(unsigned(TRANSITIONS(i)(1))));\n\t\tinprev_tdata_low    <= acs_prob_tdata(to_integer(unsigned(PREVIOUS_STATES(i)(0))));\n\t\tinprev_tdata_high   <= acs_prob_tdata(to_integer(unsigned(PREVIOUS_STATES(i)(1))));\n\n\t\tinst_acs : acs\n\t\tgeneric map(\n\t\t\tinitialize_value => INITIALIZE_TRELLIS(i)\n\t\t)\n\t\tport map(\n\t\t\tclk => clk,\n\t\t\trst => rst,\n\n\t\t\ts_axis_inbranch_tvalid     => branch_tvalid(0),\n\t\t\ts_axis_inbranch_tdata_low  => inbranch_tdata_low,\n\t\t\ts_axis_inbranch_tdata_high => inbranch_tdata_high,\n\t\t\ts_axis_inbranch_tlast      => branch_tlast(0),\n\t\t\ts_axis_inbranch_tready     => acs_tready(i),\n\n\t\t\ts_axis_inprev_tvalid     => '1',\n\t\t\ts_axis_inprev_tdata_low  => inprev_tdata_low,\n\t\t\ts_axis_inprev_tdata_high => inprev_tdata_high,\n\t\t\ts_axis_inprev_tready     => open,\n\n\t\t\tm_axis_outprob_tvalid  => open,\n\t\t\tm_axis_outprob_tdata   => acs_prob_tdata(i),\n\t\t\tm_axis_outprob_tready  => '1',\n\n\t\t\tm_axis_outdec_tvalid   => acs_tvalid(i),\n\t\t\tm_axis_outdec_tdata    => acs_dec_tdata(i),\n\t\t\tm_axis_outdec_tlast    => acs_tlast(i),\n\t\t\tm_axis_outdec_tready   => ram_tready\n\t\t);\n\tend generate gen_acs;\n\n\n\t-------------------------------\n\t-- Traceback\n\t-------------------------------\n\n\tinst_ram_ctrl : ram_ctrl\n\tport map (\n\t\tclk => clk,\n\t\trst => rst,\n\n\t\ts_axis_input_tvalid => acs_tvalid(0),\n\t\ts_axis_input_tdata  => acs_dec_tdata,\n\t\ts_axis_input_tlast  => acs_tlast(0),\n\t\ts_axis_input_tready => ram_tready,\n\n\t\tm_axis_output_tvalid       => ram_tvalid,\n\t\tm_axis_output_tdata        => ram_tdata,\n\t\tm_axis_output_tlast        => ram_tlast,\n\t\tm_axis_output_tready       => traceback_tready,\n\t\tm_axis_output_window_tuser => ram_window_tuser,\n\t\tm_axis_output_last_tuser   => ram_last_tuser,\n\n\t\ts_axis_ctrl_tvalid => s_axis_ctrl_tvalid,\n\t\ts_axis_ctrl_tdata  => s_axis_ctrl_tdata,\n\t\ts_axis_ctrl_tready => s_axis_ctrl_tready\n\t);\n\n\n\tgen_inst_trellis_traceback : for i in 1 downto 0 generate\n\tbegin\n\t\tinst_trellis_traceback : trellis_traceback\n\t\tport map(\n\t\t\tclk => clk,\n\t\t\trst => rst,\n\n\t\t\ts_axis_input_tvalid       => ram_tvalid(i),\n\t\t\ts_axis_input_tdata        => ram_tdata(i),\n\t\t\ts_axis_input_tlast        => ram_tlast(i),\n\t\t\ts_axis_input_tready       => traceback_tready(i),\n\t\t\ts_axis_input_window_tuser => ram_window_tuser(i),\n\t\t\ts_axis_input_last_tuser   => ram_last_tuser(i),\n\n\t\t\tm_axis_output_tvalid     => traceback_tvalid(i),\n\t\t\tm_axis_output_tdata      => traceback_tdata(i),\n\t\t\tm_axis_output_tlast      => traceback_tlast(i),\n\t\t\tm_axis_output_last_tuser => traceback_last_tuser(i),\n\t\t\tm_axis_output_tready     => reorder_tready(i)\n\t\t);\n\tend generate gen_inst_trellis_traceback;\n\n\n\t-------------------------------\n\t-- Reverse output order\n\t-------------------------------\n\n\tgen_inst_reorder : for i in 1 downto 0 generate\n\tbegin\n\t\tinst_reorder : reorder\n\t\tport map(\n\t\t\tclk => clk,\n\t\t\trst => rst,\n\n\t\t\ts_axis_input_tvalid     => traceback_tvalid(i),\n\t\t\ts_axis_input_tdata      => traceback_tdata(i),\n\t\t\ts_axis_input_tlast      => traceback_tlast(i),\n\t\t\ts_axis_input_last_tuser => traceback_last_tuser(i),\n\t\t\ts_axis_input_tready     => reorder_tready(i),\n\n\t\t\tm_axis_output_tvalid     => reorder_tvalid(i),\n\t\t\tm_axis_output_tdata      => reorder_tdata(i),\n\t\t\tm_axis_output_tlast      => reorder_tlast(i),\n\t\t\tm_axis_output_last_tuser => reorder_last_tuser(i),\n\t\t\tm_axis_output_tready     => output_tready(i)\n\t\t);\n\tend generate gen_inst_reorder;\n\n\n\t------------------------------\n\t-- Recursive codes handling --\n\t------------------------------\n\n\tgen_inst_recursion : if FEEDBACK_POLYNOMIAL /= 0 generate\n\t\tsignal reorder_recursion_tvalid : std_logic;\n\t\tsignal reorder_recursion_tdata  : std_logic;\n\t\tsignal reorder_recursion_tlast  : std_logic;\n\t\tsignal recursion_tready         : std_logic;\n\tbegin\n\t\tinst_recursion : recursionx\n\t\tport map(\n\t\t\tclk => clk,\n\t\t\trst => rst,\n\n\t\t\ts_axis_input_tvalid     => reorder_recursion_tvalid,\n\t\t\ts_axis_input_tdata      => reorder_recursion_tdata,\n\t\t\ts_axis_input_tlast      => reorder_recursion_tlast,\n\t\t\ts_axis_input_tready     => recursion_tready,\n\n\t\t\tm_axis_output_tvalid     => m_axis_output_tvalid,\n\t\t\tm_axis_output_tdata      => m_axis_output_tdata,\n\t\t\tm_axis_output_tlast      => m_axis_output_tlast,\n\t\t\tm_axis_output_tready     => m_axis_output_tready\n\t\t);\n\n\t\t-------------------------------\n\t\t-- Output interface handling\n\t\t-------------------------------\n\n\t\treorder_recursion_tvalid <= '1' when reorder_tvalid(0) = '1' or reorder_tvalid(1) = '1' else\n\t\t                            '0';\n\n\t\treorder_recursion_tdata  <= reorder_tdata(0) when current_active = 0 else\n\t\t                            reorder_tdata(1);\n\n\t\treorder_recursion_tlast   <= '1' when reorder_tlast(0) = '1' or reorder_tlast(1) = '1' else\n\t\t                            '0';\n\n\t\toutput_tready(0) <= '1' when (current_active = 0) and m_axis_output_tready = '1' else\n\t\t                    '0';\n\t\toutput_tready(1) <= '1' when (current_active = 1) and m_axis_output_tready = '1' else\n\t\t                    '0';\n\tend generate gen_inst_recursion;\n\n\n\n\tno_recursion: if FEEDBACK_POLYNOMIAL = 0 generate\n\n\t\t-------------------------------\n\t\t-- Output interface handling\n\t\t-------------------------------\n\n\t\tm_axis_output_tdata  <= reorder_tdata(0) when current_active = 0 else\n\t\t                        reorder_tdata(1);\n\n\t\tm_axis_output_tvalid <= '1' when reorder_tvalid(0) = '1' or reorder_tvalid(1) = '1' else\n\t\t                        '0';\n\n\t\tm_axis_output_tlast  <= '1' when reorder_tlast(0) = '1' or reorder_tlast(1) = '1' else\n\t\t                        '0';\n\n\t\toutput_tready(0) <= '1' when (current_active = 0) and m_axis_output_tready = '1' else\n\t\t                    '0';\n\t\toutput_tready(1) <= '1' when (current_active = 1) and m_axis_output_tready = '1' else\n\t\t                    '0';\n\tend generate no_recursion;\n\n\n\trecursion : if FEEDBACK_POLYNOMIAL /= 0 generate\n\tbegin\n\tend generate recursion;\n\n\n\t-- Check and merge reordering outputs and block if necessary.\n\tpr_reorder_tready : process(clk) is\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\tcurrent_active <= 0;\n\t\telse\n\t\t\tif reorder_tvalid(current_active) = '1' and m_axis_output_tready = '1' and reorder_last_tuser(current_active) = '1' then\n\t\t\t\tcurrent_active <= 1 - current_active;\n\t\t\tend if;\n\t\tend if;\n\tend if;\n\tend process pr_reorder_tready;\n\nend architecture rtl;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/src/generic_sp_ram.vhd",
    "content": "--!\n--! Copyright (C) 2010 - 2012 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Generic single port RAM with a single read/write port\n--! @author Matthias Alles\n--! @date   2010/09/28\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_helper.all;\n\n\nentity generic_sp_ram is\n\tgeneric(\n\t\tDISTR_RAM  : boolean := false;\n\t\tWORDS      : integer := 8;\n\t\tBITWIDTH   : integer := 8\n\t);\n\tport(\n\t\tclk : in std_logic;\n\t\trst : in std_logic;\n\n\t\twen : in  std_logic;\n\t\ten  : in  std_logic;\n\n\t\ta   : in  std_logic_vector(no_bits_natural(WORDS - 1) - 1 downto 0);\n\t\td   : in  std_logic_vector(BITWIDTH - 1 downto 0);\n\t\tq   : out std_logic_vector(BITWIDTH - 1 downto 0)\n\t);\nend generic_sp_ram;\n\n\narchitecture rtl of generic_sp_ram is\n\n\ttype t_ram is array(WORDS - 1 downto 0) of\n\t                      std_logic_vector(BITWIDTH - 1 downto 0);\n\tsignal sp_ram : t_ram := (others => (others => '0'));\n\n\tfunction get_ram_style_xilinx(dist_ram : in boolean) return string is\n\tbegin\n\t\tif dist_ram then\n\t\t\treturn \"pipe_distributed\";\n\t\telse\n\t\t\treturn \"block\";\n\t\tend if;\n\tend function;\n\n\tfunction get_ram_style_altera(dist_ram : in boolean) return string is\n\tbegin\n\t\tif dist_ram then\n\t\t\treturn \"MLAB, no_rw_check\";\n\t\telse\n\t\t\treturn \"AUTO\";\n\t\tend if;\n\tend function;\n\n\tattribute RAM_STYLE : string;\n\tattribute RAM_STYLE of sp_ram : signal is get_ram_style_xilinx(DISTR_RAM);\n\n\tattribute ramstyle : string;\n\tattribute ramstyle of sp_ram : signal is get_ram_style_altera(DISTR_RAM);\n\nbegin\n\n\t--\n\t-- Do not register the address for reading, since the synthesis doesn't\n\t-- recognize then that this is a single-port RAM.\n\t--\n\tpr_sp_ram_rw: process(clk)\n\tbegin\n\tif rising_edge(clk) then\n\t\tif en = '1' then\n\t\t\tif wen =  '1' then\n\t\t\t\tsp_ram(to_integer(unsigned(a))) <= d;\n\t\t\telse\n\t\t\t\tq <= sp_ram(to_integer(unsigned(a)));\n\t\t\tend if;\n\t\tend if;\n\tend if;\n\tend process pr_sp_ram_rw;\n\nend rtl;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/src/ram_ctrl.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Viterbi decoder RAM control\n--! @author Markus Fehrenz\n--! @date   2011/12/13\n--!\n--! @details Manage RAM behavior. Write and read data.\n--! The decisions are sent to the traceback units\n--! It is signaled if the data belongs to acquisition or window phase.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\nuse dec_viterbi.pkg_types.all;\nuse dec_viterbi.pkg_components.all;\n\n\nentity ram_ctrl is\n\tport(\n\tclk       : in std_logic;\n\trst       : in std_logic;\n\n\n\t--\n\t-- Slave data signals, delivers the LLR parity values.\n\t--\n\ts_axis_input_tvalid : in  std_logic;\n\ts_axis_input_tdata  : in  std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\ts_axis_input_tlast  : in  std_logic;\n\ts_axis_input_tready : out std_logic;\n\n\n\t--\n\t-- Master data signals for traceback units, delivers the decision vectors.\n\t--\n\tm_axis_output_tvalid       : out std_logic_vector(1 downto 0);\n\tm_axis_output_tdata        : out t_ram_rd_data;\n\tm_axis_output_tlast        : out std_logic_vector(1 downto 0);\n\tm_axis_output_tready       : in  std_logic_vector(1 downto 0);\n\n\t-- Signals the traceback unit when the decision bits do not belong to an acquisition.\n\tm_axis_output_window_tuser : out std_logic_vector(1 downto 0);\n\n\t-- Signals whether this is the last decision vector of the window.\n\tm_axis_output_last_tuser   : out std_logic_vector(1 downto 0);\n\n\n\t--\n\t-- Slave configuration signals, delivering the configuration data.\n\t--\n\n\ts_axis_ctrl_tvalid : in  std_logic;\n\ts_axis_ctrl_tdata  : in  std_logic_vector(31 downto 0);\n\ts_axis_ctrl_tready : out std_logic\n);\nend entity ram_ctrl;\n\n\narchitecture rtl of ram_ctrl is\n\n\t------------------------\n\t-- Type definition\n\t------------------------\n\n\t--\n\t-- Record contains runtime configuration.\n\t-- The input configuration is stored in a register.\n\t-- It is received from a AXI4-Stream interface from the top entity.\n\t--\n\ttype trec_runtime_param is record\n\t\twindow_length           : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);\n\t\tacquisition_length      : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);\n\tend record trec_runtime_param;\n\n\t-- Types for finite state machines\n\ttype t_write_ram_fsm is (CONFIGURE, START, RUN, WAIT_FOR_TRACEBACK, WAIT_FOR_LAST_TRACEBACK);\n\ttype t_read_ram_fsm is (WAIT_FOR_WINDOW, TRACEBACK, WAIT_FOR_RAM, FINISH);\n\ttype t_read_ram_fsm_array is array (0 to 1) of t_read_ram_fsm;\n\n\t-- RAM controlling types\n\ttype t_ram_data    is array (3 downto 0) of std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\ttype t_ram_addr    is array (3 downto 0) of unsigned(BW_MAX_WINDOW_LENGTH - 1  downto 0);\n\ttype t_ram_rd_addr is array (1 downto 0) of unsigned(BW_MAX_WINDOW_LENGTH - 1  downto 0);\n\ttype t_ram_ptr     is array (1 downto 0) of unsigned(1 downto 0);\n\ttype t_ram_ptr_int is array (1 downto 0) of integer range 3 downto 0;\n\n\ttype t_ram_data_cnt is array (1 downto 0) of integer range 2 * MAX_WINDOW_LENGTH downto 0;\n\n\n\t------------------------\n\t-- Signal declaration\n\t------------------------\n\n\tsignal ram_buffer   : t_ram_rd_data;\n\tsignal ram_buffer_full   : std_logic_vector(1 downto 0);\n\n\tsignal config          : trec_runtime_param;\n\tsignal write_ram_fsm   : t_write_ram_fsm;\n\tsignal read_ram_fsm    : t_read_ram_fsm_array;\n\tsignal wen_ram         : std_logic_vector(3 downto 0);\n\tsignal addr            : t_ram_addr;\n\tsignal q_reg           : t_ram_data;\n\n\t-- ram address, number and data pointer\n\tsignal write_ram_ptr  : unsigned(1 downto 0);\n\tsignal read_ram_ptr   : t_ram_ptr;\n\tsignal read_ram_ptr_d : t_ram_ptr;\n\tsignal write_addr_ptr : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);\n\tsignal read_addr_ptr  : t_ram_rd_addr;\n\n\t-- internal signals of outputs\n\tsignal m_axis_output_tvalid_int       : std_logic_vector(1 downto 0);\n\tsignal m_axis_output_tlast_int       : std_logic_vector(1 downto 0);\n\tsignal m_axis_output_window_tuser_int : std_logic_vector(1 downto 0);\n\tsignal m_axis_output_last_tuser_int   : std_logic_vector(1 downto 0);\n\tsignal s_axis_input_tready_int        : std_logic;\n\tsignal s_axis_ctrl_tready_int         : std_logic;\n\n\tsignal next_traceback : std_logic_vector(1 downto 0);\n\tsignal write_window_complete : std_logic;\n\tsignal write_last_window_complete : std_logic;\n\tsignal last_of_block : std_logic;\n\tsignal read_last_addr_ptr : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);\nbegin\n\n\tm_axis_output_tvalid       <= m_axis_output_tvalid_int;\n\tm_axis_output_tlast        <= m_axis_output_tlast_int;\n\tm_axis_output_window_tuser <= m_axis_output_window_tuser_int;\n\tm_axis_output_last_tuser   <= m_axis_output_last_tuser_int;\n\tm_axis_output_tdata(0)     <= q_reg(to_integer(read_ram_ptr_d(0))) when ram_buffer_full(0) = '0' else ram_buffer(0);\n\tm_axis_output_tdata(1)     <= q_reg(to_integer(read_ram_ptr_d(1))) when ram_buffer_full(1) = '0' else ram_buffer(1);\n\n\n\t--\n\t-- When the output port is not ready to read the output of the RAM immediately\n\t-- we have to remember the output value of the RAM in an extra register.\n\t-- When the output is ready to read, we first use the output of the register\n\t-- and only then the output of the RAM again.\n\t--\n\tpr_buf_ram_output: process(clk) is\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\tram_buffer <= (others => (others => '0'));\n\t\t\tram_buffer_full <= (others => '0');\n\t\telse\n\n\t\t\tfor i in 0 to 1 loop\n\t\t\t\tif m_axis_output_tvalid_int(i) = '1' and m_axis_output_tready(i) = '0' and ram_buffer_full(i) = '0' then\n\t\t\t\t\tram_buffer(i) <=  q_reg(to_integer(read_ram_ptr_d(i)));\n\t\t\t\t\tram_buffer_full(i) <= '1';\n\t\t\t\tend if;\n\n\t\t\t\tif m_axis_output_tvalid_int(i) = '1' and m_axis_output_tready(i) = '1' and ram_buffer_full(i) = '1' then\n\t\t\t\t\tram_buffer_full(i) <= '0';\n\t\t\t\tend if;\n\t\t\tend loop;\n\n\t\tend if;\n\tend if;\n\tend process pr_buf_ram_output;\n\n\t-----------------------------\n\t-- Manage writing from ACS --\n\t-----------------------------\n\ts_axis_input_tready_int <= '0' when (write_ram_fsm = CONFIGURE) or\n\t                           (write_ram_ptr = read_ram_ptr(0) and read_ram_fsm(0) /= WAIT_FOR_WINDOW) or\n\t                           (write_ram_ptr = read_ram_ptr(1) and read_ram_fsm(1) /= WAIT_FOR_WINDOW) or\n\t                            write_ram_fsm = WAIT_FOR_TRACEBACK or write_ram_fsm = WAIT_FOR_LAST_TRACEBACK else\n\t                           '1';\n\ts_axis_input_tready <= s_axis_input_tready_int;\n\n\ts_axis_ctrl_tready_int <= '1' when (read_ram_fsm(0) = WAIT_FOR_WINDOW and read_ram_fsm(1) = WAIT_FOR_WINDOW and write_ram_fsm = CONFIGURE) else\n\t                          '0';\n\ts_axis_ctrl_tready <= s_axis_ctrl_tready_int;\n\n\t-- Process for writing to the RAM\n\tpr_write_ram: process(clk) is\n\t\tvariable v_window_length      : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);\n\t\tvariable v_acquisition_length : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\twrite_ram_fsm         <= CONFIGURE;\n\t\t\twrite_addr_ptr        <= (others => '0');\n\t\t\twrite_ram_ptr         <= (others => '0');\n\t\t\twen_ram               <= (others => '0');\n\t\t\twrite_window_complete <= '0';\n\t\t\twrite_last_window_complete <= '0';\n\t\t\tread_last_addr_ptr    <= (others => '0');\n\t\telse\n\n\t\t\tcase write_ram_fsm is\n\n\t\t\t--\n\t\t\t-- It is necessary to configure the decoder before each block\n\t\t\t--\n\t\t\twhen CONFIGURE =>\n\t\t\t\twrite_window_complete <= '0';\n\t\t\t\twrite_last_window_complete <= '0';\n\t\t\t\tif s_axis_ctrl_tvalid = '1' and s_axis_ctrl_tready_int = '1' then\n\t\t\t\t\tv_window_length           := unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1 + 16 downto 16));\n\t\t\t\t\tv_acquisition_length      := unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1      downto  0));\n\t\t\t\t\twrite_addr_ptr            <= v_window_length - v_acquisition_length;\n\t\t\t\t\tconfig.window_length      <= v_window_length;\n\t\t\t\t\tconfig.acquisition_length <= v_acquisition_length;\n\t\t\t\t\twrite_ram_fsm             <= START;\n\n\t\t\t\t\twen_ram(to_integer(write_ram_ptr)) <= '1';\n\t\t\t\tend if;\n\n\n\t\t\t--\n\t\t\t-- After the decoder is configured, the decoder is waiting for a new block.\n\t\t\t-- When the AXIS handshake is there the packet transmission begins.\n\t\t\t-- The first write is a special case, since writing data starts at the acquisition length.\n\t\t\t-- There is no complete window available afterwards.\n\t\t\t--\n\t\t\twhen START =>\n\t\t\t\tif s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then\n\n\t\t\t\t\tif write_addr_ptr = config.window_length - 1 then\n\n\t\t\t\t\t\t-- When we switch to the next RAM, we reset the write addr.\n\t\t\t\t\t\twrite_addr_ptr <= (others => '0');\n\n\t\t\t\t\t\t-- Switch to the next RAM.\n\t\t\t\t\t\twrite_ram_ptr                          <= write_ram_ptr + 1;\n\t\t\t\t\t\twen_ram(to_integer(write_ram_ptr))     <= '0';\n\t\t\t\t\t\twen_ram(to_integer(write_ram_ptr + 1)) <= '1';\n\n\t\t\t\t\t\twrite_ram_fsm  <= RUN;\n\t\t\t\t\telse\n\t\t\t\t\t\twrite_addr_ptr <= write_addr_ptr + 1;\n\t\t\t\t\tend if;\n\t\t\t\tend if;\n\n\n\t\t\t--\n\t\t\t-- The decoder is receiving data from the ACS.\n\t\t\t--\n\t\t\twhen RUN =>\n\t\t\t\twrite_window_complete <= '0';\n\t\t\t\twrite_last_window_complete <= '0';\n\n\t\t\t\tif s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then\n\t\t\t\t\twrite_addr_ptr <= write_addr_ptr + 1;\n\n\t\t\t\t\tif write_addr_ptr = config.window_length - 1 then\n\n\t\t\t\t\t\t-- When we switch to the next RAM, we reset the write addr.\n\t\t\t\t\t\twrite_addr_ptr <= (others => '0');\n\n\t\t\t\t\t\t-- Switch to the next RAM.\n\t\t\t\t\t\twrite_ram_ptr                          <= write_ram_ptr + 1;\n\t\t\t\t\t\twen_ram(to_integer(write_ram_ptr))     <= '0';\n\t\t\t\t\t\twen_ram(to_integer(write_ram_ptr + 1)) <= '1';\n\n\t\t\t\t\t\t-- Indicate, that a complete window is within the RAM and traceback may start.\n\t\t\t\t\t\twrite_window_complete <= '1';\n\n\t\t\t\t\t\tif read_ram_fsm(0) /= WAIT_FOR_WINDOW and read_ram_fsm(1) /= WAIT_FOR_WINDOW then\n\t\t\t\t\t\t\twrite_ram_fsm <= WAIT_FOR_TRACEBACK;\n\t\t\t\t\t\tend if;\n\n\t\t\t\t\telse\n\t\t\t\t\t\twrite_addr_ptr <= write_addr_ptr + 1;\n\t\t\t\t\tend if;\n\n\t\t\t\t\tif s_axis_input_tlast = '1' then\n\t\t\t\t\t\twrite_ram_fsm <= CONFIGURE;\n\t\t\t\t\t\twen_ram       <= (others => '0');\n\n\t\t\t\t\t\twrite_last_window_complete <= '1';\n\t\t\t\t\t\tif (read_ram_fsm(0) /= WAIT_FOR_WINDOW and read_ram_fsm(1) /= WAIT_FOR_WINDOW) or write_window_complete = '1' then\n\t\t\t\t\t\t\twrite_ram_fsm <= WAIT_FOR_LAST_TRACEBACK;\n\t\t\t\t\t\tend if;\n\t\t\t\t\t\tread_last_addr_ptr <= write_addr_ptr;\n\n\t\t\t\t\t\twrite_addr_ptr <= (others => '0');\n\t\t\t\t\t\twrite_ram_ptr                          <= write_ram_ptr + 1;\n\t\t\t\t\tend if;\n\t\t\t\tend if;\n\n\t\t\twhen WAIT_FOR_TRACEBACK =>\n\t\t\t\tif read_ram_fsm(0) = WAIT_FOR_WINDOW or read_ram_fsm(1) = WAIT_FOR_WINDOW then\n\t\t\t\t\twrite_ram_fsm <= RUN;\n\t\t\t\t\twrite_window_complete <= '0';\n\t\t\t\tend if;\n\n\t\t\twhen WAIT_FOR_LAST_TRACEBACK =>\n\t\t\t\tif read_ram_fsm(0) = WAIT_FOR_WINDOW or read_ram_fsm(1) = WAIT_FOR_WINDOW then\n\t\t\t\t\twrite_ram_fsm <= CONFIGURE;\n\t\t\t\t\twrite_last_window_complete <= '0';\n\t\t\t\tend if;\n\n\t\t\tend case;\n\t\tend if;\n\tend if;\n\tend process pr_write_ram;\n\n\n\t-------------------------------------------\n\t-- Manage reading from RAM for traceback --\n\t-------------------------------------------\n\n\tgen_read_ram: for i in 0 to 1 generate\n\t\tpr_read_ram: process(clk) is\n\t\tbegin\n\t\tif rising_edge(clk) then\n\t\t\tif rst = '1' then\n\t\t\t\tread_addr_ptr(i) <= (others => '0');\n\t\t\t\tread_ram_fsm(i)  <= WAIT_FOR_WINDOW;\n\t\t\t\tm_axis_output_tvalid_int(i)       <= '0';\n\t\t\t\tm_axis_output_tlast_int(i)        <= '0';\n\t\t\t\tm_axis_output_window_tuser_int(i) <= '0';\n\t\t\t\tm_axis_output_last_tuser_int(i)   <= '0';\n\t\t\t\tread_ram_ptr(i)                   <= (others => '0');\n\t\t\t\tread_ram_ptr_d(i)                 <= (others => '0');\n\t\t\telse\n\n\t\t\t\tread_ram_ptr_d(i) <= read_ram_ptr(i);\n\t\t\t\tcase read_ram_fsm(i) is\n\n\t\t\t\t-- Wait for the next window to be ready within the RAM.\n\t\t\t\twhen WAIT_FOR_WINDOW =>\n\t\t\t\t\tread_addr_ptr(i) <= config.window_length - 1;\n\t\t\t\t\tm_axis_output_tlast_int(i) <= '0';\n\t\t\t\t\tm_axis_output_tvalid_int(i) <= '0';\n\t\t\t\t\tm_axis_output_last_tuser_int(i) <= '0';\n\t\t\t\t\tm_axis_output_window_tuser_int(i) <= '0';\n\t\t\t\t\tread_ram_ptr(i)   <= write_ram_ptr;\n\n\t\t\t\t\t-- We always start from the RAM, which was written last.\n\t\t\t\t\tif write_window_complete = '1' and next_traceback(i) = '1' then\n\t\t\t\t\t\tread_ram_ptr(i)   <= write_ram_ptr - 1;\n\t\t\t\t\t\tread_addr_ptr(i)            <= read_addr_ptr(i) - 1;\n\t\t\t\t\t\tread_ram_fsm(i)             <= TRACEBACK;\n\t\t\t\t\t\tm_axis_output_tvalid_int(i) <= '1';\n\t\t\t\t\tend if;\n\t\t\t\t\tif write_last_window_complete = '1' and next_traceback(i) = '1' then\n\t\t\t\t\t\tread_ram_ptr(i)   <= write_ram_ptr - 1;\n\t\t\t\t\t\tread_addr_ptr(i)            <= read_last_addr_ptr;\n\t\t\t\t\t\tread_ram_fsm(i)             <= TRACEBACK;\n\t\t\t\t\t\tm_axis_output_window_tuser_int(i) <= '1';\n\t\t\t\t\tend if;\n\n\t\t\t\t-- Perform the Traceback on the RAM data of the first RAM we need for acquisition and traceback.\n\t\t\t\twhen TRACEBACK =>\n\t\t\t\t\tm_axis_output_tlast_int(i) <= '0';\n\t\t\t\t\tm_axis_output_last_tuser_int(i) <= '0';\n\t\t\t\t\tm_axis_output_tvalid_int(i) <= '1';\n\n\t\t\t\t\tif m_axis_output_tready(i) = '1' then\n\t\t\t\t\t\tif read_addr_ptr(i) = 0 then\n\t\t\t\t\t\t\tif read_ram_fsm(1 - i) = TRACEBACK and read_ram_ptr(1 - i) = read_ram_ptr(i) - 1 then\n\t\t\t\t\t\t\t\tread_ram_fsm(i) <= WAIT_FOR_RAM;\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tread_addr_ptr(i) <= config.window_length - 1;\n\t\t\t\t\t\t\t\tread_ram_ptr(i)  <= read_ram_ptr(i) - 1;\n\t\t\t\t\t\t\t\tread_ram_fsm(i)  <= FINISH;\n\t\t\t\t\t\t\tend if;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tread_addr_ptr(i) <= read_addr_ptr(i) - 1;\n\t\t\t\t\t\tend if;\n\n\t\t\t\t\t\t-- Signal the traceback unit, acquisition is over.\n\t\t\t\t\t\tif read_addr_ptr(i) = config.window_length - config.acquisition_length - 1 then\n\t\t\t\t\t\t\tm_axis_output_window_tuser_int(i) <= '1';\n\t\t\t\t\t\tend if;\n\t\t\t\t\tend if;\n\n\t\t\t\twhen WAIT_FOR_RAM =>\n\t\t\t\t\tm_axis_output_tvalid_int(i) <= '0';\n\t\t\t\t\tif read_ram_fsm(1 - i) /= TRACEBACK or read_ram_ptr(1 - i) /= read_ram_ptr(i) - 1 then\n\t\t\t\t\t\tread_addr_ptr(i) <= config.window_length - 1;\n\t\t\t\t\t\tread_ram_ptr(i)  <= read_ram_ptr(i) - 1;\n\t\t\t\t\t\tread_ram_fsm(i)  <= FINISH;\n\t\t\t\t\tend if;\n\n\t\t\t\t-- Get the remaining values from the second RAM we need for traceback (no acquisition values in this RAM)\n\t\t\t\twhen FINISH =>\n\t\t\t\t\tif m_axis_output_tvalid_int(i) <= '0' then\n\t\t\t\t\t\tm_axis_output_tvalid_int(i) <= '1';\n\t\t\t\t\t\tread_addr_ptr(i) <= read_addr_ptr(i) - 1;\n\t\t\t\t\tend if;\n\t\t\t\t\tif m_axis_output_tready(i) = '1' then\n\n\t\t\t\t\t\tif read_addr_ptr(i) = config.window_length - config.acquisition_length then\n\t\t\t\t\t\t\tm_axis_output_last_tuser_int(i) <= '1';\n\t\t\t\t\t\t\tread_addr_ptr(i)        <= config.window_length - 1;\n\t\t\t\t\t\t\tread_ram_fsm(i)         <= WAIT_FOR_WINDOW;\n\n\t\t\t\t\t\t\t-- Check if the other read process finished processing.\n\t\t\t\t\t\t\tif read_ram_fsm((i+1) mod 2) = WAIT_FOR_WINDOW and last_of_block = '1' then\n\t\t\t\t\t\t\t\tm_axis_output_tlast_int(i) <= '1';\n\t\t\t\t\t\t\tend if;\n\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tread_addr_ptr(i) <= read_addr_ptr(i) - 1;\n\t\t\t\t\t\tend if;\n\t\t\t\t\tend if;\n\t\t\t\tend case;\n\t\t\tend if;\n\t\tend if;\n\t\tend process pr_read_ram;\n\tend generate gen_read_ram;\n\n\t-- This process decides which traceback unit is the next one to use.\n\tpr_next_traceback: process(clk) is\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\tnext_traceback <= \"01\";\n\t\t\tlast_of_block  <= '0';\n\t\telse\n\t\t\tif write_window_complete = '1' then\n\t\t\t\tif next_traceback(0) = '1' then\n\t\t\t\t\tnext_traceback(0) <= '0';\n\t\t\t\t\tnext_traceback(1) <= '1';\n\t\t\t\telse\n\t\t\t\t\tnext_traceback(0) <= '1';\n\t\t\t\t\tnext_traceback(1) <= '0';\n\t\t\t\tend if;\n\t\t\tend if;\n\n\t\t\tif s_axis_input_tlast = '1' then\n\t\t\t\tlast_of_block <= '1';\n\t\t\tend if;\n\n\t\tend if;\n\tend if;\n\tend process pr_next_traceback;\n\n\t------------------------------\n\t--- Portmapping components ---\n\t------------------------------\n\n\tgen_generic_sp_ram : for i in 0 to 3 generate\n\tbegin\n\n\taddr(i) <= write_addr_ptr   when (write_ram_fsm = RUN or write_ram_fsm = START) and to_integer(write_ram_ptr) = i else\n\t           read_addr_ptr(0) when (to_integer(read_ram_ptr(0)) = i and (read_ram_fsm(0) = TRACEBACK or read_ram_fsm(0) = WAIT_FOR_RAM or read_ram_fsm(0) = FINISH)) or\n\t                                 (next_traceback(0) = '1' and write_window_complete = '1' and to_integer(read_ram_ptr(0)) = i) else\n\t           read_addr_ptr(1);\n\n\tinst_generic_sp_ram : generic_sp_ram\n\tgeneric map(\n\t\tDISTR_RAM => DISTRIBUTED_RAM,\n\t\tWORDS     => MAX_WINDOW_LENGTH,\n\t\tBITWIDTH  => NUMBER_TRELLIS_STATES\n\t)\n\tport map(\n\t\tclk => clk,\n\t\trst => rst,\n\t\twen => wen_ram(i),\n\t\ten  => '1',\n\t\ta   => std_logic_vector(addr(i)),\n\t\td   => s_axis_input_tdata,\n\t\tq   => q_reg(i)\n\t);\n\tend generate gen_generic_sp_ram;\n\nend architecture rtl;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/src/recursion.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Recursion unit for recursive code.\n--! @author Markus Fehrenz\n--! @date   2011/01/12\n--!\n--! @details The recursion handling buffers the reorder output and\n--! calculates the correct output depending on the feedback polynomial.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\n\nentity recursionx is\n\tport(\n\tclk : in std_logic;\n\trst : in std_logic;\n\n\t--\n\t-- Decoded bits input from the reordering units in std_logic\n\t--\n\ts_axis_input_tvalid : in  std_logic;\n\ts_axis_input_tdata  : in  std_logic;\n\ts_axis_input_tlast  : in  std_logic;\n\ts_axis_input_tready : out std_logic;\n\n\t--\n\t-- Output decoded bits convolved with the feedback polynomial\n\t--\n\tm_axis_output_tvalid : out std_logic;\n\tm_axis_output_tdata  : out std_logic;\n\tm_axis_output_tlast  : out std_logic;\n\tm_axis_output_tready : in  std_logic\n\t);\nend entity recursionx;\n\narchitecture rtl of recursionx is\n\tsignal recursion_sreg : unsigned(ENCODER_MEMORY_DEPTH downto 0);\n\tsignal s_axis_input_tready_int  : std_logic;\n\tsignal m_axis_output_tvalid_int : std_logic;\n\nbegin\n\ts_axis_input_tready_int <= '1' when m_axis_output_tready = '1' or m_axis_output_tvalid_int = '0' else\n\t                           '0';\n\n\ts_axis_input_tready  <= s_axis_input_tready_int;\n\tm_axis_output_tvalid <= m_axis_output_tvalid_int;\n\n\t-- Use the feedback polynomial to convolve the global path.\n\tpr_recursion : process(clk) is\n\t\tvariable v_bit : std_logic := '0';\n\t\tvariable v_recursion_state : unsigned(ENCODER_MEMORY_DEPTH downto 0);\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\trecursion_sreg <= (others => '0');\n\t\t\tm_axis_output_tdata  <= '0';\n\t\t\tm_axis_output_tlast  <= '0';\n\t\telse\n\t\t\tm_axis_output_tvalid_int <= s_axis_input_tvalid;\n\n\t\t\tif s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then\n\n\t\t\t\t-- move current decoded output bits into shift register and reset if last flag is valid\n\t\t\t\tif s_axis_input_tlast = '1' then\n\t\t\t\t\trecursion_sreg <= (others => '0');\n\t\t\t\telse\n\t\t\t\t\trecursion_sreg <= s_axis_input_tdata & recursion_sreg(ENCODER_MEMORY_DEPTH downto 1);\n\t\t\t\tend if;\n\n\t\t\t\t-- convolve with feedback polynomial with the output register.\n\t\t\t\tv_bit := '0';\n\t\t\t\tv_recursion_state := (s_axis_input_tdata & recursion_sreg(ENCODER_MEMORY_DEPTH downto 1)) and\n\t\t\t\t                     ('1' & to_unsigned(FEEDBACK_POLYNOMIAL, ENCODER_MEMORY_DEPTH));\n\t\t\t\tfor i in ENCODER_MEMORY_DEPTH downto 0 loop\n\t\t\t\t\tv_bit := v_bit xor v_recursion_state(i);\n\t\t\t\tend loop;\n\t\t\t\tm_axis_output_tdata <= v_bit;\n\n\t\t\t\tm_axis_output_tlast <= s_axis_input_tlast;\n\t\t\tend if;\n\t\tend if;\n\tend if;\n\tend process pr_recursion;\n\nend architecture rtl;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/src/reorder.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Reorder twisted output due to windowing\n--! @author Markus Fehrenz\n--! @date   2011/05/12\n--!\n--! @details The windowing output is twisted.\n--!          The correct order is simply rebuilt by reversing\n--!          the output of each traceback unit.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\nuse dec_viterbi.pkg_types.all;\n\n\nentity reorder is\n\tport(\n\t\tclk :   in std_logic;\n\t\trst :   in std_logic;\n\n\t\t--\n\t\t-- Traceback unit output, twisted order\n\t\t--\n\t\ts_axis_input_tvalid     : in  std_logic;\n\t\ts_axis_input_tdata      : in  std_logic;\n\t\ts_axis_input_tlast      : in  std_logic;\n\t\ts_axis_input_last_tuser : in  std_logic;\n\t\ts_axis_input_tready     : out std_logic;\n\n\t\t--\n\t\t-- Viterbi decoder output, original (input) order.\n\t\t--\n\t\tm_axis_output_tvalid     : out std_logic;\n\t\tm_axis_output_tdata      : out std_logic;\n\t\tm_axis_output_tlast      : out std_logic;\n\t\tm_axis_output_last_tuser : out std_logic; -- Last bit of one traceback window\n\t\tm_axis_output_tready     : in  std_logic\n\t);\nend entity reorder;\n\n\narchitecture rtl of reorder is\n\n\t-- used to store one reversed output of a traceback unit\n\tsignal buffer_sreg              : unsigned(MAX_WINDOW_LENGTH - 1 downto 0);\n\tsignal buffer_cnt               : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);\n\tsignal buffer_end               : integer range ENCODER_MEMORY_DEPTH downto 0;\n\tsignal send_output, last_window : boolean;\n\n\tsignal s_axis_input_tready_int  : std_logic;\n\nbegin\n\n\ts_axis_input_tready     <= s_axis_input_tready_int;\n\ts_axis_input_tready_int <= '1' when not(send_output) else\n\t                           '0';\n\n-- \tm_axis_output_tvalid     <= '1' when send_output and m_axis_output_tready= '1' else\n\tm_axis_output_tvalid     <= '1' when send_output else\n\t                            '0';\n\tm_axis_output_tdata      <= buffer_sreg(0);\n\n\tm_axis_output_tlast      <= '1' when buffer_cnt = ENCODER_MEMORY_DEPTH  and last_window else\n\t                            '0';\n\n\t-- Reorder the global path given from an traceback unit with the help of a shift register.\n\tpr_reorder : process(clk) is\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\tbuffer_sreg              <= (others => '0');\n\t\t\tbuffer_cnt               <= (others => '0');\n\t\t\tsend_output              <= false;\n\t\t\tlast_window              <= false;\n\t\t\tbuffer_end               <= 0;\n\t\t\tm_axis_output_last_tuser <= '0';\n\t\telse\n\n\t\t\t-- store output of traceback unit\n\t\t\tif s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then\n\t\t\t\tif s_axis_input_tlast = '1' then\n\t\t\t\t\tlast_window <= true;\n\t\t\t\t\tbuffer_end <= ENCODER_MEMORY_DEPTH;\n\t\t\t\tend if;\n\t\t\t\tif s_axis_input_last_tuser = '1' then\n\t\t\t\t\tsend_output <= true;\n\t\t\t\t\tbuffer_sreg <= buffer_sreg(MAX_WINDOW_LENGTH - 2 downto 0) & s_axis_input_tdata;\n\t\t\t\telse\n\t\t\t\t\tbuffer_sreg <= buffer_sreg(MAX_WINDOW_LENGTH - 2 downto 0) & s_axis_input_tdata;\n\t\t\t\t\tbuffer_cnt  <= buffer_cnt + 1;\n\t\t\t\tend if;\n\t\t\tend if;\n\n\t\t\t-- send reordered data to the output\n\t\t\tif m_axis_output_tready = '1' and send_output then\n\t\t\t\tbuffer_sreg <= '0' & buffer_sreg(MAX_WINDOW_LENGTH - 1 downto 1);\n\n\t\t\t\t-- Next transfer will be the last one of this window.\n\t\t\t\tif buffer_cnt = 1 then\n\t\t\t\t\tm_axis_output_last_tuser <= '1';\n\t\t\t\tend if;\n\n\t\t\t\t-- This was the last data transfer. Tailbits are cut off\n\t\t\t\tif buffer_cnt = buffer_end then\n\t\t\t\t\tsend_output              <= false;\n\t\t\t\t\tlast_window              <= false;\n\t\t\t\t\tbuffer_end               <= 0;\n\t\t\t\t\tbuffer_cnt               <= (others => '0');\n\t\t\t\t\tm_axis_output_last_tuser <= '0';\n\t\t\t\telse\n\t\t\t\t\tbuffer_cnt <= buffer_cnt - 1;\n\t\t\t\tend if;\n\t\t\tend if;\n\t\tend if;\n\tend if;\n\tend process pr_reorder;\n\nend architecture rtl;\n"
  },
  {
    "path": "tests/designs/viterbi_decoder_axi4s/src/traceback.vhd",
    "content": "--!\n--! Copyright (C) 2011 - 2014 Creonic GmbH\n--!\n--! This file is part of the Creonic Viterbi Decoder, which is distributed\n--! under the terms of the GNU General Public License version 2.\n--!\n--! @file\n--! @brief  Traceback unit for a viterbi decoder\n--! @author Markus Fehrenz\n--! @date   2011/07/11\n--!\n--! @details The traceback unit only processes a data stream.\n--! There is no knowledge about the decoder configuration.\n--! The information about acquisition and window lengths is received from ram control.\n--!\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n\nlibrary dec_viterbi;\nuse dec_viterbi.pkg_param.all;\nuse dec_viterbi.pkg_param_derived.all;\n\n\nentity trellis_traceback is\n\tport(\n\t\t-- general signals\n\t\tclk : in std_logic;\n\t\trst : in std_logic;\n\n\t\ts_axis_input_tvalid       : in  std_logic;\n\t\ts_axis_input_tdata        : in  std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);\n\t\ts_axis_input_tlast        : in  std_logic;\n\t\ts_axis_input_tready       : out std_logic;\n\t\ts_axis_input_window_tuser : in  std_logic;\n\t\ts_axis_input_last_tuser   : in  std_logic;\n\n\t\tm_axis_output_tvalid     : out std_logic;\n\t\tm_axis_output_tdata      : out std_logic;\n\t\tm_axis_output_tlast      : out std_logic;\n\t\tm_axis_output_last_tuser : out std_logic;\n\t\tm_axis_output_tready     : in  std_logic\n\t);\nend entity trellis_traceback;\n\n\narchitecture rtl of trellis_traceback is\n\n\tsignal current_node               : unsigned(BW_TRELLIS_STATES - 1 downto 0);\n\tsignal m_axis_output_tvalid_int   : std_logic;\n\tsignal s_axis_input_tready_int    : std_logic;\n\nbegin\n\ts_axis_input_tready_int <= '1' when m_axis_output_tready = '1' or m_axis_output_tvalid_int = '0' else\n\t                           '0';\n\ts_axis_input_tready <= s_axis_input_tready_int;\n\n\tm_axis_output_tvalid <= m_axis_output_tvalid_int;\n\n\n\t-- Traceback the ACS local path decisions and output the resulting global path.\n\tpr_traceback : process(clk) is\n\tbegin\n\tif rising_edge(clk) then\n\t\tif rst = '1' then\n\t\t\tm_axis_output_tvalid_int   <= '0';\n\t\t\tm_axis_output_tdata        <= '0';\n\t\t\tm_axis_output_tlast        <= '0';\n\t\t\tm_axis_output_last_tuser   <= '0';\n\t\t\tcurrent_node               <= (others => '0');\n\t\telse\n\n\t\t\tif m_axis_output_tready = '1' then\n\t\t\t\tm_axis_output_tvalid_int <= '0';\n\t\t\tend if;\n\n\t\t\t-- calculate the decoded bit with an shift register\n\t\t\tif s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then\n\n\t\t\t\tm_axis_output_tlast      <= s_axis_input_tlast;\n\t\t\t\tm_axis_output_last_tuser <= s_axis_input_last_tuser;\n\n\t\t\t\t-- handle tvalid output signal\n\t\t\t\tif s_axis_input_window_tuser = '1' then\n\t\t\t\t\tm_axis_output_tvalid_int <= '1';\n\t\t\t\t\tm_axis_output_tdata <= current_node(BW_TRELLIS_STATES - 1);\n\t\t\t\tend if;\n\n\t\t\t\t-- last value of current window?\n\t\t\t\tif s_axis_input_last_tuser = '1' then\n\t\t\t\t\tcurrent_node <= to_unsigned(0, BW_TRELLIS_STATES);\n\t\t\t\telse\n\t\t\t\t\tcurrent_node <= current_node(BW_TRELLIS_STATES - 2 downto 0)\n\t\t\t\t\t                & s_axis_input_tdata(to_integer(current_node(BW_TRELLIS_STATES - 1 downto 0)));\n\t\t\t\tend if;\n\t\t\tend if;\n\t\tend if;\n\tend if;\n\tend process pr_traceback;\nend architecture rtl;\n"
  },
  {
    "path": "tests/pytest/test_array.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport copy\n\nimport pytest\n\nfrom cocotb.types import Array, Range\n\n\ndef test_value_only_construction():\n    a = Array(\"1234\")\n    assert a.left == 0\n    assert a.direction == \"to\"\n    assert a.right == 3\n\n\ndef test_both_construction():\n    a = Array(\"1234\", Range(-2, 1))\n    assert a.left == -2\n    assert a.direction == \"to\"\n    assert a.right == 1\n\n    Array(\"1234\", 4)\n    Array(\"1234\", range=Range(-2, 1))\n\n\ndef test_range_int_construction():\n    assert Array(\"1234\", 4)\n\n\ndef test_bad_construction():\n    with pytest.raises(TypeError):\n        Array()\n    with pytest.raises(TypeError):\n        Array(value=1)\n    with pytest.raises(TypeError):\n        Array(range=Range(0, 1))\n    with pytest.raises(ValueError):\n        Array(value=\"1234\", range=Range(0, 1))\n    with pytest.raises(TypeError):\n        Array(value=\"1234\", range=object())\n    with pytest.raises(TypeError):\n        Array(\"1234\", range(4))\n\n\ndef test_length():\n    a = Array(\"123456\")\n    assert len(a) == 6\n\n\ndef test_range():\n    r = Range(-2, 1)\n    a = Array(value=\"0123\", range=r)\n    assert a.range == r\n\n\ndef test_equality():\n    assert Array(\"1234\", Range(1, 4)) == Array(\"1234\", Range(1, 4))\n    assert Array(\"1234\", Range(1, 4)) == Array(\"1234\", Range(0, -3))\n    assert Array(\"1234\", Range(1, 4)) != Array(\"4321\", Range(1, 4))\n    assert Array(\"1234\") != Array(\"12\")\n    assert Array(\"1234\") != 8\n    assert Array([1, 2, 3, 4]) == [1, 2, 3, 4]\n\n\ndef test_repr_eval():\n    r = Array(\"1234\")\n    assert eval(repr(r)) == r\n\n\ndef test_iter():\n    val = [7, True, object(), \"example\"]\n    a = Array(val)\n    assert list(a) == val\n\n\ndef test_reversed():\n    val = [7, True, object(), \"example\"]\n    a = Array(val)\n    assert list(reversed(a)) == list(reversed(val))\n\n\ndef test_contains():\n    a = Array([7, True, object(), \"example\"])\n    assert True in a\n    assert 89 not in a\n\n\ndef test_index():\n    r = Array(i for j in range(10) for i in range(10))  # 0-9 repeated 10 times\n    assert r.index(5) == 5\n    assert r.index(5, 10, 20) == 15\n    with pytest.raises(ValueError):\n        r.index(object())\n\n\ndef test_count():\n    assert Array(\"011X1Z\").count(\"1\") == 3\n\n\ndef test_indexing():\n    a = Array(\"1234\", Range(8, \"to\", 11))\n    assert a[8] == \"1\"\n    with pytest.raises(IndexError):\n        a[0]\n    a[11] = False\n    assert a[11] is False\n\n    b = Array(\"1234\", Range(10, \"downto\", 7))\n    assert b[8] == \"3\"\n    with pytest.raises(IndexError):\n        b[-2]\n    b[8] = 9\n    assert b[8] == 9\n\n\ndef test_bad_indexing():\n    with pytest.raises(TypeError):\n        Array(\"1234\")[[]]\n    with pytest.raises(TypeError):\n        Array(\"1234\")[object()] = 9\n\n\ndef test_slicing():\n    a = Array(\"testingstuff\")\n    b = a[2:6]\n    assert b.left == 2\n    assert b.right == 6\n    assert b == Array(\"sting\")\n    a[0:3] = \"hack\"\n    assert a == Array(\"hackingstuff\")\n\n\ndef test_slicing_infered_start_stop():\n    a = Array([1, 2, 3, 4])\n    assert a[:] == a\n    a[:] = \"1234\"\n    assert a == Array(\"1234\")\n\n\ndef test_dont_specify_step():\n    with pytest.raises(IndexError):\n        Array(\"1234\")[::1]\n    with pytest.raises(IndexError):\n        Array(\"7896\")[1:2:1] = [1, 2]\n\n\ndef test_slice_direction_mismatch():\n    a = Array([1, 2, 3, 4], Range(10, \"downto\", 7))\n    with pytest.raises(IndexError):\n        a[7:9]\n    with pytest.raises(IndexError):\n        a[9:10] = [\"a\", \"b\"]\n\n\ndef test_set_slice_wrong_length():\n    a = Array(\"example\")\n    with pytest.raises(ValueError):\n        a[2:4] = \"real bad\"\n\n\ndef test_slice_correct_infered():\n    a = Array(\"1234\")\n    b = a[:0]\n    assert b.right == 0\n\n\ndef test_changing_range():\n    a = Array(\"1234\")\n    a.range = Range(3, \"downto\", 0)\n    assert a.range == Range(3, \"downto\", 0)\n    with pytest.raises(TypeError):\n        a.range = range(10)\n    with pytest.raises(ValueError):\n        a.range = Range(7, \"downto\", 0)\n\n\ndef test_copy() -> None:\n    l = Array(\"abcd\", Range(-2, \"to\", 1))\n\n    c = copy.copy(l)\n    assert l == c\n    assert l.range == c.range\n\n    d = copy.deepcopy(l)\n    assert l == d\n    assert l.range == d.range\n"
  },
  {
    "path": "tests/pytest/test_cocotb.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport sys\n\nimport pytest\n\nfrom cocotb_tools.runner import get_runner\n\npytestmark = pytest.mark.simulator_required\n\ntests_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\nsim_build = os.path.join(os.path.dirname(os.path.abspath(__file__)), \"sim_build\")\n\nmodule_name = [\n    \"test_async_coroutines\",\n    \"test_async_generators\",\n    \"test_clock\",\n    \"test_first_combine\",\n    \"test_deprecated\",\n    \"test_edge_triggers\",\n    \"test_handle\",\n    \"test_logging\",\n    \"pytest_assertion_rewriting\",\n    \"test_queues\",\n    \"test_scheduler\",\n    \"test_synchronization_primitives\",\n    \"test_testfactory\",\n    \"test_tests\",\n    \"test_timing_triggers\",\n    \"test_sim_time_utils\",\n]\n\nhdl_toplevel_lang = os.getenv(\"TOPLEVEL_LANG\", \"verilog\")\nvhdl_gpi_interfaces = os.getenv(\"VHDL_GPI_INTERFACE\", None)\n\nif hdl_toplevel_lang == \"verilog\":\n    sources = [os.path.join(tests_dir, \"designs\", \"sample_module\", \"sample_module.sv\")]\n    gpi_interfaces = [\"vpi\"]\n    sim = os.getenv(\"SIM\", \"icarus\")\nelse:\n    sources = [\n        os.path.join(\n            tests_dir, \"designs\", \"sample_module\", \"sample_module_package.vhdl\"\n        ),\n        os.path.join(tests_dir, \"designs\", \"sample_module\", \"sample_module_1.vhdl\"),\n        os.path.join(tests_dir, \"designs\", \"sample_module\", \"sample_module.vhdl\"),\n    ]\n    gpi_interfaces = [vhdl_gpi_interfaces]\n    sim = os.getenv(\"SIM\", \"nvc\")\ncompile_args = []\nsim_args = []\nif sim == \"questa\":\n    compile_args = [\"+acc\"]\n    sim_args = [\"-t\", \"ps\"]\nelif sim == \"xcelium\":\n    compile_args = [\"-v93\"]\nelif sim == \"nvc\":\n    compile_args = [\"--std=08\"]\n\nhdl_toplevel = \"sample_module\"\nsys.path.insert(0, os.path.join(tests_dir, \"test_cases\", \"test_cocotb\"))\n\n# test_timing_triggers.py requires a 1ps time precision.\ntimescale = (\"1ps\", \"1ps\")\n\n\n@pytest.mark.parametrize(\"reduced_log_fmt\", [\"1\", \"0\"])\ndef test_cocotb(reduced_log_fmt):\n    runner = get_runner(sim)\n\n    runner.build(\n        sources=sources,\n        hdl_toplevel=hdl_toplevel,\n        build_dir=sim_build,\n        build_args=compile_args,\n        timescale=timescale,\n    )\n\n    runner.test(\n        hdl_toplevel_lang=hdl_toplevel_lang,\n        hdl_toplevel=hdl_toplevel,\n        test_module=module_name,\n        gpi_interfaces=gpi_interfaces,\n        test_args=sim_args,\n        timescale=None if sim in (\"xcelium\",) else timescale,\n        extra_env={\"COCOTB_REDUCED_LOG_FMT\": reduced_log_fmt},\n    )\n\n\nif __name__ == \"__main__\":\n    test_cocotb()\n"
  },
  {
    "path": "tests/pytest/test_env.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Testing the :mod:`cocotb_tools.env` module used to handle\nenvironment variables in a consistent and unified way.\"\"\"\n\nfrom __future__ import annotations\n\nimport shlex\nfrom importlib import reload\nfrom logging import getLogger\nfrom pathlib import Path\nfrom re import escape\nfrom typing import Callable\n\nimport pytest\nfrom pytest import MonkeyPatch, raises\n\nimport cocotb\nimport cocotb._init\nimport cocotb._profiling\nimport cocotb.regression\nimport cocotb.types._resolve\nfrom cocotb.handle import SimHandleBase\nfrom cocotb_tools import _env\n\n\n@cocotb.test\nasync def dummy(dut: SimHandleBase) -> None:\n    \"\"\"Dummy cocotb test used to test some functions from :mod:`cocotb` package.\"\"\"\n\n\ndef test_env_exists_empty(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.exists` with existing environment variable.\"\"\"\n    monkeypatch.setenv(\"TEST_EXISTS\", \"\")\n    assert _env.exists(\"TEST_EXISTS\")\n\n\ndef test_env_exists_undefined(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.exists` with undefined environment variable.\"\"\"\n    monkeypatch.delenv(\"TEST_EXISTS\", raising=False)\n    assert not _env.exists(\"TEST_EXISTS\")\n\n\ndef test_env_bool_empty(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_bool` when environment variable is defined but empty.\"\"\"\n    monkeypatch.setenv(\"TEST_BOOL\", \"\")\n    assert not _env.as_bool(\"TEST_BOOL\")\n\n\ndef test_env_bool_undefined(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_bool` when environment variable is undefined.\"\"\"\n    monkeypatch.delenv(\"TEST_BOOL\", raising=False)\n    assert not _env.as_bool(\"TEST_BOOL\")\n\n\ndef test_env_bool_default(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_bool` with default value.\"\"\"\n    monkeypatch.delenv(\"TEST_BOOL\", raising=False)\n    assert _env.as_bool(\"TEST_BOOL\", True)\n    assert not _env.as_bool(\"TEST_BOOL\", False)\n\n\ndef test_env_bool_true(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_bool` with environment variable set to true.\"\"\"\n    for value in (\"1\", \"yes\", \"y\", \"ON\", \"True\", \"Enable\"):\n        monkeypatch.setenv(\"TEST_BOOL\", value)\n        assert _env.as_bool(\"TEST_BOOL\")\n\n\ndef test_env_bool_false(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_bool` with environment variable set to false.\"\"\"\n    for value in (\"0\", \"no\", \"n\", \"OFF\", \"False\", \"Disable\"):\n        monkeypatch.setenv(\"TEST_BOOL\", value)\n        assert not _env.as_bool(\"TEST_BOOL\")\n\n\ndef test_env_bool_invalid(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_bool` with environment variable set to invalid value.\"\"\"\n    for value in (\"-1\", \"2\", \"l\", \"x\", \"y3s\", \"0N\", \"Tru3\", \"3n4b13\"):\n        with raises(\n            ValueError,\n            match=escape(\n                f\"Unexpected value '{value}' for environment variable: 'TEST_BOOL'. Expecting one of \"\n                \"('1', 'yes', 'y', 'on', 'true', 'enable') or ('0', 'no', 'n', 'off', 'false', 'disable')\"\n            ),\n        ):\n            monkeypatch.setenv(\"TEST_BOOL\", value)\n            _env.as_bool(\"TEST_BOOL\")\n\n\ndef test_env_path_empty(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_path` when environment variable is defined but empty.\"\"\"\n    monkeypatch.setenv(\"TEST_PATH\", \"\")\n    assert _env.as_path(\"TEST_PATH\") == Path(\".\").resolve()\n\n\ndef test_env_path_undefined(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_path` when environment variable is undefined.\"\"\"\n    monkeypatch.delenv(\"TEST_PATH\", raising=False)\n    assert _env.as_path(\"TEST_PATH\") == Path(\".\").resolve()\n\n\ndef test_env_path_default(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_path` with default value.\"\"\"\n    monkeypatch.delenv(\"TEST_PATH\", raising=False)\n    assert _env.as_path(\"TEST_PATH\", tmp_path) == tmp_path.resolve()\n\n\ndef test_env_path_set(monkeypatch: MonkeyPatch, tmp_path: Path) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_path` with environment variable set to path.\"\"\"\n    monkeypatch.setenv(\"TEST_PATH\", str(tmp_path))\n    assert _env.as_path(\"TEST_PATH\") == tmp_path.resolve()\n    assert _env.as_path(\"TEST_PATH\", \"default\") == tmp_path.resolve()\n\n\ndef test_env_str_empty(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_str` when environment variable is defined but empty.\"\"\"\n    monkeypatch.setenv(\"TEST_STRING\", \"\")\n    assert _env.as_str(\"TEST_STRING\") == \"\"\n\n\ndef test_env_str_undefined(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_str` when environment variable is undefined.\"\"\"\n    monkeypatch.delenv(\"TEST_STRING\", raising=False)\n    assert _env.as_str(\"TEST_STRING\") == \"\"\n\n\ndef test_env_str_default(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_str` with default value.\"\"\"\n    monkeypatch.delenv(\"TEST_STRING\", raising=False)\n    assert _env.as_str(\"TEST_STRING\", \"default\") == \"default\"\n\n\ndef test_env_str_set(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_str` with environment variable set to string.\"\"\"\n    monkeypatch.setenv(\"TEST_STRING\", \"  value \")\n    assert _env.as_str(\"TEST_STRING\") == \"value\"\n\n\ndef test_env_int_empty(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_int` when environment variable is defined but empty.\"\"\"\n    monkeypatch.setenv(\"TEST_INT\", \"\")\n    assert _env.as_int(\"TEST_INT\") == 0\n\n\ndef test_env_int_undefined(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_int` when environment variable is undefined.\"\"\"\n    monkeypatch.delenv(\"TEST_INT\", raising=False)\n    assert _env.as_int(\"TEST_INT\") == 0\n\n\ndef test_env_int_default(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_int` with default value.\"\"\"\n    monkeypatch.delenv(\"TEST_INT\", raising=False)\n\n    for value in (-13, -1, 0, 1, 20):\n        assert _env.as_int(\"TEST_INT\", value) == value\n\n\ndef test_env_int_set(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_int` with environment variable set to integer.\"\"\"\n    for value in (-13, -1, 0, 1, 20):\n        monkeypatch.setenv(\"TEST_INT\", str(value))\n        assert _env.as_int(\"TEST_INT\") == value\n\n\ndef test_env_args_empty(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_args` when environment variable is defined but empty.\"\"\"\n    monkeypatch.setenv(\"TEST_ARGS\", \"\")\n    assert _env.as_args(\"TEST_ARGS\") == []\n\n\ndef test_env_args_undefined(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_args` when environment variable is undefined.\"\"\"\n    monkeypatch.delenv(\"TEST_ARGS\", raising=False)\n    assert _env.as_args(\"TEST_ARGS\") == []\n\n\ndef test_env_args_default(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_args` with default value.\"\"\"\n    expected: str = \"arg1 arg2 'arg3 arg4' arg5\"\n    monkeypatch.delenv(\"TEST_ARGS\", raising=False)\n    assert _env.as_args(\"TEST_ARGS\", expected) == shlex.split(expected)\n\n\ndef test_env_args_set(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_args` with environment variable set to arguments.\"\"\"\n    expected: str = \"arg1 arg2 'arg3 arg4' arg5\"\n    monkeypatch.setenv(\"TEST_ARGS\", expected)\n    assert _env.as_args(\"TEST_ARGS\", \"default\") == shlex.split(expected)\n\n\ndef test_env_list_empty(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_list` when environment variable is defined but empty.\"\"\"\n    monkeypatch.setenv(\"TEST_LIST\", \"\")\n    assert _env.as_list(\"TEST_LIST\") == []\n\n\ndef test_env_list_undefined(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_list` when environment variable is undefined.\"\"\"\n    monkeypatch.delenv(\"TEST_LIST\", raising=False)\n    assert _env.as_list(\"TEST_LIST\") == []\n\n\ndef test_env_list_default(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_list` with default value.\"\"\"\n    monkeypatch.delenv(\"TEST_LIST\", raising=False)\n    assert _env.as_list(\"TEST_LIST\", [\"a\", \"b\", \"c\", \"d\"]) == [\"a\", \"b\", \"c\", \"d\"]\n\n\ndef test_env_list_set(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test :func:`cocotb_tools._env.as_list` with environment variable set to arguments.\"\"\"\n    monkeypatch.setenv(\"TEST_LIST\", \" a,  b ,c,,d ,\")\n    assert _env.as_list(\"TEST_LIST\", \"default\") == [\"a\", \"b\", \"c\", \"d\"]\n\n\ndef test_env_cocotb_testcase_deprecated(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test if defining :envvar:`COCOTB_TESTCASE` environment variable will raise a deprecation warning.\"\"\"\n    monkeypatch.setattr(cocotb, \"RANDOM_SEED\", 0, raising=False)\n    monkeypatch.setenv(\"COCOTB_TEST_MODULES\", \"test_env\")\n    monkeypatch.delenv(\"COCOTB_TEST_FILTER\", raising=False)\n    monkeypatch.setenv(\"COCOTB_TESTCASE\", \"dummy\")\n\n    with pytest.deprecated_call():\n        cocotb.regression._setup_regression_manager()\n\n\ndef test_env_cocotb_test_modules_empty(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test if empty :envvar:`COCOTB_TEST_MODULES` environment variable will raise a runtime error.\"\"\"\n    monkeypatch.setattr(cocotb, \"RANDOM_SEED\", 0, raising=False)\n    monkeypatch.setenv(\"COCOTB_TEST_MODULES\", \"\")\n\n    with pytest.raises(\n        RuntimeError,\n        match=escape(\n            \"Environment variable COCOTB_TEST_MODULES, which defines the module(s) to execute, is not defined or empty.\"\n        ),\n    ):\n        cocotb.regression._setup_regression_manager()\n\n\ndef test_env_cocotb_test_modules_undefined(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test if undefined :envvar:`COCOTB_TEST_MODULES` environment variable will raise a runtime error.\"\"\"\n    monkeypatch.setattr(cocotb, \"RANDOM_SEED\", 0, raising=False)\n    monkeypatch.delenv(\"COCOTB_TEST_MODULES\", raising=False)\n\n    with pytest.raises(\n        RuntimeError,\n        match=escape(\n            \"Environment variable COCOTB_TEST_MODULES, which defines the module(s) to execute, is not defined or empty.\"\n        ),\n    ):\n        cocotb.regression._setup_regression_manager()\n\n\ndef test_env_cocotb_testcase_with_cocotb_test_filter(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test if defined :envvar:`COCOTB_TESTCASE` with :envvar:`COCOTB_TEST_FILETER` environment variable will raise a runtime error.\"\"\"\n    monkeypatch.setattr(cocotb, \"RANDOM_SEED\", 0, raising=False)\n    monkeypatch.setenv(\"COCOTB_TEST_MODULES\", \"test_env\")\n    monkeypatch.setenv(\"COCOTB_TEST_FILTER\", \"dummy\")\n    monkeypatch.setenv(\"COCOTB_TESTCASE\", \"dummy\")\n\n    with pytest.raises(\n        RuntimeError,\n        match=\"Specify only one of COCOTB_TESTCASE or COCOTB_TEST_FILTER\",\n    ):\n        cocotb.regression._setup_regression_manager()\n\n\ndef test_env_cocotb_random_seed(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test setting :envvar:`COCOTB_RANDOM_SEED` environment variable.\"\"\"\n    monkeypatch.setattr(cocotb, \"RANDOM_SEED\", 0, raising=False)\n    monkeypatch.setattr(cocotb._init, \"log\", getLogger(\"cocotb\"), raising=False)\n    monkeypatch.setenv(\"COCOTB_RANDOM_SEED\", \"100\")\n\n    cocotb._init._setup_random_seed()\n\n    assert cocotb.RANDOM_SEED == 100\n\n\ndef test_env_random_seed_deprecated(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test if defining :envvar:`RANDOM_SEED` environment variable will raise a deprecation warning.\"\"\"\n    monkeypatch.setattr(cocotb, \"RANDOM_SEED\", 0, raising=False)\n    monkeypatch.setattr(cocotb._init, \"log\", getLogger(\"cocotb\"), raising=False)\n    monkeypatch.delenv(\"COCOTB_RANDOM_SEED\", raising=False)\n    monkeypatch.setenv(\"RANDOM_SEED\", \"110\")\n\n    with pytest.deprecated_call():\n        cocotb._init._setup_random_seed()\n        assert cocotb.RANDOM_SEED == 110\n\n\ndef test_plusargs_ntb_random_seed_deprecated(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test if setting plusargs ``ntb_random_seed`` will raise a deprecation warning.\"\"\"\n    monkeypatch.setattr(cocotb, \"RANDOM_SEED\", 0, raising=False)\n    monkeypatch.setattr(cocotb._init, \"log\", getLogger(\"cocotb\"), raising=False)\n    monkeypatch.delenv(\"COCOTB_RANDOM_SEED\", raising=False)\n    monkeypatch.delenv(\"RANDOM_SEED\", raising=False)\n    monkeypatch.setattr(cocotb, \"plusargs\", {\"ntb_random_seed\": \"120\"}, raising=False)\n\n    with pytest.deprecated_call():\n        cocotb._init._setup_random_seed()\n        assert cocotb.RANDOM_SEED == 120\n\n\ndef test_plusargs_seed_deprecated(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test if setting plusargs ``seed`` will raise a deprecation warning.\"\"\"\n    monkeypatch.setattr(cocotb, \"RANDOM_SEED\", 0, raising=False)\n    monkeypatch.setattr(cocotb._init, \"log\", getLogger(\"cocotb\"), raising=False)\n    monkeypatch.delenv(\"COCOTB_RANDOM_SEED\", raising=False)\n    monkeypatch.delenv(\"RANDOM_SEED\", raising=False)\n    monkeypatch.setattr(cocotb, \"plusargs\", {\"seed\": \"130\"}, raising=False)\n\n    with pytest.deprecated_call():\n        cocotb._init._setup_random_seed()\n        assert cocotb.RANDOM_SEED == 130\n\n\ndef test_env_cocotb_enable_profiling(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test setting :envvar:`COCOTB_ENABLE_PROFILING` environment variable.\"\"\"\n    for value in (\"yes\", \"no\"):\n        monkeypatch.setenv(\"COCOTB_ENABLE_PROFILING\", value)\n        reload(cocotb._profiling)\n\n        cocotb._profiling._init()\n\n        with cocotb._profiling.profiling_context:\n            pass\n\n\ndef test_env_cocotb_resolve_x_weak(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test setting :envvar:`COCOTB_RESOLVE_X` environment variable to ``weak`` value.\"\"\"\n    monkeypatch.setenv(\"COCOTB_RESOLVE_X\", \"weak\")\n\n    resolve: Callable[[str], str] | None = cocotb.types._resolve._init()\n\n    assert resolve\n    assert resolve(\"0\") == \"0\"\n    assert resolve(\"1\") == \"1\"\n    assert resolve(\"L\") == \"0\"\n    assert resolve(\"H\") == \"1\"\n    assert resolve(\"W\") == \"X\"\n\n\ndef test_env_cocotb_resolve_x_value_error(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test setting :envvar:`COCOTB_RESOLVE_X` environment variable to deprecated ``value_error``.\"\"\"\n    monkeypatch.setenv(\"COCOTB_RESOLVE_X\", \"value_error\")\n\n    resolve: Callable[[str], str] | None = cocotb.types._resolve._init()\n\n    assert resolve\n    assert resolve(\"0\") == \"0\"\n    assert resolve(\"1\") == \"1\"\n\n\ndef test_env_cocotb_resolve_x_invalid(monkeypatch: MonkeyPatch) -> None:\n    \"\"\"Test setting :envvar:`COCOTB_RESOLVE_X` environment variable to invalid value.\"\"\"\n    monkeypatch.setenv(\"COCOTB_RESOLVE_X\", \"invalid\")\n\n    with pytest.raises(\n        ValueError,\n        match=escape(\n            \"Invalid COCOTB_RESOLVE_X value: 'invalid'. Valid values are 'error', 'weak', 'zeros', 'ones', or 'random'\"\n        ),\n    ):\n        cocotb.types._resolve._init()\n"
  },
  {
    "path": "tests/pytest/test_logging_with_envs.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Testing the :mod:`cocotb.logging` module.\"\"\"\n\nfrom __future__ import annotations\n\nimport re\nfrom logging import INFO, getLogger\nfrom random import randint\n\nimport pytest\nfrom pytest import LogCaptureFixture, MonkeyPatch\n\nimport cocotb.logging\nimport cocotb.simulator\n\n# X.XX{step,fs,ps,ns,us,ms,sec} <LEVEL> <name> (<file>.py:<line> in <function>)? <message>\nLOG: re.Pattern[str] = re.compile(\n    r\"^\\s*[0-9]+\\.[0-9]{2}[a-z]{1,4}\\s+[A-Z]+\\s+\\w+\\s+(\\S+\\.py:[0-9]+\\s+in\\s+\\w+)?\\s+\\w+.*$\"\n)\n\nBOOLEAN_ENVS: tuple[str, ...] = (\n    \"COCOTB_REDUCED_LOG_FMT\",\n    \"COCOTB_ANSI_OUTPUT\",\n    \"NO_COLOR\",\n    \"GUI\",\n)\n\nENVS: tuple[str, ...] = (\n    \"COCOTB_LOG_PREFIX\",\n    *BOOLEAN_ENVS,\n)\n\n\ndef mock_get_sim_time() -> tuple[int, int]:\n    \"\"\"Mock the :func:`cocotb.simulator.get_sim_time` function.\"\"\"\n    return 0, int(randint(0, 1000) * 1e4)\n\n\ndef _set_env(monkeypatch: MonkeyPatch, name: str, value: str | None) -> None:\n    \"\"\"Set environment variable.\"\"\"\n    for env in ENVS:\n        monkeypatch.delenv(env, raising=False)\n\n    if value is None:\n        monkeypatch.delenv(name, raising=False)\n    else:\n        monkeypatch.setenv(name, value)\n\n    monkeypatch.setattr(\n        cocotb.simulator, \"get_sim_time\", mock_get_sim_time, raising=False\n    )\n\n    cocotb.logging._init()\n    cocotb.logging._configure()\n\n\n@pytest.mark.parametrize(\"value\", (None, \"0\", \"1\"))\n@pytest.mark.parametrize(\"name\", BOOLEAN_ENVS)\ndef test_logging_boolean_envs(\n    monkeypatch: MonkeyPatch,\n    caplog: LogCaptureFixture,\n    name: str,\n    value: str | None,\n) -> None:\n    \"\"\"Test logging module with different boolean environment variables.\"\"\"\n    _set_env(monkeypatch, name, value)\n\n    with caplog.at_level(INFO):\n        caplog.clear()\n        getLogger(\"cocotb\").warning(\"warning message\")\n        assert LOG.match(caplog.text)\n\n\n@pytest.mark.parametrize(\"value\", (None, \"\", \"prefix\"))\ndef test_logging_log_prefix(\n    monkeypatch: MonkeyPatch,\n    caplog: LogCaptureFixture,\n    value: str | None,\n) -> None:\n    \"\"\"Test logging module with the :envvar:`COCOTB_LOG_PREFIX` environment variable.\"\"\"\n    _set_env(monkeypatch, \"COCOTB_LOG_PREFIX\", value)\n\n    with caplog.at_level(INFO):\n        getLogger(\"cocotb\").info(\"test message\")\n\n        if value:\n            assert caplog.text.rstrip() == f\"{value}test message\"\n        else:\n            assert LOG.match(caplog.text)\n"
  },
  {
    "path": "tests/pytest/test_logic.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport copy\n\nimport pytest\n\nfrom cocotb.types import Bit, Logic\n\n\ndef test_logic_conversions():\n    l = Logic(\"U\")\n    assert Logic(\"u\") == l\n    assert Logic(Logic(\"U\")) == l\n\n    l = Logic(\"X\")\n    assert Logic(\"x\") == l\n    assert Logic(Logic(\"x\")) == l\n\n    l = Logic(\"0\")\n    assert Logic(0) == l\n    assert Logic(False) == l\n    assert Logic(Logic(\"0\")) == l\n\n    l = Logic(\"1\")\n    assert Logic(1) == l\n    assert Logic(True) == l\n    assert Logic(Logic(\"1\")) == l\n\n    l = Logic(\"Z\")\n    assert Logic(\"z\") == l\n    assert Logic(Logic(\"Z\")) == l\n\n    l = Logic(\"W\")\n    assert Logic(\"w\") == l\n    assert Logic(Logic(\"W\")) == l\n\n    l = Logic(\"L\")\n    assert Logic(\"l\") == l\n    assert Logic(Logic(\"L\")) == l\n\n    l = Logic(\"H\")\n    assert Logic(\"h\") == l\n    assert Logic(Logic(\"H\")) == l\n\n    l = Logic(\"-\")\n    assert Logic(Logic(\"-\")) == l\n\n    with pytest.raises(ValueError):\n        Logic(\"j\")\n    with pytest.raises(ValueError):\n        Logic(2)\n    with pytest.raises(TypeError):\n        Logic(object())\n\n\ndef test_logic_equality():\n    assert Logic(0) == Logic(\"0\")\n    assert Logic(0) != Logic(\"X\")\n    assert Logic(0) != object()\n    assert Logic(0) == 0\n    assert Logic(\"X\") == \"X\"\n    assert Logic(\"X\") != \"j\"\n    assert Logic(\"1\") != 5\n\n\ndef test_logic_bool_conversions():\n    assert bool(Logic(\"1\")) is True\n    assert bool(Logic(\"H\")) is True\n    assert bool(Logic(\"0\")) is False\n    assert bool(Logic(\"L\")) is False\n    with pytest.raises(ValueError):\n        bool(Logic(\"X\"))\n    with pytest.raises(ValueError):\n        bool(Logic(\"Z\"))\n    with pytest.raises(ValueError):\n        bool(Logic(\"U\"))\n    with pytest.raises(ValueError):\n        bool(Logic(\"W\"))\n    with pytest.raises(ValueError):\n        bool(Logic(\"-\"))\n\n\ndef test_logic_str_conversions():\n    assert str(Logic(\"0\")) == \"0\"\n    assert str(Logic(\"1\")) == \"1\"\n    assert str(Logic(\"X\")) == \"X\"\n    assert str(Logic(\"Z\")) == \"Z\"\n\n\ndef test_logic_index_cast():\n    assert bin(Logic(\"0\")) == \"0b0\"\n    assert bin(Logic(\"1\")) == \"0b1\"\n    with pytest.raises(ValueError):\n        bin(Logic(\"X\"))\n\n\ndef test_logic_int_conversions():\n    assert int(Logic(\"0\")) == 0\n    assert int(Logic(\"1\")) == 1\n    assert int(Logic(\"L\")) == 0\n    assert int(Logic(\"H\")) == 1\n    with pytest.raises(ValueError):\n        int(Logic(\"X\"))\n    with pytest.raises(ValueError):\n        int(Logic(\"Z\"))\n    with pytest.raises(ValueError):\n        int(Logic(\"U\"))\n    with pytest.raises(ValueError):\n        int(Logic(\"-\"))\n    with pytest.raises(ValueError):\n        int(Logic(\"W\"))\n\n\ndef test_logic_repr():\n    assert eval(repr(Logic(\"0\"))) == Logic(\"0\")\n    assert eval(repr(Logic(\"1\"))) == Logic(\"1\")\n    assert eval(repr(Logic(\"X\"))) == Logic(\"X\")\n    assert eval(repr(Logic(\"Z\"))) == Logic(\"Z\")\n\n\ndef test_logic_and():\n    # will not be exhaustive\n    assert Logic(\"0\") & Logic(\"Z\") == Logic(0)\n    assert Logic(1) & Logic(\"1\") == Logic(1)\n    assert Logic(\"X\") & Logic(\"Z\") == Logic(\"X\")\n    with pytest.raises(TypeError):\n        Logic(\"1\") & 8\n    with pytest.raises(TypeError):\n        8 & Logic(\"1\")\n\n\ndef test_logic_or():\n    # will not be exhaustive\n    assert Logic(\"1\") | Logic(\"Z\") == Logic(\"1\")\n    assert Logic(0) | Logic(\"0\") == Logic(0)\n    assert Logic(\"X\") | Logic(\"Z\") == Logic(\"X\")\n    with pytest.raises(TypeError):\n        8 | Logic(0)\n    with pytest.raises(TypeError):\n        Logic(0) | 8\n\n\ndef test_logic_xor():\n    # will not be exhaustive\n    assert (Logic(\"1\") ^ Logic(True)) == Logic(0)\n    assert (Logic(1) ^ Logic(\"X\")) == Logic(\"X\")\n    assert (Logic(1) ^ Logic(False)) == Logic(1)\n    with pytest.raises(TypeError):\n        Logic(1) ^ ()\n    with pytest.raises(TypeError):\n        () ^ Logic(1)\n\n\ndef test_logic_invert():\n    assert ~Logic(0) == Logic(1)\n    assert ~Logic(1) == Logic(0)\n    assert ~Logic(\"X\") == Logic(\"X\")\n    assert ~Logic(\"Z\") == Logic(\"X\")\n\n\ndef test_resolve():\n    for inp, exp in zip(\"UX01ZWLH-\", \"UX01ZX01-\"):\n        assert Logic(inp).resolve(\"weak\") == Logic(exp)\n\n    for inp, exp in zip(\"UX01ZWLH-\", \"000100010\"):\n        assert Logic(inp).resolve(\"zeros\") == Logic(exp)\n\n    for inp, exp in zip(\"UX01ZWLH-\", \"110111011\"):\n        assert Logic(inp).resolve(\"ones\") == Logic(exp)\n\n    assert Logic(\"U\").resolve(\"random\") in (Logic(\"0\"), Logic(\"1\"))\n    assert Logic(\"X\").resolve(\"random\") in (Logic(\"0\"), Logic(\"1\"))\n    assert Logic(\"0\").resolve(\"random\") == Logic(\"0\")\n    assert Logic(\"1\").resolve(\"random\") == Logic(\"1\")\n    assert Logic(\"Z\").resolve(\"random\") in (Logic(\"0\"), Logic(\"1\"))\n    assert Logic(\"W\").resolve(\"random\") in (Logic(\"0\"), Logic(\"1\"))\n    assert Logic(\"L\").resolve(\"random\") == Logic(\"0\")\n    assert Logic(\"H\").resolve(\"random\") == Logic(\"1\")\n    assert Logic(\"-\").resolve(\"random\") in (Logic(\"0\"), Logic(\"1\"))\n\n\ndef test_logic_is_resolvable() -> None:\n    assert Logic(False).is_resolvable\n    assert Logic(1).is_resolvable\n    assert Logic(\"L\").is_resolvable\n    assert Logic(\"H\").is_resolvable\n    assert not Logic(\"U\").is_resolvable\n    assert not Logic(\"X\").is_resolvable\n    assert not Logic(\"Z\").is_resolvable\n    assert not Logic(\"W\").is_resolvable\n    assert not Logic(\"-\").is_resolvable\n\n\ndef test_copy() -> None:\n    l = Logic(\"X\")\n    assert l == copy.copy(l)\n    assert l == copy.deepcopy(l)\n\n\ndef test_bit_constructor() -> None:\n    Bit(0)\n    Bit(False)\n    Bit(\"0\")\n    Bit(Logic(0))\n    Bit(1)\n    Bit(True)\n    Bit(\"1\")\n    Bit(Logic(1))\n    with pytest.raises(ValueError):\n        Bit(\"X\")\n    with pytest.raises(ValueError):\n        Bit(\"L\")\n    a = Logic(\"X\")\n    with pytest.raises(ValueError):\n        Bit(a)\n\n\ndef test_bit_ops() -> None:\n    assert Bit(1) | Bit(0) == Bit(1)\n    assert Bit(1) & Bit(0) == Bit(0)\n    assert Bit(1) ^ Bit(0) == Bit(1)\n    assert ~Bit(1) == Bit(0)\n\n\ndef test_bit_with_logic_ops() -> None:\n    assert Logic(0) == Bit(0)\n    assert Bit(0) == Logic(0)\n    assert Logic(1) & Bit(1) == Logic(1)\n    assert Bit(1) & Logic(1) == Logic(1)\n    assert Logic(0) | Bit(1) == Logic(1)\n    assert Bit(0) | Logic(1) == Logic(1)\n    assert Logic(1) ^ Bit(1) == Logic(0)\n    assert Bit(1) ^ Logic(1) == Logic(0)\n"
  },
  {
    "path": "tests/pytest/test_logic_array.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport copy\n\nimport pytest\n\nfrom cocotb.types import Logic, LogicArray, Range\n\n\ndef test_logic_array_str_construction():\n    LogicArray(\"01XZ\")\n    assert LogicArray(\"1010\", Range(0, \"to\", 3)) == LogicArray(\"1010\")\n    assert LogicArray(\"1010\", 4) == LogicArray(\"1010\")\n    assert LogicArray(\"1010\", range=Range(0, \"to\", 3)) == LogicArray(\"1010\")\n\n    with pytest.raises(ValueError):\n        LogicArray(\"101010\", Range(0, \"to\", 0))\n\n    with pytest.raises(ValueError):\n        LogicArray(\"5h7_@\")\n\n    assert LogicArray(\"1010_1101\") == LogicArray(\"10101101\")\n    assert LogicArray(\"10_____10\") == LogicArray(\"1010\")\n    assert LogicArray(\"_0_\") == LogicArray(\"0\")\n    assert LogicArray(\"___\") == LogicArray(\"\")\n\n\ndef test_logic_array_iterable_construction():\n    assert LogicArray([False, 1, \"X\", Logic(\"Z\")]) == LogicArray(\"01XZ\")\n    assert LogicArray((1, 0, 1, 0), Range(0, \"to\", 3)) == LogicArray(\"1010\")\n    assert LogicArray((1, 0, 1, 0), 4) == LogicArray(\"1010\")\n    assert LogicArray((1, 0, 1, 0), range=Range(0, \"to\", 3)) == LogicArray(\"1010\")\n\n    def gen():\n        yield True\n        yield 0\n        yield \"X\"\n        yield Logic(\"Z\")\n\n    assert LogicArray(gen()) == LogicArray(\"10XZ\")\n\n    with pytest.raises(ValueError):\n        LogicArray([1, 0, 1, 0], Range(1, \"downto\", 0))\n    with pytest.raises(ValueError):\n        LogicArray([\"l\", \"o\", \"l\"])\n    with pytest.raises(TypeError):\n        LogicArray([object()])\n\n\ndef test_logic_array_int_construction():\n    with pytest.raises(TypeError):\n        LogicArray(10)  # refuse temptation to guess\n\n    assert LogicArray(10, Range(5, \"downto\", 0)) == LogicArray(\"001010\")\n    assert LogicArray(10, 6) == LogicArray(\"001010\")\n    assert LogicArray(10, range=Range(5, \"downto\", 0)) == LogicArray(\"001010\")\n\n    assert LogicArray(-2, Range(5, \"downto\", 0)) == LogicArray(\"111110\")\n    assert LogicArray(-2, 6) == LogicArray(\"111110\")\n    assert LogicArray(-2, range=Range(5, \"downto\", 0)) == LogicArray(\"111110\")\n\n    with pytest.raises(ValueError):\n        LogicArray(10, Range(1, \"to\", 3))\n    with pytest.raises(ValueError):\n        LogicArray(-10, Range(3, \"downto\", 0))\n\n\ndef test_logic_array_copy_construction():\n    l = LogicArray(\"01XZ\", Range(3, \"downto\", 0))\n    l2 = LogicArray(l)\n    assert l2 == l\n    assert l2.range == l.range\n    l3 = LogicArray(l, Range(7, \"downto\", 4))\n    assert l3 == l\n    assert l3.range == Range(7, \"downto\", 4)\n    l4 = LogicArray(l, 4)\n    assert l4 == l\n    assert l4.range == Range(3, \"downto\", 0)\n\n    with pytest.raises(ValueError):\n        LogicArray(l, Range(1, \"to\", 0))\n\n\ndef test_logic_array_bad_construction():\n    with pytest.raises(TypeError):\n        LogicArray(object())\n    with pytest.raises(TypeError):\n        LogicArray(\"1010\", {})\n    with pytest.raises(TypeError):\n        LogicArray(range={})\n    with pytest.raises(TypeError):\n        LogicArray()\n\n\ndef test_logic_array_unsigned_conversion():\n    with pytest.raises(TypeError):\n        LogicArray.from_unsigned(10)  # refuse temptation to guess\n    assert LogicArray.from_unsigned(10, Range(5, \"downto\", 0)) == LogicArray(\"001010\")\n    assert LogicArray.from_unsigned(10, 6) == LogicArray(\"001010\")\n    assert LogicArray.from_unsigned(10, range=Range(5, \"downto\", 0)) == LogicArray(\n        \"001010\"\n    )\n\n    with pytest.raises(ValueError):\n        LogicArray.from_unsigned(10, Range(1, \"to\", 3))\n    with pytest.raises(ValueError):\n        LogicArray.from_unsigned(10, 3)\n\n    with pytest.raises(ValueError):\n        LogicArray.from_unsigned(-10, Range(7, \"downto\", 0))\n\n    with pytest.raises(TypeError):\n        LogicArray.from_unsigned(object(), Range(3, \"downto\", 0))\n    with pytest.raises(TypeError):\n        LogicArray.from_unsigned(10, \"lol\")\n\n\ndef test_logic_array_signed_conversion():\n    with pytest.raises(TypeError):\n        LogicArray.from_signed(-2)  # refuse temptation to guess\n    assert LogicArray.from_signed(-2, Range(5, \"downto\", 0)) == LogicArray(\"111110\")\n    assert LogicArray.from_signed(-2, 6) == LogicArray(\"111110\")\n    assert LogicArray.from_signed(-2, range=Range(5, \"downto\", 0)) == LogicArray(\n        \"111110\"\n    )\n\n    with pytest.raises(ValueError):\n        LogicArray.from_signed(-45, Range(1, \"to\", 3))\n    with pytest.raises(ValueError):\n        LogicArray.from_signed(-45, 3)\n\n    with pytest.raises(TypeError):\n        LogicArray.from_signed(object(), Range(3, \"downto\", 0))\n    with pytest.raises(TypeError):\n        LogicArray.from_signed(10, \"lol\")\n\n    with pytest.raises(ValueError):\n        LogicArray.from_signed(-9, 4)\n    assert LogicArray.from_signed(-8, 4) == LogicArray(\"1000\")\n    assert LogicArray.from_signed(7, 4) == LogicArray(\"0111\")\n    with pytest.raises(ValueError):\n        LogicArray.from_signed(8, 4)\n\n\ndef test_logic_array_bytes_conversion():\n    assert LogicArray.from_bytes(b\"12\", byteorder=\"big\") == LogicArray(\n        \"0011000100110010\"\n    )\n\n    with pytest.raises(ValueError):\n        LogicArray.from_bytes(b\"123\", Range(6, \"downto\", 0), byteorder=\"big\")\n    with pytest.raises(ValueError):\n        LogicArray.from_bytes(b\"123\", 10, byteorder=\"big\")\n\n    # b\"1\" would fit in a 7 bit LogicArray, but we do not guess if top bits are significant or not\n    with pytest.raises(ValueError):\n        LogicArray.from_bytes(b\"1\", Range(6, \"downto\", 0), byteorder=\"big\")\n\n    assert LogicArray(\"00101010\").to_bytes(byteorder=\"big\") == b\"\\x2a\"\n\n\ndef test_logic_array_properties():\n    assert LogicArray(\"01\").is_resolvable\n    assert not LogicArray(\"1X1\").is_resolvable\n\n\ndef test_logic_array_properties_deprecated():\n    with pytest.warns(DeprecationWarning):\n        assert LogicArray(\"1010\").integer == 10\n\n    l = LogicArray(\"1100\")\n    with pytest.warns(DeprecationWarning):\n        l.integer = 1\n    assert l.to_unsigned() == 1\n    with pytest.warns(DeprecationWarning), pytest.raises(ValueError):\n        l.integer = 100\n    with pytest.warns(DeprecationWarning), pytest.raises(ValueError):\n        l.integer = -1\n\n    with pytest.warns(DeprecationWarning):\n        assert LogicArray(\"1010\").signed_integer == -6\n\n    l = LogicArray(\"1100\")\n    with pytest.warns(DeprecationWarning):\n        l.signed_integer = 3\n    assert l.to_signed() == 3\n    with pytest.warns(DeprecationWarning):\n        l.signed_integer = -1\n    assert l.to_signed() == -1\n    with pytest.warns(DeprecationWarning), pytest.raises(ValueError):\n        l.signed_integer = 100\n    with pytest.warns(DeprecationWarning), pytest.raises(ValueError):\n        l.signed_integer = -10\n\n    with pytest.warns(DeprecationWarning):\n        assert LogicArray(\"1010\").binstr == \"1010\"\n\n    l = LogicArray(\"1010\")\n    with pytest.warns(DeprecationWarning):\n        l.binstr = \"0101\"\n    assert str(l) == \"0101\"\n\n    with pytest.warns(DeprecationWarning):\n        assert LogicArray(\"01000001\" + \"00101111\").buff == b\"\\x41\\x2f\"\n\n    l = LogicArray(\"0\" * 16)\n    with pytest.warns(DeprecationWarning):\n        l.buff = b\"\\x41\\x2f\"\n    assert l.to_bytes(byteorder=\"big\") == b\"\\x41\\x2f\"\n    with pytest.warns(DeprecationWarning), pytest.raises(ValueError):\n        l.buff = b\"\\x41\\x2f0123\"\n    with pytest.warns(DeprecationWarning), pytest.raises(ValueError):\n        l.buff = b\"\"\n\n\ndef test_logic_array_setattr():\n    l = LogicArray(\"0000\")\n    l[1] = \"X\"\n    assert l == LogicArray(\"00X0\")\n    with pytest.raises(TypeError):\n        l[object()] = \"X\"\n\n\ndef test_logic_array_repr():\n    l = LogicArray(\"1XX110\")\n    assert eval(repr(l)) == l\n\n\ndef test_logic_array_and():\n    l = LogicArray(\"0011XZ\")\n    p = LogicArray(\"011010\")\n    assert (l & p) == LogicArray(\"0010X0\")\n    with pytest.raises(TypeError):\n        l & object()\n    with pytest.raises(TypeError):\n        object() & l\n    with pytest.raises(ValueError):\n        LogicArray(\"\") & LogicArray(\"01\")\n\n\ndef test_logic_array_or():\n    l = LogicArray(\"0011XZ\")\n    p = LogicArray(\"011010\", Range(-9, \"downto\", -14))\n    assert (l | p) == LogicArray(\"01111X\")\n    with pytest.raises(TypeError):\n        l | object()\n    with pytest.raises(TypeError):\n        object() | l\n    with pytest.raises(ValueError):\n        LogicArray(\"\") | LogicArray(\"01\")\n\n\ndef test_logic_array_xor():\n    l = LogicArray(\"0011XZ\")\n    p = LogicArray(\"011010\")\n    assert (l ^ p) == LogicArray(\"0101XX\")\n    with pytest.raises(TypeError):\n        l ^ object()\n    with pytest.raises(TypeError):\n        object() ^ l\n    with pytest.raises(ValueError):\n        LogicArray(\"\") ^ LogicArray(\"01\")\n\n\ndef test_logic_array_invert():\n    assert ~LogicArray(\"01XZ\") == LogicArray(\"10XX\")\n\n\ndef test_logic_array_literal_casts():\n    assert str(LogicArray(\"UX01ZWLH-\")) == \"UX01ZWLH-\"\n    assert int(LogicArray(\"0101010\")) == 0b0101010\n\n\ndef test_logic_array_index_casts():\n    assert bin(LogicArray(\"000101\")) == \"0b101\"\n    assert hex(LogicArray(\"01111010\")) == \"0x7a\"\n    with pytest.raises(ValueError):\n        bin(LogicArray(\"X010\"))\n\n\ndef test_equality():\n    # fmt: off\n    # cross product of all impls\n    assert LogicArray(\"0101\", Range(0, 'to', 3)) == LogicArray(\"0101\", Range(0, 'to', 3))\n    assert LogicArray(\"0101\", Range(0, 'to', 3)) == LogicArray(0b0101, Range(0, 'to', 3))\n    assert LogicArray(\"0101\", Range(0, 'to', 3)) == LogicArray([0, 1, 0, 1], Range(0, 'to', 3))\n    assert LogicArray(0b0101, Range(0, 'to', 3)) == LogicArray(\"0101\", Range(0, 'to', 3))\n    assert LogicArray(0b0101, Range(0, 'to', 3)) == LogicArray(0b0101, Range(0, 'to', 3))\n    assert LogicArray(0b0101, Range(0, 'to', 3)) == LogicArray([0, 1, 0, 1], Range(0, 'to', 3))\n    assert LogicArray([0, 1, 0, 1], Range(0, 'to', 3)) == LogicArray(\"0101\", Range(0, 'to', 3))\n    assert LogicArray([0, 1, 0, 1], Range(0, 'to', 3)) == LogicArray(0b0101, Range(0, 'to', 3))\n    assert LogicArray([0, 1, 0, 1], Range(0, 'to', 3)) == LogicArray([0, 1, 0, 1], Range(0, 'to', 3))\n    assert LogicArray(\"0101\", Range(0, 'to', 3)) == LogicArray(\"0101\", Range(7, 'downto', 4)) # equality works regardless of range\n    assert LogicArray(\"0101\", Range(0, 'to', 3)) != LogicArray(\"1010\", Range(0, 'to', 3))  # wrong value same lengths\n    assert LogicArray(\"0101\", Range(0, 'to', 3)) != LogicArray(\"010101\")  # different lengths\n    # fmt: on\n    assert LogicArray(\"0101\") == \"0101\"\n    assert LogicArray(\"0101\") == [0, 1, 0, 1]\n    assert LogicArray(\"0101\") == 0b0101\n    assert LogicArray(\"XXXX\") != 1\n    assert LogicArray(\"0101\") != object()\n    assert LogicArray(\"0101\") != \"lol\"\n    assert LogicArray(\"0101\") != 123\n    assert LogicArray(\"0101\") != [7, \"f\", dict]\n    assert LogicArray(\"1111\") == -1\n    assert LogicArray(\"1111\") == 15\n    assert LogicArray(\"0111\") != -6\n\n\ndef test_repr_eval():\n    r = LogicArray(\"X01Z\")\n    assert eval(repr(r)) == r\n\n\ndef test_iter():\n    val = [Logic(0), Logic(1), Logic(\"X\"), Logic(\"Z\")]\n    assert all(isinstance(v, Logic) for v in val)\n    a = LogicArray(val)\n    assert list(a) == val\n\n\ndef test_reversed():\n    val = [Logic(0), Logic(1), Logic(\"X\"), Logic(\"Z\")]\n    a = LogicArray(val)\n    assert list(reversed(a)) == list(reversed(val))\n\n\ndef test_contains():\n    a = LogicArray(\"01XZ\")\n    assert Logic(\"X\") in a\n    assert Logic(\"U\") not in a\n\n\ndef test_index():\n    r = LogicArray(\"0001101\", Range(7, \"downto\", 1))\n    assert r.index(Logic(\"1\")) == 4\n    assert r.index(Logic(\"1\"), 2, 0) == 1\n    with pytest.raises(ValueError):\n        r.index(object())\n\n\ndef test_count():\n    assert LogicArray(\"011X1Z\").count(Logic(\"1\")) == 3\n\n\ndef test_indexing():\n    a = LogicArray(\"0101\", Range(8, \"to\", 11))\n    assert a[8] == \"0\"\n    with pytest.raises(IndexError):\n        a[0]\n    a[11] = \"X\"\n    assert a[11] == \"X\"\n\n    b = LogicArray(\"Z01X\", Range(10, \"downto\", 7))\n    assert b[8] == 1\n    with pytest.raises(IndexError):\n        b[-2]\n    b[8] = 0\n    assert b[8] == 0\n\n\ndef test_bad_indexing():\n    with pytest.raises(TypeError):\n        LogicArray(\"01XZ\")[[]]\n    with pytest.raises(TypeError):\n        LogicArray(\"1010\")[object()] = 9\n\n\ndef test_slicing():\n    a = LogicArray(\"0110XXUU\")\n    b = a[5:1]\n    assert b.left == 5\n    assert b.right == 1\n    assert b == LogicArray(\"10XXU\")\n    a[3:0] = \"ZZZZ\"\n    assert a == LogicArray(\"0110ZZZZ\")\n    a[7:4] = 0b1010\n    assert a == LogicArray(\"1010ZZZZ\")\n\n\ndef test_slicing_infered_start_stop():\n    a = LogicArray(\"XXXX\")\n    assert a[:] == a\n    a[:] = \"1010\"\n    assert a == 0b1010\n\n\ndef test_dont_specify_step():\n    with pytest.raises(IndexError):\n        LogicArray(\"1010\")[::1]\n    with pytest.raises(IndexError):\n        LogicArray(\"1010\")[1:2:1] = [1, 2]\n\n\ndef test_slice_direction_mismatch():\n    a = LogicArray(\"1010\", Range(10, \"downto\", 7))\n    with pytest.raises(IndexError):\n        a[7:9]\n    with pytest.raises(IndexError):\n        a[9:10] = \"01\"\n\n\ndef test_set_slice_wrong_length():\n    a = LogicArray(\"XXXXXX\")\n    with pytest.raises(ValueError):\n        a[4:2] = \"0000000000000\"\n\n\ndef test_slice_correct_infered():\n    a = LogicArray(\"1111\")\n    b = a[:3]\n    assert b.right == 3\n\n\ndef test_changing_range():\n    a = LogicArray(\"X01Z\")\n    a.range = Range(3, \"downto\", 0)\n    assert a.range == Range(3, \"downto\", 0)\n    with pytest.raises(TypeError):\n        a.range = range(10)\n    with pytest.raises(ValueError):\n        a.range = Range(7, \"downto\", 0)\n\n\ndef test_null_vector():\n    null_range = Range(-1, \"downto\", 0)\n    assert len(null_range) == 0\n\n    # test construction doesn't fail\n    LogicArray(\"\")\n    LogicArray(\"\", null_range)\n    LogicArray([])\n    LogicArray([], null_range)\n    with pytest.raises(ValueError):\n        LogicArray(0, null_range)\n    with pytest.raises(ValueError):\n        LogicArray.from_unsigned(0, null_range)\n    with pytest.raises(ValueError):\n        LogicArray.from_signed(0, null_range)\n\n    null_vector = LogicArray(\"\")\n\n    # test attributes\n    assert len(null_vector) == 0\n    assert list(null_vector) == []\n    assert str(null_vector) == \"\"\n    with pytest.raises(ValueError):\n        int(null_vector)\n    with pytest.raises(ValueError):\n        null_vector.to_signed()\n    with pytest.raises(ValueError):\n        null_vector.to_unsigned()\n\n    # test comparison\n    assert null_vector == LogicArray(\"\")\n    assert null_vector == LogicArray(\"\", null_range)\n    assert null_vector == LogicArray([])\n    assert null_vector == LogicArray([], null_range)\n    assert null_vector != 0\n    assert null_vector != 1\n    assert null_vector != -1\n    assert null_vector == \"\"\n    assert null_vector == []\n\n\ndef test_bool_cast():\n    assert not LogicArray(\"0000\")\n    assert LogicArray(\"0100\")\n    with pytest.raises(ValueError):\n        bool(LogicArray(\"XZ01\"))\n\n\ndef test_resolve():\n    assert LogicArray(\"UX01ZWLH-\").resolve(\"weak\") == LogicArray(\"UX01ZX01-\")\n    assert LogicArray(\"UX01ZWLH-\").resolve(\"zeros\") == LogicArray(\"000100010\")\n    assert LogicArray(\"UX01ZWLH-\").resolve(\"ones\") == LogicArray(\"110111011\")\n    assert LogicArray(\"01LH\").resolve(\"random\") == LogicArray(\"0101\")\n    array = LogicArray(\"UXZW-\").resolve(\"random\")\n    assert all(elem in (Logic(\"0\"), Logic(\"1\")) for elem in array)\n\n\ndef test_copy() -> None:\n    l = LogicArray(\"X01Z\", Range(-2, \"to\", 1))\n\n    with pytest.raises(NotImplementedError):\n        copy.copy(l)\n\n    d = copy.deepcopy(l)\n    assert l == d\n    assert l.range == d.range\n\n\ndef test_format():\n    l = LogicArray(\"01XZ\")\n    assert f\"{l}\" == \"01XZ\"\n    assert f\"{l!s}\" == \"01XZ\"\n    assert f\"{l!r}\" == \"LogicArray('01XZ', Range(3, 'downto', 0))\"\n    with pytest.raises(ValueError):\n        f\"{l:d}\"\n    with pytest.raises(ValueError):\n        f\"{l:b}\"\n    with pytest.raises(ValueError):\n        f\"{l:x}\"\n    with pytest.raises(ValueError):\n        f\"{l:X}\"\n    with pytest.raises(ValueError):\n        f\"{l:o}\"\n\n    l = LogicArray(\"1010\")\n    assert f\"{l:d}\" == \"10\"\n    assert f\"{l:b}\" == \"1010\"\n    assert f\"{l:x}\" == \"a\"\n    assert f\"{l:X}\" == \"A\"\n    assert f\"{l:o}\" == \"12\"\n\n    with pytest.raises(ValueError):\n        f\"{l:Q}\"\n\n    l = LogicArray(\"00001101001\")\n    assert f\"{l:#_b}\" == \"0b000_0110_1001\"\n    assert f\"{l:#x}\" == \"0x069\"\n    assert f\"{l:#_X}\" == \"0X069\"\n    assert f\"{l:#_o}\" == \"0o0_0151\"\n    assert f\"{l:#,d}\" == \"0d0,105\"\n\n\ndef test_from_signed_wrap():\n    assert LogicArray.from_signed(-1, 4, on_overflow=\"wrap\") == LogicArray(\"1111\")\n    assert LogicArray.from_signed(-8, 4, on_overflow=\"wrap\") == LogicArray(\"1000\")\n    assert LogicArray.from_signed(-9, 4, on_overflow=\"wrap\") == LogicArray(\"0111\")\n    assert LogicArray.from_signed(7, 4, on_overflow=\"wrap\") == LogicArray(\"0111\")\n    assert LogicArray.from_signed(8, 4, on_overflow=\"wrap\") == LogicArray(\"1000\")\n    assert LogicArray.from_signed(15, 4, on_overflow=\"wrap\") == LogicArray(\"1111\")\n    assert LogicArray.from_signed(16, 4, on_overflow=\"wrap\") == LogicArray(\"0000\")\n    with pytest.raises(ValueError):\n        LogicArray.from_signed(-45, 4, on_overflow=\"6789\")\n\n\ndef test_from_unsigned_wrap():\n    with pytest.raises(ValueError):\n        LogicArray.from_unsigned(-1, 4)\n    with pytest.raises(ValueError):\n        LogicArray.from_unsigned(-9, 4)\n    assert LogicArray.from_unsigned(15, 4, on_overflow=\"wrap\") == LogicArray(\"1111\")\n    assert LogicArray.from_unsigned(16, 4, on_overflow=\"wrap\") == LogicArray(\"0000\")\n    assert LogicArray.from_unsigned(20, 4, on_overflow=\"wrap\") == LogicArray(\"0100\")\n    with pytest.raises(ValueError):\n        LogicArray.from_unsigned(10, 4, on_overflow=\"6789\")\n"
  },
  {
    "path": "tests/pytest/test_logs.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport sys\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\n\nimport pytest\nfrom test_cocotb import (\n    compile_args,\n    gpi_interfaces,\n    hdl_toplevel,\n    hdl_toplevel_lang,\n    sim_args,\n    sim_build,\n    sources,\n    tests_dir,\n)\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import ClockCycles\nfrom cocotb_tools.runner import get_runner\n\nsys.path.insert(0, str(Path(tests_dir) / \"pytest\"))\ntest_module = Path(__file__).stem\nsim = os.getenv(\n    \"SIM\",\n    \"icarus\" if os.getenv(\"TOPLEVEL_LANG\", \"verilog\") == \"verilog\" else \"nvc\",\n)\n\n\n@cocotb.test()\nasync def clock_design(dut):\n    clock = Clock(dut.clk, 10, unit=\"us\")\n    cocotb.start_soon(clock.start())\n    await ClockCycles(dut.clk, 10)\n\n\ndef run_simulation(sim, log_dir):\n    runner = get_runner(sim)\n    runner.build(\n        always=True,\n        clean=True,\n        sources=sources,\n        hdl_toplevel=hdl_toplevel,\n        build_dir=sim_build,\n        build_args=compile_args,\n        log_file=log_dir / \"build.log\",\n    )\n\n    runner.test(\n        hdl_toplevel_lang=hdl_toplevel_lang,\n        hdl_toplevel=hdl_toplevel,\n        gpi_interfaces=gpi_interfaces,\n        test_module=test_module,\n        test_args=sim_args,\n        build_dir=sim_build,\n        log_file=log_dir / \"test.log\",\n    )\n\n\n@pytest.mark.simulator_required\ndef test_wave_dump():\n    with TemporaryDirectory() as temp_dir:\n        log_dir = Path(temp_dir)\n        run_simulation(sim=sim, log_dir=log_dir)\n        assert (log_dir / \"build.log\").exists()\n        assert (log_dir / \"test.log\").exists()\n"
  },
  {
    "path": "tests/pytest/test_parallel_cocotb.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport sys\n\nimport pytest\nfrom test_cocotb import (\n    compile_args,\n    gpi_interfaces,\n    hdl_toplevel,\n    hdl_toplevel_lang,\n    module_name,\n    sim,\n    sim_args,\n    sim_build,\n    sources,\n    tests_dir,\n)\n\nfrom cocotb_tools.runner import get_runner\n\npytestmark = pytest.mark.simulator_required\nsys.path.insert(0, os.path.join(tests_dir, \"pytest\"))\n\n# test_timing_triggers.py requires a 1ps time precision.\ntimescale = (\"1ps\", \"1ps\")\n\n\n@pytest.mark.compile\ndef test_cocotb_parallel_compile():\n    runner = get_runner(sim)\n\n    runner.build(\n        always=True,\n        sources=sources,\n        hdl_toplevel=hdl_toplevel,\n        build_dir=sim_build,\n        build_args=compile_args,\n        timescale=timescale,\n    )\n\n\n@pytest.mark.parametrize(\"seed\", list(range(4)))\ndef test_cocotb_parallel(seed):\n    runner = get_runner(sim)\n\n    runner.build_args = compile_args\n    runner.sources = sources\n    runner.verilog_sources = []\n    runner.vhdl_sources = []\n\n    runner.test(\n        seed=seed,\n        hdl_toplevel_lang=hdl_toplevel_lang,\n        hdl_toplevel=hdl_toplevel,\n        gpi_interfaces=gpi_interfaces,\n        test_module=module_name,\n        test_args=sim_args,\n        build_dir=sim_build,\n        timescale=None if sim in (\"xcelium\",) else timescale,\n    )\n"
  },
  {
    "path": "tests/pytest/test_parameterize.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom enum import Enum\n\nimport pytest\n\nimport cocotb\nfrom cocotb._decorators import _repr, _reprs\n\n\nclass MyEnum(Enum):\n    ENUM_VALUE = 1\n\n\nclass A: ...\n\n\ndef b(): ...\n\n\ndef test_parametrize_repr():\n    assert _repr(1) == \"1\"\n    assert _repr(False) == \"False\"\n    assert _repr(0.14) == \"0.14\"\n    assert _repr(None) == \"None\"\n    assert _repr(\"wow\") == \"wow\"\n    assert _repr(\"has space\") is None\n    assert _repr(\"😊\") is None\n    assert _repr(\"wowthisisareallylongnamethatidontwantonmyterminal\") is None\n    assert _repr(A) == \"A\"\n    assert _repr(b) == \"b\"\n    assert _repr(MyEnum.ENUM_VALUE) == \"ENUM_VALUE\"\n    assert _repr(object()) is None\n\n\ndef test_parametrize_reprs():\n    assert _reprs([1, 0.5, False]) == [\"1\", \"0.5\", \"False\"]\n    assert _reprs([9, 9, object()]) == [\"0\", \"1\", \"2\"]\n\n\ndef test_parametrize_bad_args():\n    with pytest.raises(ValueError):\n        cocotb.parametrize((\"not valid\", [1, 2, 3], \"extra arg whoops\"))\n    with pytest.raises(ValueError):\n        cocotb.parametrize((\"not valid\", [1, 2, 3]))\n    with pytest.raises(ValueError):\n        cocotb.parametrize(((\"not valid\", \"valid\"), [(1, 2), (3, 4)]))\n    with pytest.raises(ValueError):\n        cocotb.parametrize(((\"a\", \"b\"), [(1, 2, \"too\", \"many\", \"args\"), (3, 4)]))\n"
  },
  {
    "path": "tests/pytest/test_plusargs.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport sys\nfrom pathlib import Path\n\nimport pytest\n\nfrom cocotb_tools.runner import get_runner\n\npytestmark = pytest.mark.simulator_required\n\nsrc_path = Path(__file__).resolve().parent.parent / \"designs\" / \"plusargs_module\"\n\ntest_module_path = (\n    Path(__file__).resolve().parent.parent / \"test_cases\" / \"test_plusargs\"\n)\n\nsys.path.insert(0, str(test_module_path))\n\n\ndef test_toplevel_library():\n    hdl_toplevel_lang = os.getenv(\"TOPLEVEL_LANG\", \"verilog\")\n    vhdl_gpi_interfaces = os.getenv(\"VHDL_GPI_INTERFACE\", None)\n    sim = os.getenv(\"SIM\", \"icarus\" if hdl_toplevel_lang == \"verilog\" else \"nvc\")\n\n    runner = get_runner(sim)\n\n    build_test_args = []\n    if hdl_toplevel_lang == \"vhdl\" and sim == \"xcelium\":\n        build_test_args = [\"-v93\"]\n    if sim == \"verilator\":\n        build_test_args = [\"--timing\"]\n\n    if hdl_toplevel_lang == \"verilog\":\n        sources = [src_path / \"tb_top.v\"]\n        gpi_interfaces = [\"vpi\"]\n    else:\n        sources = [src_path / \"tb_top.vhd\"]\n        gpi_interfaces = [vhdl_gpi_interfaces]\n\n    runner.build(\n        sources=sources,\n        hdl_toplevel=\"tb_top\",\n        build_dir=str(test_module_path / \"sim_build\" / \"pytest\"),\n        build_args=build_test_args,\n    )\n\n    runner.test(\n        hdl_toplevel=\"tb_top\",\n        test_module=\"plusargs\",\n        test_args=build_test_args,\n        gpi_interfaces=gpi_interfaces,\n        plusargs=[\"+foo=bar\", \"+test1\", \"+test2\", \"+options=fubar\", \"+lol=wow=4\"],\n    )\n"
  },
  {
    "path": "tests/pytest/test_range.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport copy\n\nimport pytest\n\nfrom cocotb.types import Range\n\n\ndef test_to_range():\n    r = Range(1, \"to\", 8)\n    assert r.left == 1\n    assert r.direction == \"to\"\n    assert r.right == 8\n    assert len(r) == 8\n    assert list(r) == [1, 2, 3, 4, 5, 6, 7, 8]\n    assert list(reversed(r)) == [8, 7, 6, 5, 4, 3, 2, 1]\n    assert r[0] == 1\n    assert r[7] == 8\n    with pytest.raises(IndexError):\n        r[8]\n    assert r[3:7] == Range(4, \"to\", 7)\n    assert 8 in r\n    assert 10 not in r\n    assert r.index(7) == 6\n    with pytest.raises(ValueError):\n        r.index(9)\n    assert r.count(4) == 1\n    assert r.count(10) == 0\n\n\ndef test_downto_range():\n    r = Range(4, \"downto\", -3)\n    assert r.left == 4\n    assert r.direction == \"downto\"\n    assert r.right == -3\n    assert len(r) == 8\n    assert list(r) == [4, 3, 2, 1, 0, -1, -2, -3]\n    assert list(reversed(r)) == [-3, -2, -1, 0, 1, 2, 3, 4]\n    assert r[0] == 4\n    assert r[7] == -3\n    with pytest.raises(IndexError):\n        r[8]\n    assert r[3:7] == Range(1, \"downto\", -2)\n    assert 0 in r\n    assert 10 not in r\n    assert r.index(2) == 2\n    with pytest.raises(ValueError):\n        r.index(9)\n    assert r.count(4) == 1\n    assert r.count(10) == 0\n\n\ndef test_range_index_from_class():\n    r = Range(9, \"downto\", 4)\n    assert Range.index(r, 8) == 1\n    with pytest.raises(ValueError):\n        Range.index(r, 0)\n\n\ndef test_null_range():\n    r = Range(1, \"downto\", 4)\n    assert r.left == 1\n    assert r.direction == \"downto\"\n    assert r.right == 4\n    assert len(r) == 0\n    assert list(r) == []\n    assert list(reversed(r)) == []\n    with pytest.raises(IndexError):\n        r[0]\n    assert 2 not in r\n    with pytest.raises(ValueError):\n        r.index(4)\n    assert r.count(4) == 0\n\n\ndef test_bad_arguments():\n    with pytest.raises(TypeError):\n        Range(1, \"to\")  # nowhere ...\n    with pytest.raises(TypeError):\n        Range(\"1\", \"to\", 5)\n    with pytest.raises(ValueError):\n        Range(1, \"BAD DIRECTION\", 3)\n\n\ndef test_equality():\n    assert Range(7, \"downto\", -7) == Range(7, \"downto\", -7)\n    assert Range(7, \"downto\", -7) != Range(0, \"to\", 8)\n    assert Range(1, \"to\", 0) == Range(8, \"to\", -8)  # null ranges are all equal?\n    assert Range(1, \"to\", 4) != 789\n\n\ndef test_other_constructors():\n    assert Range(1, 8) == Range(1, \"to\", 8)\n    assert Range(3, -4) == Range(3, \"downto\", -4)\n    assert Range(left=1, right=8) == Range(1, \"to\", 8)\n    assert Range(left=3, right=-4) == Range(3, \"downto\", -4)\n\n\ndef test_use_in_set():\n    assert len({Range(1, \"to\", 8), Range(1, \"to\", 8)}) == 1\n    assert len({Range(1, \"to\", 8), Range(8, \"downto\", 1)}) == 2\n\n\ndef test_conversions():\n    t = range(10, 1, -1)\n    r = Range.from_range(t)\n    assert r.left == 10\n    assert r.right == 2\n    assert r.direction == \"downto\"\n    assert r.to_range() == t\n\n\ndef test_repr():\n    r = Range(5, \"to\", 9)\n    assert eval(repr(r)) == r\n\n\ndef test_uppercase_in_direction():\n    r = Range(1, \"TO\", 8)\n    assert r.direction == \"to\"\n\n\ndef test_bad_direction():\n    with pytest.raises(ValueError):\n        Range(1, \"nope\", 8)\n\n\ndef test_bad_bound():\n    with pytest.raises(TypeError):\n        Range(object(), \"to\", 8)\n\n\ndef test_bad_step():\n    with pytest.raises(ValueError):\n        Range.from_range(range(10, 5, -2))\n\n\ndef test_bad_getitem():\n    with pytest.raises(TypeError):\n        Range(10, \"downto\", 4)[\"8\"]\n\n\ndef test_copy() -> None:\n    l = Range(-2, \"to\", 1)\n    assert l == copy.copy(l)\n    assert l == copy.deepcopy(l)\n\n\ndef test_index() -> None:\n    r = Range(1, \"to\", 5)\n    # value no longer in range\n    with pytest.raises(ValueError):\n        r.index(1, 2, 5)\n    with pytest.raises(ValueError):\n        r.index(1, 2)\n    with pytest.raises(ValueError):\n        r.index(5, 0, 4)\n    # value not in range at all\n    with pytest.raises(ValueError):\n        r.index(10, 1, 5)\n    with pytest.raises(ValueError):\n        r.index(10, 1)\n    with pytest.raises(ValueError):\n        r.index(0, 1, 5)\n    with pytest.raises(ValueError):\n        r.index(0, 1)\n    # start is past stop, will never find\n    with pytest.raises(ValueError):\n        r.index(3, 10, 5)\n    with pytest.raises(ValueError):\n        r.index(3, 10)\n    # start is before start of range, will always find\n    assert r.index(3, 0, 10) == 2\n    # stop is past end of range, will always find\n    assert r.index(3, 0, 10) == 2\n    # stop is before start of range, will never find\n    with pytest.raises(ValueError):\n        r.index(3, 0, -10)\n"
  },
  {
    "path": "tests/pytest/test_runner.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport sys\n\nimport find_libpython\nimport pytest\n\nimport cocotb\nfrom cocotb.triggers import Timer\nfrom cocotb_tools.runner import VHDL, _as_tcl_value, get_runner\n\npytestmark = pytest.mark.simulator_required\n\ntests_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\nsim_build = os.path.join(os.path.dirname(os.path.abspath(__file__)), \"sim_build\")\nsys.path.insert(0, os.path.join(tests_dir, \"pytest\"))\n\nsim = os.getenv(\n    \"SIM\",\n    \"icarus\" if os.getenv(\"TOPLEVEL_LANG\", \"verilog\") == \"verilog\" else \"nvc\",\n)\n\npre_cmd_sims = {\n    \"questa\",\n}\n\n\ndef test_empty_string():\n    assert _as_tcl_value(\"\") == \"\"\n\n\ndef test_special_char():\n    assert _as_tcl_value(\"Test \\n end\\ttest\\r\") == \"Test\\\\ \\\\n\\\\ end\\\\\\ttest\\\\\\r\"\n\n\nstring_define_value = \"path/to/some/(random quote)/file.wow'\"\n\n\n@cocotb.test()\nasync def cocotb_runner_test(dut):\n    await Timer(1, \"ns\")\n\n    WIDTH_IN = int(os.environ.get(\"WIDTH_IN\", \"8\"))\n    WIDTH_OUT = int(os.environ.get(\"WIDTH_OUT\", \"8\"))\n\n    assert len(dut.data_in) == WIDTH_IN\n    assert len(dut.data_out) == WIDTH_OUT\n\n\n@pytest.mark.parametrize(\n    \"parameters\", [{\"WIDTH_IN\": \"8\", \"WIDTH_OUT\": \"16\"}, {\"WIDTH_IN\": \"16\"}]\n)\n@pytest.mark.parametrize(\"clean_build\", [False, True])\n@pytest.mark.parametrize(\"pre_cmd\", [[\"touch pre_cmd_test_file;\"], None])\ndef test_runner(parameters, pre_cmd, clean_build):\n    if sim not in pre_cmd_sims and pre_cmd is not None:\n        pytest.skip(\"This simulator does not support pre_cmd\")\n\n    hdl_toplevel_lang = os.getenv(\"TOPLEVEL_LANG\", \"verilog\")\n    vhdl_gpi_interfaces = os.getenv(\"VHDL_GPI_INTERFACE\", None)\n\n    if hdl_toplevel_lang == \"verilog\":\n        sources = [os.path.join(tests_dir, \"designs\", \"runner\", \"runner.sv\")]\n        gpi_interfaces = [\"vpi\"]\n    else:\n        sources = [os.path.join(tests_dir, \"designs\", \"runner\", \"runner.vhdl\")]\n        gpi_interfaces = [vhdl_gpi_interfaces]\n\n    runner = get_runner(sim)\n    compile_args = [VHDL(\"-v93\")] if sim == \"xcelium\" else []\n\n    # Pre-make build directory and test file for clean build assertions\n    build_dir = (\n        sim_build\n        + \"/test_runner/\"\n        + \"_\".join(\"{}={}\".format(*i) for i in parameters.items())\n        + (\"_pre_cmd\" if pre_cmd is not None else \"\")\n        + (\"_clean\" if clean_build else \"\")\n    )\n    os.makedirs(build_dir, exist_ok=True)\n    open(build_dir + \"/clean_test_file\", \"a\").close()\n\n    runner.build(\n        sources=sources,\n        hdl_toplevel=\"runner\",\n        parameters=parameters,\n        defines={\"DEFINE\": 4, \"DEFINE_STR\": string_define_value},\n        includes=[os.path.join(tests_dir, \"designs\", \"basic_hierarchy_module\")],\n        build_args=compile_args,\n        clean=clean_build,\n        build_dir=build_dir,\n    )\n\n    runner.test(\n        hdl_toplevel=\"runner\",\n        test_module=\"test_runner\",\n        pre_cmd=pre_cmd,\n        gpi_interfaces=gpi_interfaces,\n        extra_env=parameters,\n    )\n\n    # Assert pre_cmd result. Questa only, at the moment\n    if sim == \"questa\":\n        if pre_cmd is not None:\n            assert os.path.isfile(build_dir + \"/pre_cmd_test_file\")\n        else:\n            assert not os.path.isfile(build_dir + \"/pre_cmd_test_file\")\n\n    # In case clean_build runner.build() must purge test directory completely,\n    # with the test file inside\n    if clean_build:\n        assert not os.path.isfile(build_dir + \"/clean_test_file\")\n    else:\n        assert os.path.isfile(build_dir + \"/clean_test_file\")\n\n\ndef test_missing_libpython(monkeypatch):\n    hdl_toplevel_lang = os.getenv(\"TOPLEVEL_LANG\", \"verilog\")\n    if hdl_toplevel_lang == \"verilog\":\n        hdl_sources = [os.path.join(tests_dir, \"designs\", \"runner\", \"runner.sv\")]\n        gpi_interfaces = [\"vpi\"]\n    else:\n        hdl_sources = [os.path.join(tests_dir, \"designs\", \"runner\", \"runner.vhdl\")]\n        gpi_interfaces = [os.getenv(\"VHDL_GPI_INTERFACE\", None)]\n\n    sim_tool = os.getenv(\n        \"SIM\",\n        \"icarus\" if os.getenv(\"TOPLEVEL_LANG\", \"verilog\") == \"verilog\" else \"nvc\",\n    )\n    sim_runner = get_runner(sim_tool)\n    sim_params = {\n        \"WIDTH_IN\": \"8\",\n        \"WIDTH_OUT\": \"8\",\n    }\n    build_args = [VHDL(\"-v93\")] if sim_tool == \"xcelium\" else []\n    build_dir = os.path.join(sim_build, \"test_missing_libpython\")\n\n    os.makedirs(build_dir, exist_ok=True)\n\n    sim_runner.build(\n        sources=hdl_sources,\n        hdl_toplevel=\"runner\",\n        parameters=sim_params,\n        defines={\"DEFINE\": 4, \"DEFINE_STR\": string_define_value},\n        includes=[os.path.join(tests_dir, \"designs\", \"basic_hierarchy_module\")],\n        build_args=build_args,\n        build_dir=build_dir,\n    )\n\n    def mock_find_libpython():\n        return None\n\n    monkeypatch.setattr(find_libpython, \"find_libpython\", mock_find_libpython)\n\n    with pytest.raises(ValueError):\n        sim_runner.test(\n            hdl_toplevel=\"runner\",\n            test_module=\"test_runner\",\n            gpi_interfaces=gpi_interfaces,\n            extra_env=sim_params,\n        )\n"
  },
  {
    "path": "tests/pytest/test_timescale.py",
    "content": "from __future__ import annotations\n\nimport os\nimport sys\nimport tempfile\n\nimport pytest\nfrom test_cocotb import (\n    compile_args,\n    gpi_interfaces,\n    hdl_toplevel,\n    hdl_toplevel_lang,\n    sim,\n    sim_args,\n    sim_build,\n    sources,\n    tests_dir,\n)\n\nfrom cocotb.simtime import _get_log_time_scale\nfrom cocotb_tools.runner import get_runner\n\nsys.path.insert(0, os.path.join(tests_dir, \"pytest\"))\n\ncocotb_test_contents = \"\"\"\nimport cocotb\nfrom cocotb.simtime import time_precision\n\n@cocotb.test()\nasync def check_timescale(dut):\n    assert time_precision == {precision}\n\"\"\"\n\n\n@pytest.mark.simulator_required\n@pytest.mark.skipif(\n    os.getenv(\"SIM\", \"icarus\") not in [\"icarus\", \"ghdl\", \"verilator\", \"dsim\"],\n    reason=\"Currently only Icarus, GHDL, Verilator, and Dsim support timescale setting when using cocotb runner\",\n)\n@pytest.mark.parametrize(\"precision\", [\"fs\", \"ps\", \"ns\", \"us\", \"ms\", \"s\"])\ndef test_precision(precision):\n    build_dir = os.path.join(sim_build, f\"test_timescale_{precision}\")\n\n    timescale = (f\"1{precision}\", f\"1{precision}\")\n    precision_log = _get_log_time_scale(precision if precision != \"s\" else \"sec\")\n\n    with tempfile.TemporaryDirectory() as d:\n        sys.path.insert(0, d)\n        test_module_path = os.path.join(d, \"test_precision.py\")\n        test_module = os.path.basename(os.path.splitext(test_module_path)[0])\n        with open(test_module_path, \"w\") as f:\n            f.write(cocotb_test_contents.format(precision=precision_log))\n            f.flush()\n\n        runner = get_runner(sim)\n        runner.build(\n            always=True,\n            clean=True,\n            sources=sources,\n            hdl_toplevel=hdl_toplevel,\n            build_dir=build_dir,\n            build_args=compile_args,\n            defines={\"NOTIMESCALE\": 1},\n            timescale=timescale,\n        )\n\n        runner.test(\n            hdl_toplevel_lang=hdl_toplevel_lang,\n            hdl_toplevel=hdl_toplevel,\n            gpi_interfaces=gpi_interfaces,\n            test_module=test_module,\n            test_args=sim_args,\n            build_dir=build_dir,\n            timescale=timescale,\n        )\n"
  },
  {
    "path": "tests/pytest/test_version.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport shutil\nimport subprocess\n\nimport cocotb\n\n\ndef test_version():\n    if \"dev\" in cocotb.__version__ and os.path.exists(\".git\") and shutil.which(\"git\"):\n        assert \"+\" in cocotb.__version__\n        parts = cocotb.__version__.split(\"+\")\n        rev = subprocess.check_output(\n            [\"git\", \"rev-parse\", \"--short\", \"HEAD\"], universal_newlines=True\n        ).strip()\n        assert parts[1] == f\"r{rev}\", (\n            \"Installed cocotb version is not the same as your latest git version\"\n        )\n"
  },
  {
    "path": "tests/pytest/test_vhdl_libraries_multiple.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport sys\nfrom pathlib import Path\n\nimport pytest\n\nfrom cocotb_tools.runner import get_runner\n\npytestmark = pytest.mark.simulator_required\n\nsrc_path = (\n    Path(__file__).resolve().parent.parent\n    / \"test_cases\"\n    / \"test_vhdl_libraries_multiple\"\n)\nsys.path.insert(0, str(src_path))\n\n\n@pytest.mark.skipif(\n    os.getenv(\"TOPLEVEL_LANG\", \"vhdl\") != \"vhdl\",\n    reason=\"Skipping test since only VHDL is supported\",\n)\n@pytest.mark.skipif(\n    os.getenv(\"SIM\", \"ghdl\") not in [\"ghdl\", \"nvc\", \"questa\", \"riviera\"],\n    reason=\"Skipping test since only GHDL, NVC, Questa/ModelSim, and Riviera are supported\",\n)\ndef test_toplevel_library():\n    vhdl_gpi_interfaces = os.getenv(\"VHDL_GPI_INTERFACE\", None)\n    gpi_interfaces = [vhdl_gpi_interfaces]\n\n    sim = os.getenv(\"SIM\", \"ghdl\")\n    runner = get_runner(sim)\n\n    compile_args = []\n    if sim == \"xcelium\":\n        compile_args = [\"-v93\"]\n\n    # Build additional libraries\n    for lib in [\"e\", \"d\", \"c\", \"b\"]:\n        runner.build(\n            hdl_library=f\"{lib}lib\",\n            sources=[src_path / f\"{lib}.vhdl\"],\n            build_args=compile_args,\n            build_dir=str(src_path / \"sim_build\" / \"pytest\"),\n        )\n\n    # Build main hdl_library\n    lib = \"a\"\n    runner.build(\n        hdl_library=f\"{lib}lib\",\n        sources=[src_path / f\"{lib}.vhdl\"],\n        hdl_toplevel=\"a\",\n        build_args=compile_args,\n        build_dir=str(src_path / \"sim_build\" / \"pytest\"),\n    )\n\n    runner.test(\n        hdl_toplevel=\"a\",\n        hdl_toplevel_library=\"alib\",\n        test_module=\"test_abcde\",\n        gpi_interfaces=gpi_interfaces,\n    )\n"
  },
  {
    "path": "tests/pytest/test_waves.py",
    "content": "from __future__ import annotations\n\nimport os\nimport subprocess\nimport sys\nimport tempfile\nfrom pathlib import Path\n\nimport pytest\nfrom test_cocotb import (\n    compile_args,\n    gpi_interfaces,\n    hdl_toplevel,\n    hdl_toplevel_lang,\n    sim_args,\n    sim_build,\n    sources,\n    tests_dir,\n)\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import ClockCycles\nfrom cocotb_tools.runner import get_runner\nfrom cocotb_tools.sim_versions import VerilatorVersion\n\nsys.path.insert(0, os.path.join(tests_dir, \"pytest\"))\ntest_module = os.path.basename(os.path.splitext(__file__)[0])\nsim = os.getenv(\n    \"SIM\",\n    \"icarus\" if os.getenv(\"TOPLEVEL_LANG\", \"verilog\") == \"verilog\" else \"nvc\",\n)\n\n\n@cocotb.test()\nasync def clock_design(dut):\n    clock = Clock(dut.clk, 10, unit=\"us\")\n    cocotb.start_soon(clock.start())\n    await ClockCycles(dut.clk, 10)\n\n\ndef run_simulation(sim, extra_build_args=None, test_args=None):\n    runner = get_runner(sim)\n    build_args = compile_args\n    if extra_build_args:\n        build_args = build_args + extra_build_args\n    runner.build(\n        always=True,\n        clean=True,\n        sources=sources,\n        hdl_toplevel=hdl_toplevel,\n        build_dir=sim_build,\n        build_args=build_args,\n        waves=False if sim in (\"xcelium\",) else True,\n    )\n\n    _test_args = sim_args\n    if test_args is not None:\n        _test_args.extend(test_args)\n\n    runner.test(\n        hdl_toplevel_lang=hdl_toplevel_lang,\n        hdl_toplevel=hdl_toplevel,\n        gpi_interfaces=gpi_interfaces,\n        test_module=test_module,\n        test_args=_test_args,\n        build_dir=sim_build,\n        waves=True,\n    )\n\n\n@pytest.mark.simulator_required\n@pytest.mark.skipif(\n    sim not in [\"icarus\", \"verilator\", \"xcelium\", \"nvc\", \"ghdl\"],\n    reason=\"Skipping test because it is only for Icarus, Verilator, Xcelium, NVC, and GHDL simulators\",\n)\ndef test_wave_dump():\n    run_simulation(sim=sim)\n    if sim == \"icarus\":\n        dumpfile_path = os.path.join(sim_build, f\"{hdl_toplevel}.fst\")\n    elif sim == \"verilator\":\n        dumpfile_path = os.path.join(sim_build, \"dump.vcd\")\n    elif sim == \"xcelium\":\n        dumpfile_path = os.path.join(sim_build, \"cocotb_waves.shm\", \"cocotb_waves.trn\")\n    elif sim == \"nvc\":\n        dumpfile_path = os.path.join(sim_build, f\"{hdl_toplevel}.fst\")\n    elif sim == \"ghdl\":\n        dumpfile_path = os.path.join(sim_build, f\"{hdl_toplevel}.ghw\")\n    else:\n        raise RuntimeError(\"Not a supported simulator\")\n    assert os.path.exists(dumpfile_path)\n\n\nskip_saif_dump_test = True\nif sim == \"verilator\":\n    sim_version_str = subprocess.run(\n        [\"verilator\", \"--version\"],\n        check=True,\n        text=True,\n        stdout=subprocess.PIPE,\n    ).stdout\n    sim_version = VerilatorVersion.from_commandline(sim_version_str)\n    if sim_version >= VerilatorVersion(\"5.042\"):\n        skip_saif_dump_test = False\n\n\n@pytest.mark.simulator_required\n@pytest.mark.skipif(\n    skip_saif_dump_test,\n    reason=\"Skipping test because it is only for the Verilator simulator, v5.042 or higher\",\n)\ndef test_saif_dump():\n    run_simulation(sim=sim, extra_build_args=[\"--trace-saif\"])\n    if sim == \"verilator\":\n        dumpfile_path = os.path.join(sim_build, \"dump.saif\")\n    else:\n        raise RuntimeError(\"Not a supported simulator\")\n    assert os.path.exists(dumpfile_path)\n\n\n@pytest.mark.simulator_required\n@pytest.mark.skipif(\n    sim not in [\"verilator\"],\n    reason=\"Skipping test because it is only for the Verilator simulator\",\n)\ndef test_named_wave_dump():\n    temp_dir = Path(tempfile.mkdtemp())\n    waves_file = temp_dir / \"waves.vcd\"\n    run_simulation(sim=sim, test_args=[\"--trace-file\", str(waves_file)])\n    if sim not in [\"verilator\"]:\n        raise RuntimeError(\"Not a supported simulator\")\n    assert waves_file.exists()\n"
  },
  {
    "path": "tests/pytest_plugin/conftest.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Configuration for all tests.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import AsyncGenerator\nfrom pathlib import Path\nfrom typing import Any\n\nfrom pytest import FixtureRequest, Parser, PytestPluginManager, fixture, hookimpl\n\nfrom cocotb.clock import Clock\nfrom cocotb_tools.pytest.hdl import HDL\n\nPLUGIN: str = \"cocotb_tools.pytest.plugin\"\nDESIGNS: Path = Path(__file__).parent.parent.resolve() / \"designs\"\n\n\n@hookimpl(tryfirst=True)\ndef pytest_addoption(parser: Parser, pluginmanager: PytestPluginManager) -> None:\n    \"\"\"Load pytest cocotb plugin in early stage of pytest when adding options to pytest.\n\n    This will allow to automatically load plugin when invoking ``pytest`` with ``tests/pytest_plugin`` argument\n    without need of providing additional ``-p cocotb_tools.pytest.plugin`` argument.\n\n    Most users in their projects will load plugin by defining an entry point in ``pyproject.toml`` file:\n\n    .. code:: toml\n\n        [project.entry-points.pytest11]\n        cocotb = \"cocotb_tools.pytest.plugin\"\n\n    Args:\n        parser: Instance of command line arguments parser used by pytest.\n        pluginmanager: Instance of pytest plugin manager.\n    \"\"\"\n    if not pluginmanager.has_plugin(PLUGIN):\n        pluginmanager.import_plugin(PLUGIN)  # import and register plugin\n\n\n@fixture(name=\"sample_module\")\ndef sample_module_fixture(hdl: HDL, request: FixtureRequest) -> HDL:\n    \"\"\"Define HDL design by adding HDL source files.\n\n    To run cocotb tests for HDL design:\n\n    .. code:: python\n\n       import pytest\n       from cocotb_tools.pytest.hdl import HDL\n\n       @pytest.mark.cocotb_runner\n       def test_sample_module(sample_module: HDL) -> None:\n           sample_module.test()\n\n    Args:\n        hdl: HDL design.\n\n    Returns:\n        Defined HDL design with added HDL source files.\n    \"\"\"\n    hdl.toplevel = \"sample_module\"\n\n    # Selected based on command line argument --cocotb-toplevel-lang=<verilog|vhdl>\n    # or enforced by HDL simulator choice --cocotb-simulator=<name>\n    if hdl.toplevel_lang == \"vhdl\":\n        hdl.sources = (\n            DESIGNS / \"sample_module\" / \"sample_module_package.vhdl\",\n            DESIGNS / \"sample_module\" / \"sample_module_1.vhdl\",\n            DESIGNS / \"sample_module\" / \"sample_module.vhdl\",\n        )\n    else:\n        hdl.sources = (DESIGNS / \"sample_module\" / \"sample_module.sv\",)\n\n    if hdl.simulator == \"questa\":\n        hdl.build_args = [\"+acc\"]\n\n    elif hdl.simulator == \"xcelium\":\n        hdl.build_args = [\"-v93\"]\n\n    elif hdl.simulator == \"nvc\":\n        hdl.build_args = [\"--std=08\"]\n\n    hdl.build()\n\n    return hdl\n\n\n@fixture(name=\"clock_generation\", scope=\"session\", autouse=True)\nasync def clock_generation_fixture(dut: Any) -> AsyncGenerator[None, None]:\n    \"\"\"Generate clock for all tests using session scope.\"\"\"\n    # Test setup (executed before test), create and start clock generation\n    dut.clk.value = 0\n\n    Clock(dut.clk, 10, unit=\"ns\").start(start_high=False)\n\n    yield  # Calling test, yield is needed to keep clock generation alive\n\n    # Test teardown (executed after test), clock generation will be finished here\n"
  },
  {
    "path": "tests/pytest_plugin/test_caplog.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test pytest `caplog` fixture.\"\"\"\n\nfrom __future__ import annotations\n\nfrom logging import INFO, WARNING, Logger, getLogger\n\nfrom pytest import LogCaptureFixture\n\n\nasync def test_capture_info(dut, caplog: LogCaptureFixture) -> None:\n    \"\"\"Test capturing informational logs.\"\"\"\n    caplog.set_level(INFO, logger=\"test\")\n    logger: Logger = getLogger(\"test\")\n\n    expected: str = \"Message to be captured\"\n    logger.info(expected)\n\n    assert expected in caplog.text\n\n\nasync def test_capture_warning(dut, caplog: LogCaptureFixture) -> None:\n    \"\"\"Test capturing warning logs.\"\"\"\n    caplog.set_level(WARNING, logger=\"test\")\n    logger: Logger = getLogger(\"test\")\n\n    unexpected: str = \"Unexpected message not to be captured\"\n    expected: str = \"Warning to be captured\"\n\n    logger.info(unexpected)\n    logger.warning(expected)\n\n    assert expected in caplog.text\n    assert unexpected not in caplog.text\n"
  },
  {
    "path": "tests/pytest_plugin/test_cocotb.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test ``@cocotb.*`` decorators with pytest used as regression manager for cocotb tests.\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.triggers import FallingEdge, SimTimeoutError\n\n\n@cocotb.test\nasync def test_default_1(dut) -> None:\n    \"\"\"Test default arguments from @cocotb.test decorator.\"\"\"\n\n\n@cocotb.test()\nasync def test_default_2(dut) -> None:\n    \"\"\"Test default arguments from @cocotb.test decorator.\"\"\"\n\n\n@cocotb.test(skip=True)\nasync def test_skip_true(dut) -> None:\n    \"\"\"Test skip from @cocotb.test decorator.\"\"\"\n    raise RuntimeError(\"skipped error\")\n\n\n@cocotb.test(skip=False)\nasync def test_skip_false(dut) -> None:\n    \"\"\"Test skip from @cocotb.test decorator.\"\"\"\n\n\n@cocotb.test(timeout_time=100, timeout_unit=\"ns\", expect_error=SimTimeoutError)\nasync def test_timeout(dut) -> None:\n    \"\"\"Test timeout from @cocotb.test decorator.\"\"\"\n    for _ in range(100):\n        await FallingEdge(dut.clk)\n\n\n@cocotb.test(expect_fail=True)\nasync def test_expect_fail_true(dut) -> None:\n    \"\"\"Test expect fail from @cocotb.test decorator.\"\"\"\n    raise RuntimeError(\"expecting any error\")\n\n\n@cocotb.test(expect_fail=False)\nasync def test_expect_fail_false(dut) -> None:\n    \"\"\"Test expect fail from @cocotb.test decorator.\"\"\"\n\n\n@cocotb.test(expect_error=None)\nasync def test_expect_error_none(dut) -> None:\n    \"\"\"Test expect error from @cocotb.test decorator.\"\"\"\n\n\n@cocotb.test(expect_error=RuntimeError)\nasync def test_expect_error_1(dut) -> None:\n    \"\"\"Test expect error from @cocotb.test decorator.\"\"\"\n    raise RuntimeError(\"expecting runtime error\")\n\n\n@cocotb.test(expect_error=(RuntimeError, ValueError))\nasync def test_expect_error_2(dut) -> None:\n    \"\"\"Test expect error from @cocotb.test decorator.\"\"\"\n    raise ValueError(\"expecting value error\")\n\n\n@cocotb.xfail()\nasync def test_xfail_default(dut) -> None:\n    \"\"\"Test @cocotb.xfail decorator.\"\"\"\n    raise RuntimeError(\"expecting any error\")\n\n\n@cocotb.xfail(raises=None)\nasync def test_xfail_raises_none(dut) -> None:\n    \"\"\"Test @cocotb.xfail decorator.\"\"\"\n    raise RuntimeError(\"expecting any error\")\n\n\n@cocotb.xfail(raises=RuntimeError)\nasync def test_xfail_raises_1(dut) -> None:\n    \"\"\"Test @cocotb.xfail decorator.\"\"\"\n    raise RuntimeError(\"expecting runtime error\")\n\n\n@cocotb.xfail(raises=(RuntimeError, ValueError))\nasync def test_xfail_raises_2(dut) -> None:\n    \"\"\"Test @cocotb.xfail decorator.\"\"\"\n    raise ValueError(\"expecting value error\")\n\n\n@cocotb.xfail(condition=False)\nasync def test_xfail_condition_false(dut) -> None:\n    \"\"\"Test @cocotb.xfail decorator.\"\"\"\n\n\n@cocotb.xfail(condition=True)\nasync def test_xfail_condition_true(dut) -> None:\n    \"\"\"Test @cocotb.xfail decorator.\"\"\"\n    raise RuntimeError(\"expecting any error\")\n\n\n@cocotb.xfail(reason=\"not yet supported\")\nasync def test_xfail_reason_message(dut) -> None:\n    \"\"\"Test @cocotb.xfail decorator.\"\"\"\n    raise RuntimeError(\"expecting any error\")\n\n\n@cocotb.skipif(True)\nasync def test_skipif_true(dut) -> None:\n    \"\"\"Test @cocotb.skipif decorator.\"\"\"\n    raise RuntimeError(\"skipped error\")\n\n\n@cocotb.skipif(False)\nasync def test_skipif_false(dut) -> None:\n    \"\"\"Test @cocotb.skipif decorator.\"\"\"\n\n\n@cocotb.parametrize()\nasync def test_parametrize_empty(dut) -> None:\n    \"\"\"Test @cocotb.parametrize decorator.\"\"\"\n\n\n@cocotb.parametrize(x=[1, 2], y=[3, 4, 5])\nasync def test_parametrize_matrix(dut, x: int, y: int) -> None:\n    \"\"\"Test @cocotb.parametrize decorator.\"\"\"\n    assert x in (1, 2)\n    assert y in (3, 4, 5)\n\n\n@cocotb.parametrize(((\"a\", \"b\"), [(1, 2), (3, 4)]))\nasync def test_parametrize_series_1(dut, a: int, b: int) -> None:\n    \"\"\"Test @cocotb.parametrize decorator.\"\"\"\n    assert (a == 1 and b == 2) or (a == 3 and b == 4)\n\n\n@cocotb.parametrize(\n    (\n        (\"x\", \"y\"),\n        ((1, 2), (3, 4)),\n    ),\n    (\n        \"z\",\n        (5, 6),\n    ),\n)\nasync def test_parametrize_series_2(dut, x: int, y: int, z: int) -> None:\n    \"\"\"Test @cocotb.parametrize decorator.\"\"\"\n    assert x in (1, 3)\n    assert y in (2, 4)\n    assert z in (5, 6)\n\n\nclass TestClass:\n    @cocotb.test\n    async def test_simple(dut) -> None:\n        \"\"\"Test @cocotb.test under class.\"\"\"\n\n    @cocotb.parametrize(x=(1, 2), y=(3, 4))\n    async def test_parametrize_matrix(dut, x: int, y: int) -> None:\n        \"\"\"Test @cocotb.parametrize under class.\"\"\"\n        assert x in (1, 2)\n        assert y in (3, 4)\n"
  },
  {
    "path": "tests/pytest_plugin/test_cocotb_top.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test :py:data:`cocotb.top` with pytest decorators.\"\"\"\n\nfrom __future__ import annotations\n\nimport pytest\n\nimport cocotb\n\n\n@pytest.mark.skipif(cocotb.top.INT_PARAM.value == 0, reason=\"\")\nasync def test_eq(dut) -> None:\n    \"\"\"Test `cocotb.top.ATTR == X`.\"\"\"\n\n\n@pytest.mark.skipif(cocotb.top.INT_PARAM.value != 0, reason=\"\")\nasync def test_nq(dut) -> None:\n    \"\"\"Test `cocotb.top.ATTR != X`.\"\"\"\n\n\n@pytest.mark.skipif(int(cocotb.top.INT_PARAM.value) < 0, reason=\"\")\nasync def test_lt(dut) -> None:\n    \"\"\"Test `cocotb.top.ATTR < X`.\"\"\"\n\n\n@pytest.mark.skipif(int(cocotb.top.INT_PARAM.value) <= 0, reason=\"\")\nasync def test_le(dut) -> None:\n    \"\"\"Test `cocotb.top.ATTR <= X`.\"\"\"\n\n\n@pytest.mark.skipif(int(cocotb.top.INT_PARAM.value) > 0, reason=\"\")\nasync def test_gt(dut) -> None:\n    \"\"\"Test `cocotb.top.ATTR > X`.\"\"\"\n\n\n@pytest.mark.skipif(int(cocotb.top.INT_PARAM.value) >= 0, reason=\"\")\nasync def test_ge(dut) -> None:\n    \"\"\"Test `cocotb.top.ATTR >= X`.\"\"\"\n\n\n@pytest.mark.skipif(cocotb.top.INT_PARAM.value, reason=\"\")\nasync def test_value(dut) -> None:\n    \"\"\"Test `cocotb.top.ATTR`.\"\"\"\n"
  },
  {
    "path": "tests/pytest_plugin/test_end_test.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test :func:`cocotb.end_test`.\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\n\n\nasync def test_end_test(dut) -> None:\n    \"\"\"Test :func:`cocotb.end_test`.\"\"\"\n    cocotb.end_test()\n    assert False, \"this should never be reached\"\n"
  },
  {
    "path": "tests/pytest_plugin/test_fixture.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test pytest fixtures with cocotb.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import AsyncGenerator, Generator\n\nfrom pytest import fixture\n\n\n@fixture(name=\"x\")\ndef x_fixture() -> int:\n    \"\"\"Simple fixture that is returning a value.\"\"\"\n    return 5\n\n\n@fixture(name=\"x_generator\")\ndef x_generator_fixture() -> Generator[int, None, None]:\n    \"\"\"Simple generator fixture that is returning a value.\"\"\"\n    yield 10\n\n\n@fixture(name=\"x_async\")\nasync def x_async_fixture() -> int:\n    \"\"\"Simple asynchronous fixture that is returning a value.\"\"\"\n    return 15\n\n\n@fixture(name=\"x_async_generator\")\nasync def x_async_generator_fixture() -> AsyncGenerator[int, None]:\n    \"\"\"Simple asynchronous generator fixture that is returning a value.\"\"\"\n    yield 20\n\n\nasync def test_fixture_value(dut, x: int) -> None:\n    \"\"\"Test fixture.\"\"\"\n    assert x == 5\n\n\nasync def test_fixture_generator(dut, x_generator: int) -> None:\n    \"\"\"Test generator fixture.\"\"\"\n    assert x_generator == 10\n\n\nasync def test_fixture_asynchronous_value(dut, x_async: int) -> None:\n    \"\"\"Test asynchronous fixture.\"\"\"\n    assert x_async == 15\n\n\nasync def test_fixture_asynchronous_generator(dut, x_async_generator: int) -> None:\n    \"\"\"Test asynchronous generator fixture.\"\"\"\n    assert x_async_generator == 20\n\n\nasync def test_fixture_mix(\n    dut, x: int, x_generator: int, x_async: int, x_async_generator\n) -> None:\n    \"\"\"Test mix of non-asynchronous and asynchronous fixtures.\"\"\"\n    assert x == 5\n    assert x_generator == 10\n    assert x_async == 15\n    assert x_async_generator == 20\n"
  },
  {
    "path": "tests/pytest_plugin/test_parametrize.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test ``@pytest.mark.parametrize`` for cocotb tests.\"\"\"\n\nfrom __future__ import annotations\n\nimport pytest\n\n\n@pytest.mark.parametrize(\"x\", [1, 2])\n@pytest.mark.parametrize(\"y\", [3, 4, 5])\nasync def test_matrix(dut, x: int, y: int) -> None:\n    \"\"\"Test @pytest.mark.parametrize.\"\"\"\n    assert x in (1, 2)\n    assert y in (3, 4, 5)\n\n\n@pytest.mark.parametrize(\"x,y\", ((1, 2), (3, 4)))\n@pytest.mark.parametrize(\"z\", (5, 6))\nasync def test_series(dut, x: int, y: int, z: int) -> None:\n    \"\"\"Test @pytest.mark.parametrize.\"\"\"\n    assert x in (1, 3)\n    assert y in (2, 4)\n    assert z in (5, 6)\n\n\n@pytest.mark.parametrize(\"z\", (1, 2))\nclass TestParametrize:\n    async def test_from_class(dut, z: int) -> None:\n        \"\"\"Test @pytest.mark.parametrize.\"\"\"\n        assert z in (1, 2)\n\n    @pytest.mark.parametrize(\"x\", [4, 5])\n    @pytest.mark.parametrize(\"y\", [6, 7, 8])\n    async def test_matrix(dut, x: int, y: int, z: int) -> None:\n        \"\"\"Test @pytest.mark.parametrize.\"\"\"\n        assert x in (4, 5)\n        assert y in (6, 7, 8)\n        assert z in (1, 2)\n\n    @pytest.mark.parametrize(\"x,y\", ((7, 8), (9, 4)))\n    async def test_series(dut, x: int, y: int, z: int) -> None:\n        \"\"\"Test @pytest.mark.parametrize.\"\"\"\n        assert x in (7, 9)\n        assert y in (8, 4)\n        assert z in (1, 2)\n"
  },
  {
    "path": "tests/pytest_plugin/test_sample_module.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test HDL DUT ``sample_module``.\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import AsyncGenerator\n\nimport pytest\n\nimport cocotb\nfrom cocotb.triggers import FallingEdge\nfrom cocotb_tools.pytest.hdl import HDL\n\n\n@pytest.fixture(autouse=True)\nasync def sample_module_fixture(dut) -> AsyncGenerator[None, None]:\n    \"\"\"Setup/teardown sample module.\"\"\"\n    # Test setup (executed before test)\n    dut.stream_in_valid.value = 0\n    dut.stream_in_data.value = 0\n    dut.stream_out_ready.value = 0\n\n    for _ in range(2):\n        await FallingEdge(dut.clk)\n\n    yield  # Calling test\n\n    # Test teardown (executed after test)\n    dut.stream_in_valid.value = 0\n    dut.stream_in_data.value = 0\n    dut.stream_out_ready.value = 0\n\n    # NOTE: Without it, Icarus simulator will crash with unexpected segmentation fault\n    # at the end of the simulation. This also happen using built-in regression manager.\n    # All other HDL simulators are fine, only Icarus is buggy\n    await FallingEdge(dut.clk)\n\n\n# cocotb marker is optional but it helps pytest-cocotb plugin to identify this function as cocotb runner and\n# bind collected cocotb tests to cocotb runner during pytest tests collection:\n# pytest --collect-only (in short: pytest --co)\n# With that, user can use pytest -k '<expression>' to quickly filter tests that will be run by particular runner\n@pytest.mark.cocotb_runner\ndef test_sample_module(sample_module: HDL) -> None:\n    \"\"\"Running HDL simulator using cocotb runner for sample module.\"\"\"\n    sample_module.test()\n\n\n@pytest.mark.cocotb_runner(\n    \"test_cocotb\",\n    \"test_cocotb_top\",\n    \"test_parametrize\",\n    \"test_xfail\",\n    \"test_caplog\",\n    \"test_end_test\",\n    \"test_timeout\",\n    \"test_fixture\",\n)\ndef test_sample_module_extra(sample_module: HDL) -> None:\n    \"\"\"Running HDL simulator using cocotb runner for sample module.\"\"\"\n    sample_module.test()\n\n\n@pytest.mark.cocotb_runner(\"test_sample_module_1\")\ndef test_sample_module_1(sample_module: HDL) -> None:\n    \"\"\"Running HDL simulator using cocotb runner for sample module.\"\"\"\n    sample_module.test()\n\n\n@pytest.mark.cocotb_runner(\"test_sample_module_1\", \"test_sample_module_2\")\ndef test_sample_module_2(sample_module: HDL) -> None:\n    \"\"\"Running HDL simulator using cocotb runner for sample module.\"\"\"\n    sample_module.test()\n\n\n@pytest.mark.cocotb_runner(\"test_sample_module_1\", \"test_sample_module_2\")\n@pytest.mark.parametrize(\"int_param\", (1, 4, 8))\ndef test_sample_module_parametrize(sample_module: HDL, int_param: int) -> None:\n    \"\"\"Running HDL simulator using cocotb runner for sample module.\"\"\"\n    sample_module[\"INT_PARAM\"] = int_param\n    sample_module.test()\n\n\nasync def test_pass(dut) -> None:\n    pass\n\n\nasync def test_simple(dut, start: int = 0, stop: int = 1, step: int = 1) -> None:\n    \"\"\"Test sample module with simple data transfer.\"\"\"\n    dut.stream_in_valid.value = 1\n    dut.stream_out_ready.value = 1\n    await FallingEdge(dut.clk)\n\n    for data in range(start, stop, step):\n        dut.stream_in_data.value = data\n        await FallingEdge(dut.clk)\n\n        assert dut.stream_out_data_registered.value == data\n\n\nasync def test_setup_only(dut) -> None:\n    \"\"\"Test sample module with simple data transfer.\"\"\"\n    await test_simple(dut)\n\n\n@pytest.mark.parametrize(\"start\", [0, 4])\n@pytest.mark.parametrize(\"stop\", [6, 8, 10])\n@pytest.mark.parametrize(\"step\", [1, 2])\nasync def test_parametrize_matrix(dut, start: int, stop: int, step: int) -> None:\n    \"\"\"Test sample module with simple data transfer.\"\"\"\n    await test_simple(dut, start, stop, step)\n\n\n@pytest.mark.parametrize(\"start,stop,step\", [(0, 4, 1), (2, 8, 2)])\nasync def test_parametrize_series(dut, start: int, stop: int, step: int) -> None:\n    \"\"\"Test sample module with simple data transfer.\"\"\"\n    await test_simple(dut, start, stop, step)\n\n\n@pytest.mark.parametrize(\"num\", [1, 4, 8])\nasync def test_parametrize_single(dut, num: int) -> None:\n    \"\"\"Test sample module with simple data transfer.\"\"\"\n    await test_simple(dut, stop=num)\n\n\n@pytest.mark.xfail(raises=RuntimeError, strict=True)\nasync def test_xfail_raises_string(dut) -> None:\n    \"\"\"Test sample module with simple data transfer.\"\"\"\n    await test_simple(dut)\n    raise RuntimeError(\"runtime error\")\n\n\n@pytest.mark.xfail(strict=True)\nasync def test_xfail_any(dut) -> None:\n    \"\"\"Test sample module with simple data transfer.\"\"\"\n    await test_simple(dut)\n    raise ValueError(\"value error\")\n\n\n@cocotb.xfail(raises=RuntimeError)\nasync def test_xfail_raises(dut) -> None:\n    \"\"\"Test sample module with simple data transfer.\"\"\"\n    await test_simple(dut)\n    raise RuntimeError(\"runtime error\")\n"
  },
  {
    "path": "tests/pytest_plugin/test_sample_module_1.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test HDL DUT ``sample_module``.\"\"\"\n\nfrom __future__ import annotations\n\nfrom cocotb.triggers import FallingEdge\n\n\nasync def test_dut(dut) -> None:\n    \"\"\"Test used to test DUT from other test module.\"\"\"\n    dut.stream_in_data.value = 1\n    await FallingEdge(dut.clk)\n    assert dut.stream_out_data_registered.value == 1\n"
  },
  {
    "path": "tests/pytest_plugin/test_sample_module_2.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test HDL DUT ``sample_module``.\"\"\"\n\nfrom __future__ import annotations\n\nfrom cocotb.triggers import FallingEdge\n\n\nasync def test_dut(dut) -> None:\n    \"\"\"Test used to test DUT from other test module.\"\"\"\n    dut.stream_in_data.value = 2\n    await FallingEdge(dut.clk)\n    assert dut.stream_out_data_registered.value == 2\n"
  },
  {
    "path": "tests/pytest_plugin/test_session.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Build HDL designs with different HDL modules at once during pytest session scope.\"\"\"\n\nfrom __future__ import annotations\n\nfrom pathlib import Path\n\nimport pytest\nfrom pytest import FixtureRequest, fixture\n\nfrom cocotb_tools.pytest.hdl import HDL\n\nDESIGNS: Path = Path(__file__).parent.parent.resolve() / \"designs\"\n\n\n@fixture(name=\"my_hdl_project\", scope=\"session\")\ndef my_hdl_project_fixture(hdl_session: HDL, request: FixtureRequest) -> HDL:\n    \"\"\"Define HDL design with all HDL modules and build it.\"\"\"\n    # NOTE: Icarus/Xcelium runners are requiring a defined top level\n    hdl_session.toplevel = \"sample_module\"\n\n    # Selected based on command line argument --cocotb-toplevel-lang=<verilog|vhdl>\n    # or enforced by HDL simulator choice --cocotb-simulator=<name>\n    if hdl_session.toplevel_lang == \"vhdl\":\n        hdl_session.sources = (\n            DESIGNS / \"array_module\" / \"array_module_pack.vhd\",\n            DESIGNS / \"array_module\" / \"array_module.vhd\",\n            DESIGNS / \"sample_module\" / \"sample_module_package.vhdl\",\n            DESIGNS / \"sample_module\" / \"sample_module_1.vhdl\",\n            DESIGNS / \"sample_module\" / \"sample_module.vhdl\",\n        )\n    else:\n        hdl_session.sources = (\n            DESIGNS / \"array_module\" / \"array_module.sv\",\n            DESIGNS / \"sample_module\" / \"sample_module.sv\",\n        )\n\n    if hdl_session.simulator == \"questa\":\n        hdl_session.build_args = [\"+acc\"]\n\n    elif hdl_session.simulator == \"xcelium\":\n        hdl_session.build_args = [\"-v93\"]\n\n    elif hdl_session.simulator == \"nvc\":\n        hdl_session.build_args = [\"--std=08\"]\n\n    hdl_session.build()\n\n    return hdl_session\n\n\n@fixture(name=\"array_module\")\ndef array_module_fixture(hdl: HDL, my_hdl_project: HDL) -> HDL:\n    \"\"\"Define HDL module: ``array_module``.\"\"\"\n    hdl.build_dir = my_hdl_project.build_dir\n    hdl.toplevel = \"array_module\"\n\n    return hdl\n\n\n@fixture(name=\"sample_module\")\ndef sample_module_fixture(hdl: HDL, my_hdl_project: HDL) -> HDL:\n    \"\"\"Define HDL module: ``sample_module``.\"\"\"\n    hdl.build_dir = my_hdl_project.build_dir\n    hdl.toplevel = \"sample_module\"\n\n    return hdl\n\n\n@pytest.mark.cocotb_runner\ndef test_array_module(array_module: HDL) -> None:\n    \"\"\"Run HDL simulator to test ``array_module``.\"\"\"\n    # TODO: Not all runners are supporting build_dir != test_dir :( For now, run only build stage\n    # array_module.test()\n\n\n@pytest.mark.cocotb_runner\ndef test_sample_module(sample_module: HDL) -> None:\n    \"\"\"Run HDL simulator to test ``sample_module``.\"\"\"\n    # TODO: Not all runners are supporting build_dir != test_dir :( For now, run only build stage\n    # sample_module.test()\n"
  },
  {
    "path": "tests/pytest_plugin/test_timeout.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test timeout with :py:deco:`cocotb_tools.pytest.mark.cocotb_timeout` marker.\"\"\"\n\nfrom __future__ import annotations\n\nimport pytest\n\nfrom cocotb.triggers import FallingEdge, SimTimeoutError\n\n\n@pytest.mark.xfail(raises=SimTimeoutError)\n@pytest.mark.cocotb_timeout(100, \"ns\")\nasync def test_timeout_with_positional_arguments(dut) -> None:\n    \"\"\"Test timeout with :py:deco:`cocotb_tools.pytest.mark.cocotb_timeout` marker.\"\"\"\n    for _ in range(100):\n        await FallingEdge(dut.clk)\n\n\n@pytest.mark.xfail(raises=SimTimeoutError)\n@pytest.mark.cocotb_timeout(duration=40, unit=\"ns\")\nasync def test_timeout_with_named_arguments(dut) -> None:\n    \"\"\"Test timeout with :py:deco:`cocotb_tools.pytest.mark.cocotb_timeout` marker.\"\"\"\n    for _ in range(100):\n        await FallingEdge(dut.clk)\n"
  },
  {
    "path": "tests/pytest_plugin/test_xfail.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test ``@pytest.mark.xfail`` for cocotb tests.\"\"\"\n\nfrom __future__ import annotations\n\nimport pytest\n\nimport cocotb\n\n\n@pytest.mark.xfail\nasync def test_any(dut) -> None:\n    \"\"\"Test ``@pytest.mark.xfail`` with any raise.\"\"\"\n    raise ValueError(\"expecting any error\")\n\n\n@cocotb.xfail(raises=RuntimeError)\nasync def test_raises_1(dut) -> None:\n    \"\"\"Test ``@pytest.mark.xfail`` with raises.\"\"\"\n    raise RuntimeError(\"expecting runtime error\")\n\n\n@cocotb.xfail(raises=(RuntimeError, ValueError))\nasync def test_raises_2(dut) -> None:\n    \"\"\"Test ``@pytest.mark.xfail`` with raises.\"\"\"\n    raise ValueError(\"expecting value error\")\n\n\n@pytest.mark.xfail(raises=RuntimeError, strict=True)\nasync def test_raises_strict(dut) -> None:\n    \"\"\"Test ``@pytest.mark.xfail`` with raises and strict.\"\"\"\n    raise RuntimeError(\"expecting runtime error\")\n\n\n@pytest.mark.xfail(strict=True)\nasync def test_any_strict(dut) -> None:\n    \"\"\"Test ``@pytest.mark.xfail`` with any raise.\"\"\"\n    raise ValueError(\"expecting any error\")\n"
  },
  {
    "path": "tests/sxs.ps1",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Run this script with:\n# powershell -executionpolicy bypass -File tests\\sxs.ps1\n\n$j = Start-Job -ScriptBlock { SxsTrace Trace -logfile:SxsTrace.etl }\nStart-Sleep -s 5\npython -c \"import cocotb.simulator\"\nStart-Sleep -s 5\n$j | Stop-Job\nSxsTrace Stoptrace\nSxsTrace Parse -logfile:SxsTrace.etl -outfile:SxsTrace.txt\nGet-Content SxsTrace.txt\n"
  },
  {
    "path": "tests/test_cases/test_array/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2016 Potential Ventures Ltd\n# Copyright (c) 2016 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# Icarus doesn't support structs (gh-2592)\n# Verilator doesn't support structs (gh-1275)\n\nifeq ($(SIM),)\nall:\n\t@echo \"Skipping test_array since icarus doesn't support structs\"\n\nclean::\n# nothing to clean, just define target in this branch\n\nelse ifneq ($(filter $(shell echo $(SIM) | tr A-Z a-z),icarus verilator),)\nall:\n\t@echo \"Skipping test_array since $(SIM) doesn't support structs\"\n\nclean::\n# nothing to clean, just define target in this branch\n\nelse\n\ninclude ../../designs/array_module/Makefile\n\nCOCOTB_TEST_MODULES = test_array\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_array/test_array.py",
    "content": "\"\"\"\nA set of tests that demonstrate Array structure support\n\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nimport os\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.handle import (\n    ArrayObject,\n    HierarchyArrayObject,\n    HierarchyObject,\n    LogicArrayObject,\n    LogicObject,\n    _HierarchyObjectBase,\n)\nfrom cocotb.triggers import Timer\nfrom cocotb_tools.sim_versions import XceliumVersion\n\nSIM_NAME = cocotb.SIM_NAME.lower()\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\n\n# NOTE: simulator-specific handling is done in this test itself, not via expect_error in the decorator\n# GHDL unable to access std_logic_vector generics (gh-2593) (hard crash, so skip)\n@cocotb.test(skip=SIM_NAME.startswith(\"ghdl\"))\nasync def test_read_write(dut):\n    \"\"\"Test handle inheritance\"\"\"\n\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n\n    await Timer(10, \"ns\")\n\n    assert dut.param_logic.value == 1\n    assert dut.param_logic_vec.value == 0xDA\n\n    if LANGUAGE in [\"vhdl\"]:\n        assert dut.param_bool.value == 1\n        assert dut.param_int.value == 6\n        assert dut.param_real.value == 3.14\n        assert dut.param_char.value == ord(\"p\")\n        assert dut.param_str.value == b\"ARRAYMOD\"\n\n        assert dut.param_rec.a.value == 0\n        assert dut.param_rec.b[0].value == 0\n        assert dut.param_rec.b[1].value == 0\n        assert dut.param_rec.b[2].value == 0\n        assert dut.param_cmplx[0].a.value == 0\n        assert dut.param_cmplx[0].b[0].value == 0\n        assert dut.param_cmplx[0].b[1].value == 0\n        assert dut.param_cmplx[0].b[2].value == 0\n        assert dut.param_cmplx[1].a.value == 0\n        assert dut.param_cmplx[1].b[0].value == 0\n        assert dut.param_cmplx[1].b[1].value == 0\n        assert dut.param_cmplx[1].b[2].value == 0\n\n    assert dut.const_logic.value == 0\n    assert dut.const_logic_vec.value == 0x3D\n\n    if LANGUAGE in [\"vhdl\"]:\n        assert dut.const_bool.value == 0\n        assert dut.const_int.value == 12\n        assert dut.const_real.value == 6.28\n        assert dut.const_char.value == ord(\"c\")\n        assert dut.const_str.value == b\"MODARRAY\"\n\n        assert dut.const_rec.a.value == 1\n        assert dut.const_rec.b[0].value == 0xFF\n        assert dut.const_rec.b[1].value == 0xFF\n        assert dut.const_rec.b[2].value == 0xFF\n        assert dut.const_cmplx[1].a.value == 1\n        assert dut.const_cmplx[1].b[0].value == 0xFF\n        assert dut.const_cmplx[1].b[1].value == 0xFF\n        assert dut.const_cmplx[1].b[2].value == 0xFF\n        assert dut.const_cmplx[2].a.value == 1\n        assert dut.const_cmplx[2].b[0].value == 0xFF\n        assert dut.const_cmplx[2].b[1].value == 0xFF\n        assert dut.const_cmplx[2].b[2].value == 0xFF\n\n    dut.select_in.value = 2\n\n    await Timer(10, \"ns\")\n\n    dut.sig_logic.value = 1\n    dut.sig_logic_vec.value = 0xCC\n    dut.sig_t2.value = [0xCC, 0xDD, 0xEE, 0xFF]\n    dut.sig_t4.value = [\n        [0x00, 0x11, 0x22, 0x33],\n        [0x44, 0x55, 0x66, 0x77],\n        [0x88, 0x99, 0xAA, 0xBB],\n        [0xCC, 0xDD, 0xEE, 0xFF],\n    ]\n\n    if LANGUAGE in [\"vhdl\"]:\n        dut.sig_bool.value = 1\n        dut.sig_int.value = 5000\n        dut.sig_real.value = 22.54\n        dut.sig_char.value = ord(\"Z\")\n        dut.sig_str.value = b\"Testing\"\n        dut.sig_rec.a.value = 1\n        dut.sig_rec.b[0].value = 0x01\n        dut.sig_rec.b[1].value = 0x23\n        dut.sig_rec.b[2].value = 0x45\n        dut.sig_cmplx[0].a.value = 0\n        dut.sig_cmplx[0].b[0].value = 0x67\n        dut.sig_cmplx[0].b[1].value = 0x89\n        dut.sig_cmplx[0].b[2].value = 0xAB\n        dut.sig_cmplx[1].a.value = 1\n        dut.sig_cmplx[1].b[0].value = 0xCD\n        dut.sig_cmplx[1].b[1].value = 0xEF\n        dut.sig_cmplx[1].b[2].value = 0x55\n\n    await Timer(10, \"ns\")\n\n    assert dut.port_logic_out.value == 1\n    assert dut.port_logic_vec_out.value == 0xCC\n    # Some writes to multi-dimensional arrays don't make it into the design.\n    # https://github.com/cocotb/cocotb/issues/3372\n    if not (\n        cocotb.SIM_NAME.startswith(\"xmsim\")\n        and XceliumVersion(cocotb.SIM_VERSION) < XceliumVersion(\"24.03-s004\")\n    ):\n        assert dut.sig_t2.value == [0xCC, 0xDD, 0xEE, 0xFF]\n        assert dut.sig_t2[7].value == 0xCC\n        assert dut.sig_t2[4].value == 0xFF\n        assert dut.sig_t4[1][5].value == 0x66\n        assert dut.sig_t4[3][7].value == 0xCC\n\n    if LANGUAGE in [\"vhdl\"]:\n        assert dut.port_bool_out.value == 1\n        assert dut.port_int_out.value == 5000\n        assert dut.port_real_out.value == 22.54\n        assert dut.port_char_out.value == ord(\"Z\")\n        assert dut.port_str_out.value == b\"Testing\"\n\n        assert dut.port_rec_out.a.value == 1\n        assert dut.port_rec_out.b[0].value == 0x01\n        assert dut.port_rec_out.b[1].value == 0x23\n        assert dut.port_rec_out.b[2].value == 0x45\n        assert dut.port_cmplx_out[0].a.value == 0\n        assert dut.port_cmplx_out[0].b[0].value == 0x67\n        assert dut.port_cmplx_out[0].b[1].value == 0x89\n        assert dut.port_cmplx_out[0].b[2].value == 0xAB\n        assert dut.port_cmplx_out[1].a.value == 1\n        assert dut.port_cmplx_out[1].b[0].value == 0xCD\n        assert dut.port_cmplx_out[1].b[1].value == 0xEF\n        assert dut.port_cmplx_out[1].b[2].value == 0x55\n\n\n# GHDL unable to access signals in generate loops (gh-2594)\n# VCS is unable to access signals in generate loops through VPI (#4328).\n@cocotb.test(\n    expect_error=IndexError\n    if SIM_NAME.startswith(\"ghdl\")\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else ()\n)\nasync def test_gen_loop(dut):\n    \"\"\"Test accessing Generate Loops\"\"\"\n    tlog = logging.getLogger(\"cocotb.test\")\n\n    asc_gen_20 = dut.asc_gen[20]\n    desc_gen = dut.desc_gen\n\n    assert isinstance(dut.asc_gen, HierarchyArrayObject)\n    assert isinstance(desc_gen, HierarchyArrayObject)\n    assert isinstance(asc_gen_20, HierarchyObject)\n\n    tlog.info(\"Direct access found %s\", asc_gen_20)\n    tlog.info(\"Direct access found %s\", desc_gen)\n\n    for gens in desc_gen:\n        tlog.info(\"Iterate access found %s\", gens)\n\n    assert len(desc_gen) == 8\n    tlog.info(\"Length of desc_gen is %d\", len(desc_gen))\n\n    assert len(dut.asc_gen) == 8\n    tlog.info(\"Length of asc_gen is %d\", len(dut.asc_gen))\n\n    for gens in dut.asc_gen:\n        tlog.info(\"Iterate access found %s\", gens)\n\n\n@cocotb.test()\nasync def test_discover_all(dut):\n    r\"\"\"Discover everything in the DUT:\n    dut\n           TYPE    CNT  NOTES                                                  EXCEPTIONS\n       parameters: 7/2 (base types)                                            (VHDL/Verilog)\n                     6 (param_rec.a, param_rec.b[0:2])                         (VHDL Only)\n                    13 (param_cmplx[0:1].a, param_cmplx[0:1].b[0:2])           (VHDL Only)\n            ports:   1 (clk)\n                     1 (select_in)                                             (VPI - Aldec sees as 32 bit register (i.e. cnt = 33)\n                     9 (port_desc_in)\n                     9 (port_asc_in)\n                     9 (port_ofst_in)\n                     9 (port_desc_out)\n                     9 (port_asc_out)\n                     9 (port_ofst_out)\n                     1 (port_logic_out)\n                     9 (port_logic_vec_out)\n                     1 (port_bool_out)                                         (VHDL Only)\n                     1 (port_int_out)                                          (VHDL Only)\n                     1 (port_real_out)                                         (VHDL Only)\n                     1 (port_char_out)                                         (VHDL Only)\n                     9 (port_str_out)                                          (VHDL Only)\n                    30 (port_rec_out)                                          (VPI - Aldec sees as a Module and not structure (i.e. cnt = 1))\n                    61 (port_cmplx_out)                                        (VPI - Aldec sees as a Module and not structure (i.e. cnt = 1))\n        constants:   1 (const_logic)\n                     9 (const_logic_vec)\n                     1 (const_bool)                                            (VHDL Only)\n                     1 (const_int)                                             (VHDL Only)\n                     1 (const_real)                                            (VHDL Only)\n                     1 (const_char)                                            (VHDL Only)\n                     9 (const_str)                                             (VHDL Only)\n                     1 (const_rec)                                             (VHDL Only)\n                     1 (const_rec.a)                                           (VHDL Only)\n                     1 (const_rec.b)                                           (VHDL Only)\n                     9 (const_rec.b[0])                                        (VHDL Only)\n                     9 (const_rec.b[1])                                        (VHDL Only)\n                     9 (const_rec.b[2])                                        (VHDL Only)\n                     1 (const_cmplx)                                           (VHDL Only)\n                     1 (const_cmplx[1])                                        (VHDL Only)\n                     1 (const_cmplx[1].a)                                      (VHDL Only)\n                     1 (const_cmplx[1].b)                                      (VHDL Only)\n                     9 (const_cmplx[1].b[0])                                   (VHDL Only)\n                     9 (const_cmplx[1].b[1])                                   (VHDL Only)\n                     9 (const_cmplx[1].b[2])                                   (VHDL Only)\n                     1 (const_cmplx[2])                                        (VHDL Only)\n                     1 (const_cmplx[2].a)                                      (VHDL Only)\n                     1 (const_cmplx[2].b)                                      (VHDL Only)\n                     9 (const_cmplx[2].b[0])                                   (VHDL Only)\n                     9 (const_cmplx[2].b[1])                                   (VHDL Only)\n                     9 (const_cmplx[2].b[2])                                   (VHDL Only)\n          signals:   9 (sig_desc)\n                     9 (sig_asc)\n                     1 (\\ext_id\\)                                              (VHDL Only)\n                     1 (\\!\\)                                                   (VHDL Only)\n                     5 (sig_t1)\n                    37 (sig_t2[7:4][7:0])\n                    37 (sig_t3a[1:4][7:0])\n                    37 (sig_t3b[3:0][7:0])\n                   149 (sig_t4[0:3][7:4][7:0])\n                   112 (sig_t5[0:2][0:3][7:0])\n                    57 (sig_t6[0:1][2:4][7:0])\n                   149 (sig_t7[3:0][3:0])                                      (VPI Only)\n                   149 ([3:0][3:0]sig_t8)                                      (VPI Only)\n                     1 (sig_logic)\n                     9 (sig_logic_vec)\n                     1 (sig_bool)                                              (VHDL Only)\n                     1 (sig_int)                                               (VHDL Only)\n                     1 (sig_real)                                              (VHDL Only)\n                     1 (sig_char)                                              (VHDL Only)\n                     9 (sig_str)                                               (VHDL Only)\n                    30 (sig_rec.a, sig_rec.b[0:2][7:0])                        (VPI doesn't find, added manually, except for Aldec)\n                    61 (sig_cmplx[0:1].a, sig_cmplx[0:1].b[0:2][7:0])          (VPI - Aldec older than 2017.10.67 doesn't find)\n          regions:   9 (asc_gen[16:23])\n                     8 (asc_gen: signals)\n                     8 (asc_gen: constant)\n                     8 (asc_gen: variable)\n                     9 (desc_gen[7:0])\n                     8 (desc_gen: signals)\n                     8 (desc_gen: constant)\n                     8 (desc_gen: variable)\n\n            TOTAL: 1032 (VHDL - Default)\n                    818 (VHDL - Aldec)\n                   1078 (Verilog - Default)\n               947/1038 (Verilog - Aldec)\n    \"\"\"\n\n    tlog = logging.getLogger(\"cocotb.test\")\n\n    await Timer(10, \"ns\")\n\n    # Modelsim/Questa VPI will not find a vpiStructVar from vpiModule so we access them explicitly\n    # to ensure the handle is in the dut \"sub_handles\" for iterating\n    if LANGUAGE in [\"verilog\"] and cocotb.SIM_NAME.lower().startswith(\n        (\"modelsim\", \"ncsim\", \"xmsim\")\n    ):\n        dut.sig_rec\n        dut.port_rec_out\n\n    if cocotb.SIM_NAME.lower().startswith(\"ghdl\"):\n        pass_total = 56\n    elif (\n        LANGUAGE in [\"vhdl\"]\n        and cocotb.SIM_NAME.lower().startswith(\"modelsim\")\n        and os.environ[\"VHDL_GPI_INTERFACE\"] == \"vhpi\"\n    ):\n        # VHPI finds the array_module.asc_gen and array_module.desc_gen more than once =/\n        pass_total = 308\n    elif LANGUAGE in [\"verilog\"] and cocotb.SIM_NAME.lower().startswith(\"riviera\"):\n        # Applies to Riviera-PRO 2019.10 and newer.\n        pass_total = 180\n    elif LANGUAGE in [\"verilog\"] and \"vcs\" in SIM_NAME:\n        # VCS is unable to access signals in generate loops through VPI (#4328).\n        pass_total = 172\n    elif LANGUAGE in [\"vhdl\"]:\n        pass_total = 244\n    else:\n        # verilog\n        pass_total = 206\n\n    def _discover(obj):\n        if not isinstance(\n            obj,\n            (\n                _HierarchyObjectBase,\n                ArrayObject,\n            ),\n        ):\n            return 0\n        count = 0\n        for thing in obj:\n            count += 1\n            tlog.info(\"Found %s (%s)\", thing._path, type(thing))\n            count += _discover(thing)\n        return count\n\n    total = _discover(dut)\n    tlog.info(\"Found a total of %d things\", total)\n    assert total == pass_total\n\n\n# GHDL unable to access std_logic_vector generics (gh-2593)\n@cocotb.test(\n    skip=(LANGUAGE in [\"verilog\"] or cocotb.SIM_NAME.lower().startswith(\"riviera\")),\n    expect_error=AttributeError if SIM_NAME.startswith(\"ghdl\") else (),\n)\nasync def test_direct_constant_indexing(dut):\n    \"\"\"Test directly accessing constant/parameter data in arrays, i.e. not iterating\"\"\"\n\n    assert isinstance(dut.param_rec, HierarchyObject)\n    assert isinstance(dut.param_rec.a, LogicObject)\n    assert isinstance(dut.param_rec.b, ArrayObject)\n    assert isinstance(dut.param_rec.b[1], LogicArrayObject)\n\n    assert isinstance(dut.param_cmplx, ArrayObject)\n    assert isinstance(dut.param_cmplx[0], HierarchyObject)\n    assert isinstance(dut.param_cmplx[0].a, LogicObject)\n    assert isinstance(dut.param_cmplx[0].b, ArrayObject)\n    assert isinstance(dut.param_cmplx[0].b[1], LogicArrayObject)\n\n    assert isinstance(dut.const_rec, HierarchyObject)\n    assert isinstance(dut.const_rec.a, LogicObject)\n    assert isinstance(dut.const_rec.b, ArrayObject)\n    assert isinstance(dut.const_rec.b[1], LogicArrayObject)\n\n    assert isinstance(dut.const_cmplx, ArrayObject)\n    assert isinstance(dut.const_cmplx[1], HierarchyObject)\n    assert isinstance(dut.const_cmplx[1].a, LogicObject)\n    assert isinstance(dut.const_cmplx[1].b, ArrayObject)\n    assert isinstance(dut.const_cmplx[1].b[1], LogicArrayObject)\n\n\n# GHDL unable to index multi-dimensional arrays (gh-2587)\n@cocotb.test(expect_fail=SIM_NAME.startswith(\"ghdl\"))\nasync def test_direct_signal_indexing(dut):\n    \"\"\"Test directly accessing signal/net data in arrays, i.e. not iterating\"\"\"\n\n    assert isinstance(dut.sig_t1, LogicArrayObject)\n    assert isinstance(dut.sig_t2, ArrayObject)\n    assert isinstance(dut.sig_t2[5], LogicArrayObject)\n    assert isinstance(dut.sig_t3b[3], LogicArrayObject)\n    assert isinstance(dut.sig_t3a, ArrayObject)\n    assert isinstance(dut.sig_t4, ArrayObject)\n    assert isinstance(dut.sig_t4[3], ArrayObject)\n    assert isinstance(dut.sig_t4[3][4], LogicArrayObject)\n    assert isinstance(dut.sig_t5, ArrayObject)\n    assert isinstance(dut.sig_t5[1], ArrayObject)\n    assert isinstance(dut.sig_t5[1][0], LogicArrayObject)\n    assert isinstance(dut.sig_t6, ArrayObject)\n    assert isinstance(dut.sig_t6[1], ArrayObject)\n    assert isinstance(dut.sig_t6[0][3], LogicArrayObject)\n\n    if LANGUAGE in [\"verilog\"]:\n        assert isinstance(dut.sig_t7[1], ArrayObject)\n        assert isinstance(dut.sig_t7[0][3], LogicArrayObject)\n        assert isinstance(dut.sig_t8, LogicArrayObject)\n\n    assert isinstance(dut.sig_cmplx, ArrayObject)\n    assert isinstance(dut.sig_cmplx[1], HierarchyObject)\n    assert isinstance(dut.sig_cmplx[1].a, LogicObject)\n    assert isinstance(dut.sig_cmplx[1].b, ArrayObject)\n    assert isinstance(dut.sig_cmplx[1].b[1], LogicArrayObject)\n\n    assert isinstance(dut.sig_rec, HierarchyObject)\n    assert isinstance(dut.sig_rec.a, LogicObject)\n    assert isinstance(dut.sig_rec.b, ArrayObject)\n    assert isinstance(dut.sig_rec.b[1], LogicArrayObject)\n\n\n@cocotb.test(skip=(LANGUAGE in [\"verilog\"]))\nasync def test_extended_identifiers(dut):\n    \"\"\"Test accessing extended identifiers\"\"\"\n\n    assert isinstance(dut[\"\\\\ext_id\\\\\"], LogicObject)\n    assert isinstance(dut[\"\\\\!\\\\\"], LogicObject)\n"
  },
  {
    "path": "tests/test_cases/test_array_simple/Makefile",
    "content": "include ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES = test_array_simple\n"
  },
  {
    "path": "tests/test_cases/test_array_simple/test_array_simple.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"Test getting and setting values of arrays\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nimport os\n\nimport pytest\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import Timer\n\ntlog = logging.getLogger(\"cocotb.test\")\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\n\ndef _check_value(tlog, hdl, expected):\n    assert hdl.value == expected\n    tlog.info(f\"   Found {hdl!r} ({hdl._type}) with value={hdl.value}\")\n\n\n# GHDL unable to put values on nested array types (gh-2588)\n@cocotb.test(\n    expect_error=Exception if cocotb.SIM_NAME.lower().startswith(\"ghdl\") else ()\n)\nasync def test_1dim_array_handles(dut):\n    \"\"\"Test getting and setting array values using the handle of the full array.\"\"\"\n\n    cocotb.start_soon(Clock(dut.clk, 1000, \"ns\").start())\n\n    dut.array_7_downto_4.value = [0xF0, 0xE0, 0xD0, 0xC0]\n    dut.array_4_to_7.value = [0xB0, 0xA0, 0x90, 0x80]\n    dut.array_3_downto_0.value = [0x70, 0x60, 0x50, 0x40]\n    dut.array_0_to_3.value = [0x30, 0x20, 0x10, 0x00]\n\n    await Timer(1000, \"ns\")\n\n    _check_value(tlog, dut.array_7_downto_4, [0xF0, 0xE0, 0xD0, 0xC0])\n    _check_value(tlog, dut.array_4_to_7, [0xB0, 0xA0, 0x90, 0x80])\n    _check_value(tlog, dut.array_3_downto_0, [0x70, 0x60, 0x50, 0x40])\n    _check_value(tlog, dut.array_0_to_3, [0x30, 0x20, 0x10, 0x00])\n\n\n# GHDL unable to put values on nested array types (gh-2588)\n# iverilog flattens multi-dimensional unpacked arrays (gh-2595)\n@cocotb.test(\n    expect_error=Exception\n    if cocotb.SIM_NAME.lower().startswith((\"icarus\", \"ghdl\"))\n    else ()\n)\nasync def test_ndim_array_handles(dut):\n    \"\"\"Test getting and setting multi-dimensional array values using the handle of the full array.\"\"\"\n\n    cocotb.start_soon(Clock(dut.clk, 1000, \"ns\").start())\n\n    dut.array_2d.value = [[0xF0, 0xE0, 0xD0, 0xC0], [0xB0, 0xA0, 0x90, 0x80]]\n\n    await Timer(1000, \"ns\")\n\n    _check_value(\n        tlog, dut.array_2d, [[0xF0, 0xE0, 0xD0, 0xC0], [0xB0, 0xA0, 0x90, 0x80]]\n    )\n\n\n# GHDL unable to put values on nested array types (gh-2588)\n@cocotb.test(\n    expect_error=Exception if cocotb.SIM_NAME.lower().startswith(\"ghdl\") else ()\n)\nasync def test_1dim_array_indexes(dut):\n    \"\"\"Test getting and setting values of array indexes.\"\"\"\n\n    cocotb.start_soon(Clock(dut.clk, 1000, \"ns\").start())\n\n    dut.array_7_downto_4.value = [0xF0, 0xE0, 0xD0, 0xC0]\n    dut.array_4_to_7.value = [0xB0, 0xA0, 0x90, 0x80]\n    dut.array_3_downto_0.value = [0x70, 0x60, 0x50, 0x40]\n    dut.array_0_to_3.value = [0x30, 0x20, 0x10, 0x00]\n\n    await Timer(1000, \"ns\")\n\n    # Check indices\n    _check_value(tlog, dut.array_7_downto_4[7], 0xF0)\n    _check_value(tlog, dut.array_7_downto_4[4], 0xC0)\n    _check_value(tlog, dut.array_4_to_7[4], 0xB0)\n    _check_value(tlog, dut.array_4_to_7[7], 0x80)\n    _check_value(tlog, dut.array_3_downto_0[3], 0x70)\n    _check_value(tlog, dut.array_3_downto_0[0], 0x40)\n    _check_value(tlog, dut.array_0_to_3[0], 0x30)\n    _check_value(tlog, dut.array_0_to_3[3], 0x00)\n    _check_value(tlog, dut.array_0_to_3[1], 0x20)\n\n    # Get sub-handles through ArrayObject.__getitem__\n    dut.array_7_downto_4[7].value = 0xDE\n    dut.array_4_to_7[4].value = 0xFC\n    dut.array_3_downto_0[0].value = 0xAB\n    dut.array_0_to_3[1].value = 0x7A\n    dut.array_0_to_3[3].value = 0x42\n\n    await Timer(1000, \"ns\")\n\n    _check_value(tlog, dut.array_7_downto_4[7], 0xDE)\n    _check_value(tlog, dut.array_4_to_7[4], 0xFC)\n    _check_value(tlog, dut.array_3_downto_0[0], 0xAB)\n    _check_value(tlog, dut.array_0_to_3[1], 0x7A)\n    _check_value(tlog, dut.array_0_to_3[3], 0x42)\n\n\n# GHDL unable to put values on nested array types (gh-2588)\n# iverilog flattens multi-dimensional unpacked arrays (gh-2595)\n@cocotb.test(\n    expect_error=Exception\n    if cocotb.SIM_NAME.lower().startswith((\"icarus\", \"ghdl\"))\n    else ()\n)\nasync def test_ndim_array_indexes(dut):\n    \"\"\"Test getting and setting values of multi-dimensional array indexes.\"\"\"\n\n    cocotb.start_soon(Clock(dut.clk, 1000, \"ns\").start())\n\n    dut.array_2d.value = [[0xF0, 0xE0, 0xD0, 0xC0], [0xB0, 0xA0, 0x90, 0x80]]\n\n    await Timer(1000, \"ns\")\n\n    # Check indices\n    _check_value(tlog, dut.array_2d[1], [0xB0, 0xA0, 0x90, 0x80])\n    _check_value(tlog, dut.array_2d[0][31], 0xF0)\n    _check_value(tlog, dut.array_2d[1][29], 0x90)\n    _check_value(tlog, dut.array_2d[1][28], 0x80)\n\n    # Get sub-handles through ArrayObject.__getitem__\n    dut.array_2d[1].value = [0xDE, 0xAD, 0xBE, 0xEF]\n    dut.array_2d[0][31].value = 0x0F\n\n    await Timer(1000, \"ns\")\n\n    _check_value(tlog, dut.array_2d[0][31], 0x0F)\n    _check_value(tlog, dut.array_2d[0][29], 0xD0)\n    _check_value(tlog, dut.array_2d[1][30], 0xAD)\n    _check_value(tlog, dut.array_2d[1][28], 0xEF)\n\n\n# GHDL unable to access record signals (gh-2591)\n# Icarus doesn't support structs (gh-2592)\n# Verilator doesn't support structs (gh-1275)\n# Riviera-PRO does not discover inout_if correctly over VPI (gh-3587, gh-3933)\n@cocotb.test(\n    expect_error=AttributeError\n    if cocotb.SIM_NAME.lower().startswith((\"icarus\", \"ghdl\", \"verilator\"))\n    or (cocotb.SIM_NAME.lower().startswith(\"riviera\") and LANGUAGE == \"verilog\")\n    else ()\n)\nasync def test_struct_unpacked(dut):\n    \"\"\"Test setting and getting values of unpacked structs.\"\"\"\n    cocotb.start_soon(Clock(dut.clk, 1000, \"ns\").start())\n    dut.inout_if.a_in.value = 1\n    await Timer(1000, \"ns\")\n    _check_value(tlog, dut.inout_if.a_in, 1)\n    dut.inout_if.a_in.value = 0\n    await Timer(1000, \"ns\")\n    _check_value(tlog, dut.inout_if.a_in, 0)\n\n\n@cocotb.test()\nasync def test_exceptions(dut):\n    \"\"\"Test that correct Exceptions are raised.\"\"\"\n    with pytest.raises(TypeError):\n        dut.array_4_to_7.value = Exception(\"Exception Object\")\n    with pytest.raises(ValueError):\n        dut.array_3_downto_0.value = [0x70, 0x60, 0x50]\n    with pytest.raises(ValueError):\n        dut.array_0_to_3.value = [0x40, 0x30, 0x20, 0x10, 0x00]\n"
  },
  {
    "path": "tests/test_cases/test_async_bridge/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES = test_async_bridge\n"
  },
  {
    "path": "tests/test_cases/test_async_bridge/test_async_bridge.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013, 2018 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport threading\nimport time\n\nimport pytest\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.task import bridge, resume\nfrom cocotb.triggers import ReadOnly, RisingEdge, Timer\nfrom cocotb.utils import get_sim_steps, get_sim_time\n\n\ndef return_two(dut):\n    return 2\n\n\n@resume\nasync def await_two_clock_edges(dut):\n    await RisingEdge(dut.clk)\n    await RisingEdge(dut.clk)\n    await Timer(1, unit=\"ns\")\n    cocotb.log.info(\"Returning from await_two_clock_edges\")\n    return 2\n\n\ndef calls_resume(dut):\n    return await_two_clock_edges(dut)\n\n\ndef print_sim_time(dut, base_time):\n    # We are not calling out here so time should not advance\n    # And should also remain consistent\n    for _ in range(5):\n        time.sleep(0.02)\n        assert get_sim_time(\"step\") == base_time\n\n\n@cocotb.test()\nasync def test_time_in_bridge(dut):\n    \"\"\"\n    Test that the simulation time does not advance if the wrapped blocking\n    routine does not call @resume\n    \"\"\"\n    await Timer(10, unit=\"ns\")\n    time = get_sim_time(\"step\")\n    for _ in range(10):\n        await bridge(print_sim_time)(dut, time)\n\n    time_now = get_sim_time(\"step\")\n    await Timer(10, unit=\"ns\")\n\n    assert time == time_now\n\n\n@cocotb.test()\nasync def test_time_in_resume(dut):\n    \"\"\"\n    Test that an @bridge function calling back into a cocotb @resume\n    takes the expected amount of time\n    \"\"\"\n\n    @resume\n    async def wait_cycles(dut, n):\n        for _ in range(n):\n            await RisingEdge(dut.clk)\n\n    @bridge\n    def wait_cycles_wrapper(dut, n):\n        return wait_cycles(dut, n)\n\n    cocotb.start_soon(Clock(dut.clk, 100, unit=\"ns\").start())\n    await Timer(10, unit=\"ns\")\n    for n in range(5):\n        for _ in range(20):\n            await RisingEdge(dut.clk)\n            time = get_sim_time(\"step\")\n            expected_after = time + get_sim_steps(100, \"ns\") * n\n            await wait_cycles_wrapper(dut, n)\n            time_after = get_sim_time(\"step\")\n            assert expected_after == time_after\n\n\n@cocotb.test()\nasync def test_blocking_function_call_return(dut):\n    \"\"\"\n    Test ability to await a blocking function that is not a coroutine using @bridge\n    \"\"\"\n\n    async def clock_monitor(dut):\n        count = 0\n        while True:\n            await RisingEdge(dut.clk)\n            await Timer(1000, unit=\"ns\")\n            count += 1\n\n    cocotb.start_soon(clock_monitor(dut))\n    cocotb.start_soon(Clock(dut.clk, 100, unit=\"ns\").start())\n    value = await bridge(return_two)(dut)\n    assert value == 2\n\n\n@cocotb.test()\nasync def test_consecutive_bridges(dut):\n    \"\"\"\n    Test that multiple @bridge functions can be called in the same test\n    \"\"\"\n    value = await bridge(return_two)(dut)\n    cocotb.log.info(\"First one completed\")\n    assert value == 2\n\n    value = await bridge(return_two)(dut)\n    cocotb.log.info(\"Second one completed\")\n    assert value == 2\n\n\n@cocotb.test()\nasync def test_bridge_from_readonly(dut):\n    \"\"\"\n    Test that @bridge functions that don't consume simulation time\n    can be called from ReadOnly state\n    \"\"\"\n    await ReadOnly()\n    cocotb.log.info(\"In readonly\")\n    value = await bridge(return_two)(dut)\n    assert value == 2\n\n\n@cocotb.test()\nasync def test_resume_from_readonly(dut):\n    \"\"\"\n    Test that @bridge functions that call @resumes that await Triggers\n    can be called from ReadOnly state\n    \"\"\"\n    cocotb.start_soon(Clock(dut.clk, 100, unit=\"ns\").start())\n\n    await ReadOnly()\n    cocotb.log.info(\"In readonly\")\n    value = await bridge(calls_resume)(dut)\n    assert value == 2\n\n\n@cocotb.test()\nasync def test_resume_that_awaits(dut):\n    \"\"\"\n    Test that @bridge functions can call @resume coroutines that\n    awaits Triggers and return values back through to\n    the test\n    \"\"\"\n    cocotb.start_soon(Clock(dut.clk, 100, unit=\"ns\").start())\n\n    value = await bridge(calls_resume)(dut)\n    assert value == 2\n\n\n@cocotb.test()\nasync def test_await_after_bridge(dut):\n    \"\"\"\n    Test that awaiting a Trigger works after returning\n    from @bridge functions that call @resumes that consume\n    simulation time\n    \"\"\"\n    cocotb.start_soon(Clock(dut.clk, 100, unit=\"ns\").start())\n\n    value = await bridge(calls_resume)(dut)\n    assert value == 2\n\n    await Timer(10, unit=\"ns\")\n    await RisingEdge(dut.clk)\n\n\n@cocotb.test()\nasync def test_bridge_from_start_soon(dut):\n    \"\"\"\n    Test that @bridge functions work when awaited from a forked\n    task\n    \"\"\"\n\n    async def run_function(dut):\n        value = await bridge(calls_resume)(dut)\n        return value\n\n    async def run_bridge(dut):\n        value = await bridge(return_two)(dut)\n        return value\n\n    cocotb.start_soon(Clock(dut.clk, 100, unit=\"ns\").start())\n\n    coro1 = cocotb.start_soon(run_function(dut))\n    value = await coro1\n    assert value == 2\n    cocotb.log.info(\"Back from join 1\")\n\n    value = 0\n    coro2 = cocotb.start_soon(run_bridge(dut))\n    value = await coro2\n    assert value == 2\n    cocotb.log.info(\"Back from join 2\")\n\n\n@cocotb.test()\nasync def test_bridge_raised_exception(dut):\n    \"\"\"\n    Test that exceptions thrown by @bridge functions can be caught\n    \"\"\"\n\n    @bridge\n    def func():\n        raise ValueError()\n\n    with pytest.raises(ValueError):\n        await func()\n\n\n@cocotb.test()\nasync def test_bridge_returns_exception(dut):\n    \"\"\"\n    Test that exceptions can be returned by @bridge functions\n    \"\"\"\n\n    @bridge\n    def func():\n        return ValueError()\n\n    result = await func()\n\n    assert isinstance(result, ValueError)\n\n\n@cocotb.test()\nasync def test_resume_raised_exception(dut):\n    \"\"\"\n    Test that exceptions thrown by @resume coroutines can be caught\n    \"\"\"\n\n    @resume\n    async def func():\n        raise ValueError()\n\n    @bridge\n    def ext():\n        return func()\n\n    with pytest.raises(ValueError):\n        await ext()\n\n\n@cocotb.test()\nasync def test_resume_returns_exception(dut):\n    \"\"\"\n    Test that exceptions can be returned by @resume coroutines\n    \"\"\"\n\n    @resume\n    async def gen_func():\n        return ValueError()\n\n    @bridge\n    def ext():\n        return gen_func()\n\n    result = await ext()\n\n    assert isinstance(result, ValueError)\n\n\n@cocotb.test()\nasync def test_resume_from_weird_thread_fails(dut):\n    \"\"\"\n    Test that background threads calling a @resume do not hang forever\n    \"\"\"\n    func_started = False\n    caller_resumed = False\n    raised = False\n\n    @resume\n    async def func():\n        nonlocal func_started\n        func_started = True\n        await Timer(10, unit=\"ns\")\n\n    def function_caller():\n        nonlocal raised\n        nonlocal caller_resumed\n        try:\n            func()\n        except RuntimeError:\n            raised = True\n        finally:\n            caller_resumed = True\n\n    @bridge\n    def ext():\n        t = threading.Thread(target=function_caller)\n        t.start()\n        t.join()\n\n    task = cocotb.start_soon(ext())\n\n    await Timer(20, unit=\"ns\")\n\n    assert caller_resumed, \"Caller was never resumed\"\n    assert not func_started, \"Function should never have started\"\n    assert raised, \"No exception was raised to warn the user\"\n\n    await task\n\n\n@cocotb.test()\nasync def test_resume_called_in_parallel(dut):\n    \"\"\"\n    Test that the same `@resume` can be called from two parallel background\n    threads.\n    \"\"\"\n\n    @resume\n    async def function(x):\n        await Timer(1, unit=\"ns\")\n        return x\n\n    @bridge\n    def call_function(x):\n        return function(x)\n\n    t1 = cocotb.start_soon(call_function(1))\n    t2 = cocotb.start_soon(call_function(2))\n    v1 = await t1\n    v2 = await t2\n    assert v1 == 1, v1\n    assert v2 == 2, v2\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/sample_module/Makefile\n\n# The pytest_assertion_rewriting test module deliberately does not follow the\n# test_* naming convention to test that pytest assertion rewriting is enabled\n# on all test modules declared in COCOTB_TEST_MODULES (gh-3011)\nCOCOTB_TEST_MODULES := \"\\\n\ttest_deprecated,\\\n\ttest_synchronization_primitives,\\\n\ttest_first_combine,\\\n\ttest_tests,\\\n\ttest_testfactory,\\\n\ttest_timing_triggers,\\\n\ttest_scheduler,\\\n\ttest_clock,\\\n\ttest_edge_triggers,\\\n\ttest_async_coroutines,\\\n\ttest_async_generators,\\\n\ttest_handle,\\\n\ttest_logging,\\\n\tpytest_assertion_rewriting,\\\n\ttest_queues,\\\n\ttest_sim_time_utils,\\\n\ttest_start_soon,\\\n\ttest_ci,\\\n\ttest_waiters,\\\n\ttest_task_manager,\\\n\t\"\n\n# test_timing_triggers.py requires a 1ps time precision.\nCOCOTB_HDL_TIMEPRECISION := 1ps\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/common.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nCommon utilities shared by many tests in this directory\n\"\"\"\n\nfrom __future__ import annotations\n\nimport operator\nimport re\nimport traceback\nfrom collections.abc import Generator\nfrom contextlib import contextmanager\nfrom typing import Callable\n\nfrom cocotb.simtime import TimeUnit\nfrom cocotb.utils import get_sim_steps, get_sim_time, get_time_from_sim_steps\n\n\nasync def _check_traceback(running_coro, exc_type, pattern, *match_args):\n    try:\n        await running_coro\n    except exc_type:\n        tb_text = traceback.format_exc()\n    else:\n        assert False, \"Exception was not raised\"\n\n    assert re.match(pattern, tb_text, *match_args), (\n        \"Traceback didn't match - got:\\n\\n\"\n        f\"{tb_text}\\n\"\n        \"which did not match the pattern:\\n\\n\"\n        f\"{pattern}\"\n    )\n\n\nclass MyException(Exception): ...\n\n\nclass MyBaseException(BaseException): ...\n\n\n@contextmanager\ndef assert_takes(\n    time: float, unit: TimeUnit, cmp: Callable[[int, int], bool] = operator.eq\n) -> Generator[None, None, None]:\n    \"\"\"Assert that the block takes a certain amount of time to finish.\n\n    The *cmp* function passes actual after first argument and expected as the second.\n    Other useful comparison functions are: :func:`math.isclose`, and the functions in the\n    :mod:`operator` module.\n\n    Args:\n        time: Time value.\n        unit: Unit of *time*.\n        cmp: Comparison function to use. Defaults to equality.\n    \"\"\"\n    expected = get_sim_steps(time, unit)\n    start = get_sim_time(\"step\")\n    yield\n    end = get_sim_time(\"step\")\n    actual = end - start\n    actual_in_units = get_time_from_sim_steps(actual, unit)\n    assert cmp(actual, expected), (\n        f\"Expected the code to take {time}{unit}, actually took {actual_in_units}{unit}\"\n    )\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/pytest_assertion_rewriting.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"Tests relating to pytest integration\"\"\"\n\nfrom __future__ import annotations\n\nimport pytest\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_assertion_rewriting(_):\n    \"\"\"Test that assertion rewriting hooks take effect in cocotb tests\"\"\"\n    with pytest.raises(AssertionError) as e:\n        assert 1 == 42  # noqa: PLR0133\n    assert \"42\" in str(e), f\"Assertion rewriting seems not to work, message was {e}\"\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_async_coroutines.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTest function and substitutability of async coroutines\n\"\"\"\n\nfrom __future__ import annotations\n\nimport pytest\nfrom common import MyException\n\nimport cocotb\nfrom cocotb._outcomes import Error, Value\nfrom cocotb.task import Task\nfrom cocotb.triggers import Timer\n\n\nclass produce:\n    \"\"\"Test helpers that produce a value / exception in different ways\"\"\"\n\n    @staticmethod\n    async def async_(outcome):\n        await Timer(1)\n        return outcome.get()\n\n\n@cocotb.test()\nasync def test_async_from_async(dut):\n    \"\"\"Test that async coroutines are able to call raw async functions\"\"\"\n    v = await produce.async_(Value(1))\n    assert v == 1\n\n    try:\n        await produce.async_(Error(MyException))\n    except MyException:\n        pass\n    else:\n        assert False\n\n\n@cocotb.test()\nasync def test_trigger_await_gives_self(dut):\n    \"\"\"Test that await returns the trigger itself for triggers\"\"\"\n    t = Timer(1)\n    t2 = await t\n    assert t2 is t\n\n\n@cocotb.test()\nasync def test_fork_coroutine_function_exception(dut):\n    async def coro():\n        pass\n\n    pattern = f\"Coroutine function {coro} should be called prior to being scheduled.\"\n    with pytest.raises(TypeError, match=pattern):\n        cocotb.start_soon(coro)\n\n\n@cocotb.test()\nasync def test_task_coroutine_function_exception(dut):\n    async def coro(dut):\n        pass\n\n    pattern = f\"Coroutine function {coro} should be called prior to being scheduled.\"\n    with pytest.raises(TypeError, match=pattern):\n        Task(coro)\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_async_generators.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport pytest\n\nimport cocotb\nfrom cocotb.task import Task\n\n\nasync def whoops_async_generator():\n    # the user should have used `await` here, but they wrote `yield` by accident.\n    yield cocotb.triggers.Timer(1)\n\n\n@cocotb.test\nasync def test_forking_accidental_async_generator(_) -> None:\n    with pytest.raises(TypeError) as e:\n        cocotb.start_soon(whoops_async_generator())\n\n    assert \"async generator\" in str(e)\n\n\n@cocotb.test\nasync def test_constructing_accidental_async_generator(_) -> None:\n    with pytest.raises(TypeError) as e:\n        Task(whoops_async_generator())\n\n    assert \"async generator\" in str(e)\n\n\n@cocotb.test\nasync def test_creating_accidental_async_generator(_) -> None:\n    with pytest.raises(TypeError) as e:\n        cocotb.create_task(whoops_async_generator())\n\n    assert \"async generator\" in str(e)\n\n\n@cocotb.test\nasync def test_awaiting_accidental_async_generator(_) -> None:\n    with pytest.raises(TypeError):\n        await whoops_async_generator()\n\n    # Python handles this so we don't want to presume what the error message is\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_ci.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport sys\n\nimport cocotb\n\n\n@cocotb.test(skip=os.getenv(\"GITHUB_ACTIONS\") is None)\nasync def test_python_version(_: object) -> None:\n    assert sys.version.startswith(os.environ[\"PYTHON_VERSION\"].strip())\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_clock.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests relating to cocotb.clock.Clock\n\"\"\"\n\nfrom __future__ import annotations\n\nimport decimal\nimport fractions\nimport os\nfrom typing import Any\n\nimport pytest\nfrom common import assert_takes\n\nimport cocotb\nfrom cocotb._base_triggers import NullTrigger\nfrom cocotb.clock import Clock\nfrom cocotb.handle import Immediate\nfrom cocotb.simulator import clock_create, get_precision\nfrom cocotb.triggers import (\n    FallingEdge,\n    RisingEdge,\n    SimTimeoutError,\n    Timer,\n    ValueChange,\n    with_timeout,\n)\n\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\n\n@cocotb.test()\n@cocotb.parametrize(impl=[\"gpi\", \"py\"])\nasync def test_clock_with_units(dut, impl: str) -> None:\n    clk_1mhz = Clock(dut.clk, 1.0, unit=\"us\", impl=impl)\n    clk_250mhz = Clock(dut.clk, 4, unit=\"ns\", impl=impl)\n\n    assert clk_1mhz.signal is dut.clk\n    assert clk_1mhz.period == 1.0\n    assert clk_1mhz.unit == \"us\"\n    assert clk_1mhz.impl == impl\n\n    assert str(clk_1mhz) == f\"<Clock, {dut.clk._path} @ 1.0 MHz>\"\n    assert str(clk_250mhz) == f\"<Clock, {dut.clk._path} @ 250.0 MHz>\"\n\n    clk_1mhz.start()\n\n    with assert_takes(1000, \"ns\"):\n        await Timer(1, \"ns\")\n        await RisingEdge(dut.clk)\n\n    with assert_takes(1000, \"ns\"):\n        await RisingEdge(dut.clk)\n\n    clk_1mhz.stop()\n\n    clk_250mhz.start()\n\n    with assert_takes(4, \"ns\"):\n        await Timer(1, \"ns\")\n        await RisingEdge(dut.clk)\n\n    with assert_takes(4, \"ns\"):\n        await RisingEdge(dut.clk)\n\n    clk_250mhz.stop()\n\n\n@cocotb.test\nasync def test_gpi_clock_error_signal_type(_) -> None:\n    with pytest.raises(TypeError):\n        clock_create(None)\n\n\n@cocotb.test\nasync def test_gpi_clock_error_impl(dut):\n    with pytest.raises(ValueError):\n        Clock(dut.clk, 1.0, unit=\"step\", impl=\"invalid\")\n\n\n@cocotb.test\nasync def test_gpi_clock_error_params(dut):\n    clk = clock_create(dut.clk._handle)\n    with pytest.raises(TypeError):\n        clk.start(2, 1)\n\n\n@cocotb.test\nasync def test_gpi_clock_error_timing(dut):\n    clk = clock_create(dut.clk._handle)\n    with pytest.raises(ValueError):\n        clk.start(2, 3, True, 0)\n\n\n@cocotb.test\nasync def test_bad_period(dut):\n    with pytest.raises(ValueError, match=\"Bad `period`\"):\n        Clock(dut.clk, 1, unit=\"step\", impl=\"gpi\")\n    with pytest.raises(ValueError, match=\"Bad `period`\"):\n        Clock(dut.clk, 1, unit=\"step\", impl=\"py\")\n\n\n@cocotb.test\nasync def test_gpi_clock_error_already_started(dut):\n    clk = clock_create(dut.clk._handle)\n    clk.start(2, 1, True, 0)\n    with pytest.raises(RuntimeError):\n        clk.start(2, 1, True, 0)\n    clk.stop()\n\n\n# Xcelium/VHDL does not correctly report the simulator precision.\n# See also https://github.com/cocotb/cocotb/issues/3419\n@cocotb.test(skip=(LANGUAGE == \"vhdl\" and cocotb.SIM_NAME.startswith(\"xmsim\")))\nasync def test_clocks_with_other_number_types(dut):\n    # The following test assumes a time precision of at least 0.1ns.\n    # Update the simulator invocation if this assert hits!\n    assert get_precision() <= -10\n\n    clk1 = cocotb.start_soon(Clock(dut.clk, decimal.Decimal(\"1\"), unit=\"ns\").start())\n    await Timer(10, \"ns\")\n    clk1.cancel()\n    clk2 = cocotb.start_soon(Clock(dut.clk, fractions.Fraction(1), unit=\"ns\").start())\n    await Timer(10, \"ns\")\n    clk2.cancel()\n\n\n@cocotb.test\nasync def test_clock_stop_and_restart(dut) -> None:\n    c = Clock(dut.clk, 10, \"ns\")\n    c.start()\n    for _ in range(10):\n        await RisingEdge(dut.clk)\n    with pytest.raises(RuntimeError):\n        c.start()\n    c.stop()\n    with pytest.raises(RuntimeError):\n        c.stop()\n    c.start()\n    for _ in range(10):\n        await RisingEdge(dut.clk)\n\n\n@cocotb.test\nasync def test_clock_cycles(dut: Any) -> None:\n    period_ns = 10\n    cycles = 10\n    c = Clock(dut.clk, 10, \"ns\")\n    c.start()\n\n    with pytest.raises(ValueError):\n        await c.cycles(-5)\n\n    # so we start at a consistent state for math below\n    await RisingEdge(dut.clk)\n\n    with assert_takes(0, \"ns\"):\n        await c.cycles(0)\n\n    with assert_takes(cycles * period_ns, \"ns\"):\n        await c.cycles(cycles)\n\n    with assert_takes((cycles * period_ns) - (period_ns // 2), \"ns\"):\n        await c.cycles(cycles, FallingEdge)\n\n    with assert_takes((cycles * period_ns // 2), \"ns\"):\n        await c.cycles(cycles, ValueChange)\n\n\n@cocotb.test\nasync def test_clock_task_cancel(dut) -> None:\n    c = Clock(dut.clk, 10, \"ns\")\n    task = c.start()\n\n    await RisingEdge(dut.clk)\n    task.cancel()\n\n    # Ensure clock is dead.\n    with pytest.raises(SimTimeoutError):\n        await with_timeout(RisingEdge(dut.clk), 20, \"ns\")\n\n\n@cocotb.test\nasync def test_bad_set_action(dut: Any) -> None:\n    with pytest.raises(TypeError):\n        Clock(dut.clk, 10, \"ns\", set_action=1)\n\n\n# Immediate isn't truly immediate on every simulator,\n# and checking just one is sufficient to know it works.\n@cocotb.test(skip=not cocotb.SIM_NAME.lower().startswith(\"verilator\"))\nasync def test_set_action(dut: Any) -> None:\n    c = Clock(dut.clk, 10, \"ns\", set_action=Immediate)\n\n    c.start(start_high=True)\n    await NullTrigger()\n    assert dut.clk.value == 1\n\n    await Timer(5, \"ns\")\n    await NullTrigger()\n    assert dut.clk.value == 0\n\n    assert c.set_action is Immediate\n\n\n@cocotb.test\nasync def test_period_high(dut: Any) -> None:\n    # Check bad constructions\n    with pytest.raises(ValueError, match=\"Bad `period_high`\"):\n        Clock(dut.clk, 2, unit=\"step\", period_high=0.5, impl=\"gpi\")\n    with pytest.raises(ValueError, match=\"Bad `period_high`\"):\n        Clock(dut.clk, 2, unit=\"step\", period_high=0.5, impl=\"py\")\n    with pytest.raises(\n        ValueError, match=\"`period_high` must be strictly less than `period`\"\n    ):\n        Clock(dut.clk, 2, unit=\"step\", period_high=10)\n\n    # Check functionality\n    c = Clock(dut.clk, 9, \"ns\", period_high=7)\n    c.start()\n    await RisingEdge(dut.clk)\n    for _ in range(10):\n        with assert_takes(7, \"ns\"):\n            await FallingEdge(dut.clk)\n        with assert_takes(2, \"ns\"):\n            await RisingEdge(dut.clk)\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_deprecated.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport sys\nimport warnings\nfrom typing import Any\n\nimport pytest\nfrom common import assert_takes\n\nimport cocotb\nfrom cocotb._base_triggers import Lock\nfrom cocotb.clock import Clock\nfrom cocotb.regression import TestFactory\nfrom cocotb.task import Join, current_task\nfrom cocotb.triggers import Edge, Event, First, Timer\nfrom cocotb.utils import get_sim_steps, get_sim_time, get_time_from_sim_steps\n\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\n\n# identifiers starting with `_` are illegal in VHDL\n@cocotb.test(skip=LANGUAGE in (\"vhdl\"))\nasync def test_id_deprecated(dut):\n    with pytest.warns(DeprecationWarning):\n        dut._id(\"_underscore_name\", extended=False)\n\n\ntest_testfactory_deprecated_values = []\n\n\nasync def test_testfactory_deprecated_test(dut, a):\n    test_testfactory_deprecated_values.append(a)\n\n\nwith warnings.catch_warnings(record=True) as tf_warns:\n    warnings.simplefilter(\"default\", category=DeprecationWarning)\n    tf = TestFactory(test_testfactory_deprecated_test)\n\ntf.add_option(\"a\", [1, 2])\ntf.generate_tests()\n\n\n@cocotb.test\nasync def test_testfactory_deprecated(dut):\n    assert \"test_testfactory_deprecated_test_001\" in globals()\n    assert \"test_testfactory_deprecated_test_002\" in globals()\n    assert test_testfactory_deprecated_values == [1, 2]\n    assert len(tf_warns) == 1\n    assert tf_warns[0].category is DeprecationWarning\n\n\n@cocotb.test(skip=cocotb.SIM_NAME.lower().startswith((\"icarus\", \"ghdl\")))\nasync def test_real_handle_casts_deprecated(dut):\n    dut.stream_in_real.value = 5.03\n    await Timer(1, \"ns\")\n    with pytest.warns(DeprecationWarning):\n        assert float(dut.stream_in_real) == 5.03\n\n\n@cocotb.test(skip=cocotb.SIM_NAME.lower().startswith(\"icarus\"))\nasync def test_int_handle_casts_deprecated(dut):\n    dut.stream_in_int.value = 100\n    await Timer(1, \"ns\")\n    with pytest.warns(DeprecationWarning):\n        assert int(dut.stream_in_int) == 100\n\n\n@cocotb.test\nasync def test_logic_handle_casts_deprecated(dut):\n    dut.stream_in_data.value = 0b1011_0011\n    await Timer(1, \"ns\")\n    with pytest.warns(DeprecationWarning):\n        assert int(dut.stream_in_data) == 0b1011_0011\n    with pytest.warns(DeprecationWarning):\n        assert str(dut.stream_in_data) == \"10110011\"\n\n\n@cocotb.test(skip=cocotb.SIM_NAME.lower().startswith((\"icarus\", \"ghdl\")))\nasync def test_string_handle_casts_deprecated(dut):\n    dut.stream_in_string.value = b\"sample\"\n    await Timer(1, \"ns\")\n    with pytest.warns(DeprecationWarning):\n        str(dut.stream_in_string)\n\n\n@cocotb.test\nasync def test_join_trigger_deprecated(_) -> None:\n    async def returns_1():\n        return 1\n\n    t = cocotb.start_soon(returns_1())\n    with pytest.warns(DeprecationWarning, match=r\"Join\\(task\\)\"):\n        j = Join(t)\n    assert (await j) == 1\n    assert isinstance(j, Join)\n    assert type(j) is Join\n\n\n@cocotb.test\nasync def test_join_trigger_in_first_backwards_compat(_) -> None:\n    async def returns_1():\n        return 1\n\n    t = cocotb.start_soon(returns_1())\n    with pytest.warns(DeprecationWarning, match=r\"Join\\(task\\)\"):\n        j = Join(t)\n    res = await First(j, Timer(1))\n    assert res == 1\n\n\n@cocotb.test\nasync def test_task_join_deprecated(_) -> None:\n    async def returns_1():\n        return 1\n\n    t = cocotb.start_soon(returns_1())\n    with pytest.warns(DeprecationWarning, match=r\"task.join\\(\\)\"):\n        j = t.join()\n    assert (await j) == 1\n\n\n@cocotb.test\nasync def test_task_join_in_first_backwards_compat(_) -> None:\n    async def returns_1():\n        return 1\n\n    t = cocotb.start_soon(returns_1())\n    with pytest.warns(DeprecationWarning, match=r\"task.join\\(\\)\"):\n        j = t.join()\n    res = await First(j, Timer(1))\n    assert res == 1\n\n\n@cocotb.test\nasync def test_event_data_deprecated(_) -> None:\n    e = Event()\n\n    with pytest.warns(DeprecationWarning):\n        e.data = 12\n\n    with pytest.warns(DeprecationWarning):\n        assert e.data == 12\n\n    with pytest.warns(DeprecationWarning):\n        e.set(42)\n\n    with pytest.warns(DeprecationWarning):\n        assert e.data == 42\n\n\n@cocotb.test\nasync def test_logic_scalar_object_methods_deprecated(dut) -> None:\n    dut.stream_in_valid.value = 1\n    await Timer(1, \"ns\")\n    with pytest.warns(DeprecationWarning):\n        assert int(dut.stream_in_valid) == 1\n    with pytest.warns(DeprecationWarning):\n        assert str(dut.stream_in_valid) == \"1\"\n\n\n@cocotb.test\nasync def test_edge_trigger_deprecated(dut) -> None:\n    with pytest.warns(DeprecationWarning):\n        e = Edge(dut.stream_in_valid)\n    assert isinstance(e, Edge)\n    assert type(e) is Edge\n\n\n@cocotb.test\nasync def test_cocotb_start(_) -> None:\n    done = False\n\n    async def do_something():\n        nonlocal done\n        done = True\n\n    with pytest.warns(DeprecationWarning):\n        await cocotb.start(do_something())\n\n    assert done\n\n\n@cocotb.test\nasync def test_setimmediatevalue(dut) -> None:\n    with pytest.warns(DeprecationWarning):\n        dut.stream_in_data.setimmediatevalue(10)\n\n\n@cocotb.test\nasync def test_event_name_deprecated(_) -> None:\n    with pytest.warns(DeprecationWarning):\n        e = Event(\"test1\")\n\n    with pytest.warns(DeprecationWarning):\n        assert e.name == \"test1\"\n\n    with pytest.warns(DeprecationWarning):\n        e.name = \"test2\"\n\n    with pytest.warns(DeprecationWarning):\n        assert e.name == \"test2\"\n\n\n@cocotb.test\nasync def test_units_deprecated(dut: Any) -> None:\n    with assert_takes(10, \"ns\"), pytest.warns(DeprecationWarning):\n        await Timer(10, units=\"ns\")\n    with pytest.warns(DeprecationWarning):\n        assert Clock(dut.clk, 10, units=\"ns\").unit == \"ns\"\n    with pytest.warns(DeprecationWarning):\n        assert get_sim_time(units=\"ns\") == get_sim_time(\"ns\")\n    with pytest.warns(DeprecationWarning):\n        assert get_sim_steps(10, units=\"ns\") == get_sim_steps(10, \"ns\")\n    with pytest.warns(DeprecationWarning):\n        assert get_time_from_sim_steps(10, units=\"ns\") == get_time_from_sim_steps(\n            10, \"ns\"\n        )\n\n\n@cocotb.test(skip=sys.version_info < (3, 7))\nasync def test_results_deprecated(_: Any) -> None:\n    with pytest.warns(DeprecationWarning):\n        from cocotb.result import TestSuccess  # noqa: F401, PLC0415\n    with pytest.warns(DeprecationWarning):\n        from cocotb.result import SimFailure  # noqa: F401, PLC0415\n    with pytest.warns(DeprecationWarning):\n        from cocotb.result import SimTimeoutError  # noqa: F401, PLC0415\n\n\n@cocotb.test(skip=sys.version_info < (3, 7))\nasync def test_triggers_Join_import_deprecated(_: Any) -> None:\n    with pytest.warns(DeprecationWarning):\n        from cocotb.triggers import Join  # noqa: F401, PLC0415\n\n\n@cocotb.test\nasync def test_Lock_name_deprecated(_: object) -> None:\n    with pytest.warns(DeprecationWarning):\n        l = Lock(name=\"thingy\")\n    with pytest.warns(DeprecationWarning):\n        assert l.name == \"thingy\"\n    with pytest.warns(DeprecationWarning):\n        l.name = \"foobar\"\n    with pytest.warns(DeprecationWarning):\n        assert l.name == \"foobar\"\n\n\n@cocotb.test\nasync def test_Task_kill_unstarted(_: object) -> None:\n    async def example() -> None:\n        await Timer(10, \"ns\")\n\n    task = cocotb.create_task(example())\n\n    with pytest.warns(DeprecationWarning):\n        task.kill()\n\n    assert task.done()\n    assert task.result() is None\n\n\n@cocotb.test\nasync def test_Task_kill_scheduled(_: object) -> None:\n    async def example() -> None:\n        await Timer(10, \"ns\")\n\n    task = cocotb.start_soon(example())\n\n    with pytest.warns(DeprecationWarning):\n        task.kill()\n\n    assert task.done()\n    assert task.result() is None\n\n\n@cocotb.test\nasync def test_Task_kill_pending(_: object) -> None:\n    async def example() -> None:\n        await Timer(10, \"ns\")\n\n    task = cocotb.start_soon(example())\n    await Timer(1)\n\n    with pytest.warns(DeprecationWarning):\n        task.kill()\n\n    assert task.done()\n    assert task.result() is None\n\n\n@cocotb.test\nasync def test_Task_kill_done(_: object) -> None:\n    async def example() -> int:\n        return 1\n\n    task = cocotb.start_soon(example())\n    await Timer(1)\n\n    assert task.done()\n    assert task.result() == 1\n\n    with pytest.warns(DeprecationWarning):\n        task.kill()\n\n    assert task.done()\n    assert task.result() == 1\n\n\n@cocotb.test\nasync def test_Task_kill_running(_: object) -> None:\n    async def example() -> None:\n        task = current_task()\n        with pytest.warns(DeprecationWarning), pytest.raises(RuntimeError):\n            task.kill()\n        assert not task.done()\n        await Timer(1)\n        # things still work after the failed kill\n        assert not task.done()\n\n    task = cocotb.start_soon(example())\n    await task\n    assert task.done()\n\n\n@cocotb.test\nasync def test_pass_test_in_task(_) -> None:\n    async def raise_test_success():\n        await Timer(1, unit=\"ns\")\n        with pytest.warns(DeprecationWarning):\n            cocotb.pass_test(\"Finished test early\")\n\n    cocotb.start_soon(raise_test_success())\n    await Timer(10, unit=\"ns\")\n\n\n@cocotb.test\nasync def test_pass_test_in_test(_) -> None:\n    with pytest.warns(DeprecationWarning):\n        cocotb.pass_test(\"Finished test early\")\n\n\n@cocotb.test\n@cocotb.xfail(raises=TypeError)\nasync def test_pass_test_in_xfail_exception(dut: object) -> None:\n    with pytest.warns(DeprecationWarning):\n        cocotb.pass_test(\"Finished test early\")\n\n\n@cocotb.test\n@cocotb.xfail()\nasync def test_pass_test_in_xfail_assert(dut: object) -> None:\n    with pytest.warns(DeprecationWarning):\n        cocotb.pass_test(\"Finished test early\")\n\n\n@cocotb.test(expect_error=TypeError)\nasync def test_pass_test_in_expect_error(dut: object) -> None:\n    with pytest.warns(DeprecationWarning):\n        cocotb.pass_test(\"Finished test early\")\n\n\n@cocotb.test(expect_fail=True)\nasync def test_pass_test_in_expect_fail(dut: object) -> None:\n    with pytest.warns(DeprecationWarning):\n        cocotb.pass_test(\"Finished test early\")\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_edge_triggers.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests for edge triggers\n\n* ValueChange\n* RisingEdge\n* FallingEdge\n* ClockCycles\n\"\"\"\n\nfrom __future__ import annotations\n\nimport os\nimport re\nimport unittest.mock\n\nimport pytest\nfrom common import assert_takes\n\nimport cocotb\nfrom cocotb import simulator\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import (\n    ClockCycles,\n    FallingEdge,\n    ReadOnly,\n    RisingEdge,\n    SimTimeoutError,\n    Timer,\n    ValueChange,\n    gather,\n    select,\n    with_timeout,\n)\nfrom cocotb_tools.sim_versions import RivieraVersion\n\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\nSIM_NAME = cocotb.SIM_NAME.lower()\n\n\nasync def count_edges_cycles(signal, edges):\n    edge = RisingEdge(signal)\n    for i in range(edges):\n        await edge\n        cocotb.log.info(\"Rising edge %d detected\", i)\n    cocotb.log.info(\"Finished, returning %d\", edges)\n    return edges\n\n\nasync def do_single_edge_check(dut, level):\n    \"\"\"Do test for rising edge\"\"\"\n    old_value = dut.clk.value\n    cocotb.log.info(\"Value of %s is %d\", dut.clk._path, old_value)\n    assert old_value != level\n    if level == 1:\n        await RisingEdge(dut.clk)\n    else:\n        await FallingEdge(dut.clk)\n    assert dut.clk.value == level\n\n\n@cocotb.test()\nasync def test_rising_edge(dut):\n    \"\"\"Test that a rising edge can be awaited on\"\"\"\n    dut.clk.value = 0\n    await Timer(1, \"ns\")\n    test = cocotb.start_soon(do_single_edge_check(dut, 1))\n    await Timer(10, \"ns\")\n    dut.clk.value = 1\n    fail_timer = Timer(1000, \"ns\")\n    _, result = await select(fail_timer, test)\n    assert result is not fail_timer, \"Test timed out\"\n\n\n@cocotb.test()\nasync def test_falling_edge(dut):\n    \"\"\"Test that a falling edge can be awaited on\"\"\"\n    dut.clk.value = 1\n    await Timer(1, \"ns\")\n    test = cocotb.start_soon(do_single_edge_check(dut, 0))\n    await Timer(10, \"ns\")\n    dut.clk.value = 0\n    fail_timer = Timer(1000, \"ns\")\n    _, result = await select(fail_timer, test)\n    assert result is not fail_timer, \"Test timed out\"\n\n\n@cocotb.test()\nasync def test_either_edge(dut):\n    \"\"\"Test that either edge can be triggered on\"\"\"\n    dut.clk.value = 0\n    await Timer(1, \"ns\")\n    dut.clk.value = 1\n    await ValueChange(dut.clk)\n    assert dut.clk.value == 1\n    await Timer(10, \"ns\")\n    dut.clk.value = 0\n    await ValueChange(dut.clk)\n    assert dut.clk.value == 0\n    await Timer(10, \"ns\")\n    dut.clk.value = 1\n    await ValueChange(dut.clk)\n    assert dut.clk.value == 1\n    await Timer(10, \"ns\")\n    dut.clk.value = 0\n    await ValueChange(dut.clk)\n    assert dut.clk.value == 0\n    await Timer(10, \"ns\")\n    dut.clk.value = 1\n    await ValueChange(dut.clk)\n    assert dut.clk.value == 1\n    await Timer(10, \"ns\")\n    dut.clk.value = 0\n    await ValueChange(dut.clk)\n    assert dut.clk.value == 0\n\n\n@cocotb.test()\nasync def test_fork_and_monitor(dut, period=1000, clocks=6):\n    cocotb.start_soon(Clock(dut.clk, period, \"ns\").start())\n\n    # Ensure the clock has started\n    await RisingEdge(dut.clk)\n\n    timer = Timer(period + 10, \"ns\")\n    task = cocotb.start_soon(count_edges_cycles(dut.clk, clocks))\n    count = 0\n    expect = clocks - 1\n\n    while True:\n        _, result = await select(timer, task)\n        assert count <= expect, \"Task didn't complete in expected time\"\n        if result is timer:\n            cocotb.log.info(\"Count %d: Task still running\", count)\n            count += 1\n        else:\n            break\n    assert count == expect\n    assert result == clocks\n\n\nasync def do_clock(dut, limit, period):\n    \"\"\"Simple clock with a limit\"\"\"\n    wait_period = period / 2\n    while limit:\n        await Timer(wait_period, \"ns\")\n        dut.clk.value = 0\n        await Timer(wait_period, \"ns\")\n        dut.clk.value = 1\n        limit -= 1\n\n\nasync def do_edge_count(dut, signal):\n    \"\"\"Count the edges\"\"\"\n    global edges_seen\n    while True:\n        await RisingEdge(signal)\n        edges_seen += 1\n\n\n@cocotb.test()\nasync def test_edge_count(dut):\n    \"\"\"Count the number of edges is as expected\"\"\"\n    global edges_seen\n    edges_seen = 0\n    clk_period = 100\n    edge_count = 10\n    cocotb.start_soon(do_clock(dut, edge_count, clk_period))\n    cocotb.start_soon(do_edge_count(dut, dut.clk))\n\n    await Timer(clk_period * (edge_count + 1), \"ns\")\n    assert edge_count == edges_seen\n\n\n@cocotb.test()\nasync def test_edge_identity(dut):\n    \"\"\"\n    Test that ValueChange triggers returns the same object each time\n    \"\"\"\n\n    re = RisingEdge(dut.clk)\n    fe = FallingEdge(dut.clk)\n    e = ValueChange(dut.clk)\n\n    assert re is RisingEdge(dut.clk)\n    assert fe is FallingEdge(dut.clk)\n    assert e is ValueChange(dut.clk)\n\n    # check they are all unique\n    assert len({re, fe, e}) == 3\n    await Timer(1, \"ns\")\n\n\n@cocotb.test\nasync def test_trigger_result_type(dut) -> None:\n    \"\"\"\n    Test that the result of trigger expression have a predictable type\n    \"\"\"\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n\n    r = RisingEdge(dut.clk)\n    assert r is dut.clk.rising_edge\n    assert (await r) is r\n    assert (await dut.clk.rising_edge) is dut.clk.rising_edge\n\n    f = FallingEdge(dut.clk)\n    assert f is dut.clk.falling_edge\n    assert (await f) is f\n    assert (await dut.clk.falling_edge) is dut.clk.falling_edge\n\n    vc = ValueChange(dut.clk)\n    assert vc is dut.clk.value_change\n    assert (await vc) is vc\n    assert (await dut.clk.value_change) is dut.clk.value_change\n\n\n@cocotb.test()\nasync def test_clock_cycles(dut):\n    \"\"\"\n    Test the ClockCycles Trigger\n    \"\"\"\n    clk = dut.clk\n    period = 100\n    cycles = 10\n    cocotb.start_soon(Clock(clk, period, \"ns\").start())\n\n    # necessary to put us in a consistent state for the cycle count math below\n    await RisingEdge(clk)\n\n    t = ClockCycles(clk, cycles, RisingEdge)\n    # NVC gives upper-case identifiers for some things, so do case-insensitive match. See gh-3985\n    assert re.match(\n        r\"ClockCycles\\(sample_module.clk, 10, RisingEdge\\)\",\n        repr(t),\n        flags=re.IGNORECASE,\n    )\n    assert t.signal is clk\n    assert t.num_cycles == cycles\n    assert t.edge_type is RisingEdge\n\n    with assert_takes((cycles * period), \"ns\"):\n        await t\n\n    t = ClockCycles(clk, 10, FallingEdge)\n    # NVC gives upper-case identifiers for some things, so do case-insensitive match. See gh-3985\n    assert re.match(\n        r\"ClockCycles\\(sample_module.clk, 10, FallingEdge\\)\",\n        repr(t),\n        flags=re.IGNORECASE,\n    )\n    assert t.signal is clk\n    assert t.num_cycles == cycles\n    assert t.edge_type is FallingEdge\n\n    with assert_takes((cycles * period) - (period // 2), \"ns\"):\n        await t\n\n    # test other edge type construction\n    assert ClockCycles(clk, cycles, True).edge_type is RisingEdge\n    assert ClockCycles(clk, cycles, False).edge_type is FallingEdge\n    assert ClockCycles(clk, cycles, edge_type=ValueChange).edge_type is ValueChange\n    assert ClockCycles(clk, cycles, rising=True).edge_type is RisingEdge\n    assert ClockCycles(clk, cycles, rising=False).edge_type is FallingEdge\n    assert ClockCycles(clk, cycles).edge_type is RisingEdge  # default\n\n    # bad construction calls\n    with pytest.raises(TypeError):\n        ClockCycles(clk, cycles, True, edge_type=RisingEdge)\n    with pytest.raises(TypeError):\n        ClockCycles(clk, cycles, True, rising=True)\n    with pytest.raises(TypeError):\n        ClockCycles(clk, cycles, rising=True, edge_type=RisingEdge)\n    with pytest.raises(TypeError):\n        ClockCycles(clk, cycles, ValueChange, rising=True, edge_type=RisingEdge)\n\n\n@cocotb.test()\nasync def test_clock_cycles_forked(dut):\n    \"\"\"Test that ClockCycles can be used in forked coroutines\"\"\"\n    # gh-520\n\n    cocotb.start_soon(Clock(dut.clk, 100, \"ns\").start())\n\n    async def wait_ten():\n        await ClockCycles(dut.clk, 10)\n\n    a = cocotb.start_soon(wait_ten())\n    b = cocotb.start_soon(wait_ten())\n    await a\n    await b\n\n\n@cocotb.test(\n    timeout_time=100,\n    timeout_unit=\"ns\",\n    expect_error=(  # gh-2344\n        SimTimeoutError\n        if (\n            LANGUAGE in [\"verilog\"]\n            and SIM_NAME.startswith((\"riviera\", \"aldec\"))\n            and RivieraVersion(cocotb.SIM_VERSION) < RivieraVersion(\"2023.04\")\n        )\n        else ()\n    ),\n)\nasync def test_both_edge_triggers(dut):\n    async def wait_rising_edge():\n        await RisingEdge(dut.clk)\n\n    async def wait_falling_edge():\n        await FallingEdge(dut.clk)\n\n    rising_coro = cocotb.start_soon(wait_rising_edge())\n    falling_coro = cocotb.start_soon(wait_falling_edge())\n    cocotb.start_soon(Clock(dut.clk, 10, unit=\"ns\").start())\n    await gather(rising_coro, falling_coro)\n\n\n@cocotb.test()\nasync def test_edge_on_vector(dut):\n    \"\"\"Test that ValueChange() triggers on any 0/1 change in a vector\"\"\"\n\n    cocotb.start_soon(Clock(dut.clk, 100, \"ns\").start())\n\n    edge_cnt = 0\n\n    async def wait_edge():\n        nonlocal edge_cnt\n        while True:\n            await ValueChange(dut.stream_out_data_registered)\n            if SIM_NAME.startswith(\"modelsim\"):\n                await ReadOnly()  # not needed for other simulators\n            edge_cnt = edge_cnt + 1\n\n    dut.stream_in_data.value = 0\n    await RisingEdge(dut.clk)\n    await RisingEdge(dut.clk)\n\n    cocotb.start_soon(wait_edge())\n\n    for val in range(1, 2 ** len(dut.stream_in_data) - 1):\n        # produce an edge by setting a value != 0:\n        dut.stream_in_data.value = val\n        await RisingEdge(dut.clk)\n        # set back to all-0:\n        dut.stream_in_data.value = 0\n        await RisingEdge(dut.clk)\n\n    # We have to wait because we don't know the scheduling order of the above\n    # ValueChange(dut.stream_out_data_registered) and the above RisingEdge(dut.clk)\n    # ValueChange(dut.stream_out_data_registered) should occur strictly after RisingEdge(dut.clk),\n    # but NVC and Verilator behave differently.\n    await RisingEdge(dut.clk)\n\n    expected_count = 2 * ((2 ** len(dut.stream_in_data) - 1) - 1)\n\n    assert edge_cnt == expected_count\n\n\n@cocotb.test()\nasync def test_edge_bad_handles(dut):\n    with pytest.raises(TypeError):\n        RisingEdge(dut)\n\n    with pytest.raises(TypeError):\n        FallingEdge(dut)\n\n    with pytest.raises(TypeError):\n        ValueChange(dut)\n\n    with pytest.raises(TypeError):\n        RisingEdge(dut.stream_in_data)\n\n    with pytest.raises(TypeError):\n        FallingEdge(dut.stream_in_data)\n\n\n@cocotb.test()\nasync def test_edge_logic_vector(dut):\n    dut.stream_in_data.value = 0\n\n    async def change_stream_in_data():\n        await Timer(10, \"ns\")\n        dut.stream_in_data.value = 10\n\n    cocotb.start_soon(change_stream_in_data())\n\n    await with_timeout(ValueChange(dut.stream_in_data), 20, \"ns\")\n\n\n# icarus doesn't support integer inputs/outputs\n@cocotb.test(skip=SIM_NAME.startswith(\"icarus\"))\nasync def test_edge_non_logic_handles(dut):\n    dut.stream_in_int.value = 0\n\n    async def change_stream_in_int():\n        await Timer(10, \"ns\")\n        dut.stream_in_int.value = 10\n\n    cocotb.start_soon(change_stream_in_int())\n\n    await with_timeout(ValueChange(dut.stream_in_int), 20, \"ns\")\n\n\n@cocotb.test\nasync def test_edge_trigger_repr(dut) -> None:\n    e = ValueChange(dut.clk)\n    # NVC gives upper-case identifiers for some things, so do case-insensitive match. See gh-3985\n    assert re.match(\n        r\"ValueChange\\(LogicObject\\(sample_module\\.clk\\)\\)\",\n        repr(e),\n        flags=re.IGNORECASE,\n    )\n    f = RisingEdge(dut.stream_in_ready)\n    assert re.match(\n        r\"RisingEdge\\(LogicObject\\(sample_module\\.stream_in_ready\\)\\)\",\n        repr(f),\n        flags=re.IGNORECASE,\n    )\n    g = FallingEdge(dut.stream_in_valid)\n    assert re.match(\n        r\"FallingEdge\\(LogicObject\\(sample_module\\.stream_in_valid\\)\\)\",\n        repr(g),\n        flags=re.IGNORECASE,\n    )\n\n\nasync def test_edge_trigger_on_const(dut) -> None:\n    \"\"\"Test failure if getting Edge trigger on const signal.\"\"\"\n    with pytest.raises(TypeError):\n        RisingEdge(dut.INT_PARAM)\n    with pytest.raises(TypeError):\n        FallingEdge(dut.INT_PARAM)\n    with pytest.raises(TypeError):\n        ValueChange(dut.INT_PARAM)\n    with pytest.raises(TypeError):\n        dut.INT_PARAM.value_change\n\n\nasync def wait_for_edge(signal):\n    for _ in range(10):\n        await ValueChange(signal)\n\n\nasync def wait_for_rising_edge(signal):\n    for _ in range(10):\n        await RisingEdge(signal)\n\n\nasync def wait_for_falling_edge(signal):\n    for _ in range(10):\n        await FallingEdge(signal)\n\n\n@cocotb.test\nasync def issue_376_all_edges(dut):\n    Clock(dut.clk, 2500).start()\n    cocotb.start_soon(wait_for_edge(dut.clk))\n    cocotb.start_soon(wait_for_rising_edge(dut.clk))\n    await cocotb.start_soon(wait_for_falling_edge(dut.clk))\n\n\n@cocotb.test()\nasync def issue_376_same_edges(dut):\n    Clock(dut.clk, 2500).start()\n    cocotb.start_soon(wait_for_rising_edge(dut.clk))\n    await cocotb.start_soon(wait_for_rising_edge(dut.clk))\n\n\n@cocotb.test()\nasync def issue_376_different_edges(dut):\n    Clock(dut.clk, 2500).start()\n    cocotb.start_soon(wait_for_rising_edge(dut.clk))\n    await cocotb.start_soon(wait_for_falling_edge(dut.clk))\n\n\n@cocotb.test()\nasync def test_callback_registration_failure_raises_runtime_error(dut):\n    \"\"\"Regression test for gh-5439: callback registration failure\n    should raise RuntimeError, not crash.\"\"\"\n    # Create a fresh trigger (not the cached dut.clk.rising_edge) so that\n    # the corrupted state from the mock doesn't affect subsequent tests.\n    trigger = RisingEdge._make(dut.clk)\n\n    with unittest.mock.patch.object(\n        simulator,\n        \"register_value_change_callback\",\n        return_value=None,\n    ):\n        with pytest.raises(RuntimeError, match=\"Unable set up .* Trigger\"):\n            await trigger\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_first_combine.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests for concurrency primitives like First and Combine\n\"\"\"\n\nfrom __future__ import annotations\n\nimport re\nfrom collections import deque\nfrom random import randint\nfrom typing import Any\n\nimport pytest\nfrom common import MyException, _check_traceback, assert_takes\n\nimport cocotb\nfrom cocotb.task import Task\nfrom cocotb.triggers import Combine, Event, First, Timer, Trigger\n\n\nclass MyTrigger(Trigger):\n    def __init__(self) -> None:\n        super().__init__()\n        self.primed = 0\n        self.unprimed = 0\n\n    def _prime(self) -> None:\n        self.primed += 1\n\n    def _unprime(self) -> None:\n        self.unprimed += 1\n\n\n@cocotb.test\nasync def test_First_unfired_triggers_killed(_) -> None:\n    \"\"\"Test that un-fired trigger(s) in First don't later cause a spurious wakeup.\"\"\"\n\n    triggers = [MyTrigger() for _ in range(3)]\n\n    timer = Timer(1, \"ns\")\n    res = await First(timer, *triggers)\n    assert res is timer\n\n    for t in triggers:\n        assert t.primed == 1\n        assert t.unprimed == 1\n\n\n@cocotb.test\nasync def test_First_unfired_triggers_killed_on_exception(_) -> None:\n    \"\"\"Test that un-fired trigger(s) in First after exception don't later cause a spurious wakeup.\"\"\"\n\n    triggers = [MyTrigger() for _ in range(3)]\n\n    async def fails() -> None:\n        raise ValueError(\"I am a failure\")\n\n    with pytest.raises(ValueError), pytest.warns(DeprecationWarning):\n        await First(cocotb.start_soon(Task(fails())), *triggers)\n\n    for t in triggers:\n        assert t.primed == 1\n        assert t.unprimed == 1\n\n\n@cocotb.test\nasync def test_Combine_unfired_triggers_killed_on_exception(_) -> None:\n    \"\"\"Test that un-fired trigger(s) in Combine after exception don't later cause a spurious wakeup.\"\"\"\n\n    triggers = [MyTrigger() for _ in range(3)]\n\n    async def fails() -> None:\n        raise ValueError(\"I am a failure\")\n\n    with pytest.raises(ValueError), pytest.warns(DeprecationWarning):\n        await Combine(cocotb.start_soon(Task(fails())), *triggers)\n\n    for t in triggers:\n        assert t.primed == 1\n        assert t.unprimed == 1\n\n\n@cocotb.test()\nasync def test_nested_first(dut):\n    \"\"\"Test that nested First triggers behave as expected\"\"\"\n    events = [Event() for i in range(3)]\n    waiters = [e.wait() for e in events]\n\n    async def fire_events():\n        \"\"\"fire the events in order\"\"\"\n        for e in events:\n            await Timer(1, \"ns\")\n            e.set()\n\n    async def wait_for_nested_first():\n        inner_first = First(waiters[0], waiters[1])\n        ret = await First(inner_first, waiters[2])\n\n        # should unpack completely, rather than just by one level\n        assert ret is not inner_first\n        assert ret is waiters[0]\n\n    fire_task = cocotb.start_soon(fire_events())\n    await wait_for_nested_first()\n    await fire_task\n\n\n@cocotb.test()\nasync def test_first_does_not_kill(dut):\n    \"\"\"Test that `First` does not kill coroutines that did not finish first\"\"\"\n    ran = False\n\n    async def coro():\n        nonlocal ran\n        await Timer(2, unit=\"ns\")\n        ran = True\n\n    # Coroutine runs for 2ns, so we expect the timer to fire first\n    timer = Timer(1, unit=\"ns\")\n    with pytest.warns(DeprecationWarning):\n        t = await First(timer, cocotb.start_soon(coro()))\n    assert t is timer\n    assert not ran\n\n    # the background routine is still running, but should finish after 1ns\n    await Timer(2, unit=\"ns\")\n\n    assert ran\n\n\n@cocotb.test()\nasync def test_exceptions_first(dut):\n    \"\"\"Test exception propagation via cocotb.triggers.First\"\"\"\n\n    async def raise_inner():\n        await Timer(10, \"ns\")\n        raise ValueError(\"It is soon now\")\n\n    async def raise_soon():\n        await Timer(1, \"ns\")\n        with pytest.warns(DeprecationWarning):\n            await First(cocotb.start_soon(raise_inner()))\n\n    await _check_traceback(\n        raise_soon(), ValueError, r\".*in raise_soon.*in raise_inner\", re.DOTALL\n    )\n\n\n@cocotb.test()\nasync def test_combine(dut):\n    \"\"\"Test the Combine trigger.\"\"\"\n    # gh-852\n\n    async def coro(delay):\n        await Timer(delay, \"ns\")\n\n    tasks = [cocotb.start_soon(coro(dly)) for dly in [10, 30, 20]]\n\n    with pytest.warns(DeprecationWarning):\n        await Combine(*tasks)\n\n\n@cocotb.test()\nasync def test_fork_combine(dut):\n    \"\"\"Test the Combine trigger with forked coroutines.\"\"\"\n    # gh-852\n\n    async def coro(delay):\n        await Timer(delay, \"ns\")\n\n    tasks = [cocotb.start_soon(coro(dly)) for dly in [10, 30, 20]]\n\n    with pytest.warns(DeprecationWarning):\n        await Combine(*tasks)\n\n\n@cocotb.test()\nasync def test_event_is_set(dut):\n    e = Event()\n\n    assert not e.is_set()\n    e.set()\n    assert e.is_set()\n    e.clear()\n    assert not e.is_set()\n\n\n@cocotb.test()\nasync def test_combine_start_soon(_):\n    async def coro(delay):\n        await Timer(delay, \"ns\")\n\n    max_delay = 10\n\n    tasks = [cocotb.start_soon(coro(d)) for d in range(1, max_delay + 1)]\n\n    with assert_takes(max_delay, \"ns\"), pytest.warns(DeprecationWarning):\n        await Combine(*tasks)\n\n\n@cocotb.test()\nasync def test_recursive_combine_and_start_soon(_):\n    \"\"\"Test using `Combine` on forked coroutines that themselves use `Combine`.\"\"\"\n\n    async def mergesort(n):\n        if len(n) == 1:\n            return n\n        part1 = n[: len(n) // 2]\n        part2 = n[len(n) // 2 :]\n        sort1 = cocotb.start_soon(mergesort(part1))\n        sort2 = cocotb.start_soon(mergesort(part2))\n        with pytest.warns(DeprecationWarning):\n            await Combine(sort1, sort2)\n        res1 = deque(sort1.result())\n        res2 = deque(sort2.result())\n        res = []\n        while res1 and res2:\n            if res1[0] < res2[0]:\n                res.append(res1.popleft())\n            else:\n                res.append(res2.popleft())\n        res.extend(res1)\n        res.extend(res2)\n        return res\n\n    t = [randint(0, 1000) for _ in range(100)]\n    res = await mergesort(t)\n    t.sort()\n    assert t == res\n\n\n@cocotb.test()\nasync def test_recursive_combine(_):\n    \"\"\"Test passing a `Combine` trigger directly to another `Combine` trigger.\"\"\"\n\n    done = set()\n\n    async def waiter(N):\n        await Timer(N, \"ns\")\n        done.add(N)\n\n    with assert_takes(30, \"ns\"):\n        with pytest.warns(DeprecationWarning):\n            await Combine(\n                Combine(cocotb.start_soon(waiter(10)), cocotb.start_soon(waiter(20))),\n                cocotb.start_soon(waiter(30)),\n            )\n    assert done == {10, 20, 30}\n\n\nclass MyEvent(Event):\n    pass\n\n\n@cocotb.test\nasync def test_concurrency_trigger_repr(_):\n    e = Event()\n    assert re.match(r\"<Event at \\w+>\", repr(e))\n\n    e = MyEvent()\n    assert re.match(r\"<MyEvent at \\w+>\", repr(e))\n    w = e.wait()\n    assert re.match(r\"<<MyEvent at \\w+>\\.wait\\(\\) at \\w+>\", repr(w))\n\n\n@cocotb.test()\nasync def test_invalid_trigger_types(dut):\n    o = object()\n\n    with pytest.raises(TypeError):\n        await First(Timer(1), o)\n\n    with pytest.raises(TypeError):\n        await Combine(Timer(1), o)\n\n\n@cocotb.test\nasync def test_Combine_empty(_) -> None:\n    \"\"\"Test that a Combine with no triggers passes no time.\"\"\"\n    combine = Combine()\n    with assert_takes(0, \"ns\"):\n        res = await combine\n    assert res is combine\n\n\n@cocotb.test\nasync def test_Combine_single(_) -> None:\n    \"\"\"Test Combine with a single trigger acts the same as awaiting the trigger directly.\"\"\"\n    combine = Combine(Timer(9, \"ns\"))\n    with assert_takes(9, \"ns\"):\n        res = await combine\n    assert res is combine\n\n\n@cocotb.test(timeout_time=10, timeout_unit=\"ns\")\nasync def test_Combine_exception(dut) -> None:\n    \"\"\"Test Combine with exception ends immediately and isn't blocked by unfired triggers.\"\"\"\n\n    e = Event()  # we never plan on setting this\n\n    async def raises_after_1ns():\n        await Timer(1, \"ns\")\n        raise MyException\n\n    with pytest.warns(DeprecationWarning):\n        combine = Combine(\n            cocotb.start_soon(raises_after_1ns()), Timer(10, \"ns\"), e.wait()\n        )\n    with assert_takes(1, \"ns\"), pytest.raises(MyException):\n        await combine\n\n\n@cocotb.test\nasync def test_First_empty(_) -> None:\n    \"\"\"Test that a First with no triggers raises an error.\"\"\"\n    with pytest.raises(ValueError):\n        await First()\n\n\n@cocotb.test\nasync def test_First_single(_) -> None:\n    \"\"\"Test First with a single trigger acts the same as awaiting the trigger directly.\"\"\"\n    timer = Timer(13, \"ns\")\n    with assert_takes(13, \"ns\"):\n        res = await First(timer)\n    assert res is timer\n\n\n@cocotb.test(timeout_time=10, timeout_unit=\"ns\")\nasync def test_First_exception(_) -> None:\n    \"\"\"Test First with exception ends immediately and isn't blocked by unfired triggers.\"\"\"\n\n    e = Event()  # we never plan on setting this\n\n    async def raises_after_1ns():\n        await Timer(1, \"ns\")\n        raise MyException\n\n    with pytest.warns(DeprecationWarning):\n        first = First(cocotb.start_soon(raises_after_1ns()), Timer(10, \"ns\"), e.wait())\n    with assert_takes(1, \"ns\"), pytest.raises(MyException):\n        await first\n\n\n@cocotb.test\nasync def test_Combine_objects_shared_by_multiple(_: Any) -> None:\n    \"\"\"Test waiting for the same objects in multiple concurrent Combines.\"\"\"\n    count = 0\n    events = [Event() for _ in range(5)]\n\n    async def wait_for_all_events():\n        nonlocal count\n        await Combine(*(event.wait() for event in events))\n        count += 1\n\n    waiters = [cocotb.start_soon(wait_for_all_events()) for _ in range(5)]\n    for e in events:\n        e.set()\n    with pytest.warns(DeprecationWarning):\n        await Combine(*waiters)\n    assert count == 5\n\n\n@cocotb.test\nasync def test_Combine_task_cancelled(_: Any) -> None:\n    \"\"\"Test that cancelling a Task waiting on a Combine cleans waiter tasks.\"\"\"\n\n    triggers = [MyTrigger() for _ in range(5)]\n\n    async def waiter() -> None:\n        await Combine(*triggers)\n\n    task = cocotb.start_soon(waiter())\n    await Timer(1, \"ns\")\n    for t in triggers:\n        assert t.primed == 1\n    for t in triggers:\n        assert t.unprimed == 0\n    task.cancel()\n    await Timer(1, \"ns\")\n    for t in triggers:\n        assert t.primed == 1\n    for t in triggers:\n        assert t.unprimed == 1\n\n\n@cocotb.test\nasync def test_First_task_cancelled(_: Any) -> None:\n    \"\"\"Test that cancelling a Task waiting on a First cleans waiter tasks.\"\"\"\n\n    triggers = [MyTrigger() for _ in range(5)]\n\n    async def waiter() -> None:\n        await First(*triggers)\n\n    task = cocotb.start_soon(waiter())\n    await Timer(1, \"ns\")\n    for t in triggers:\n        assert t.primed == 1\n    for t in triggers:\n        assert t.unprimed == 0\n    task.cancel()\n    await Timer(1, \"ns\")\n    for t in triggers:\n        assert t.primed == 1\n    for t in triggers:\n        assert t.unprimed == 1\n\n\n@cocotb.test\nasync def test_Combine_task_being_waited_cancelled(_: Any) -> None:\n    \"\"\"Test cancelling a Task being awaited by a Combine causes it to finish.\"\"\"\n    e = Event()\n\n    async def wait_forever() -> None:\n        await e.wait()\n\n    tasks = [cocotb.start_soon(wait_forever()) for _ in range(5)]\n\n    async def wait_on_tasks() -> None:\n        with pytest.warns(DeprecationWarning):\n            await Combine(*tasks)\n\n    waiter_task = cocotb.start_soon(wait_on_tasks())\n    await Timer(1, \"ns\")\n\n    # cancel just one task\n    tasks[0].cancel()\n\n    # check other tasks haven't been cancelled and the Combine isn't finished.\n    await Timer(1, \"ns\")\n    assert not waiter_task.done()\n    for t in tasks[1:]:\n        assert not t.done()\n\n    # cancel remaining tasks\n    for t in tasks[1:]:\n        t.cancel()\n\n    # see if that finishes the Combine\n    await Timer(1, \"ns\")\n    assert waiter_task.done()\n\n\n@cocotb.test\nasync def test_First_task_being_waited_cancelled(_: Any) -> None:\n    \"\"\"Test cancelling a Task being awaited by a First causes it to finish.\"\"\"\n    e = Event()\n\n    async def wait_forever() -> None:\n        await e.wait()\n\n    tasks = [cocotb.start_soon(wait_forever()) for _ in range(5)]\n\n    async def wait_on_tasks() -> None:\n        with pytest.warns(DeprecationWarning):\n            await First(*tasks)\n\n    waiter_task = cocotb.start_soon(wait_on_tasks())\n    await Timer(1, \"ns\")\n\n    # cancel just one task\n    tasks[0].cancel()\n\n    # check other tasks have been cancelled and the Combine is finished.\n    await Timer(1, \"ns\")\n    assert waiter_task.done()\n    for t in tasks[1:]:\n        assert not t.done()\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_handle.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests for handles\n\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\nimport os\nimport pickle\nimport random\nfrom typing import Any\n\nimport pytest\n\nimport cocotb\nimport cocotb.clock\nimport cocotb.triggers\nfrom cocotb.handle import Immediate, StringObject\nfrom cocotb.triggers import FallingEdge, Timer, ValueChange\nfrom cocotb.types import Logic, LogicArray\nfrom cocotb_tools.sim_versions import RivieraVersion\n\nSIM_NAME = cocotb.SIM_NAME.lower()\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\nSIM_VERSION = cocotb.SIM_VERSION\n\nriviera_before_2025_04 = SIM_NAME.startswith(\"riviera\") and RivieraVersion(\n    SIM_VERSION\n) < RivieraVersion(\"2025.04\")\n\n\n@cocotb.test()\nasync def test_bad_attr(dut):\n    with pytest.raises(AttributeError):\n        dut.fake_signal\n\n    try:\n        _ = dut.stream_in_data.whoops\n    except AttributeError as e:\n        assert \"whoops\" in str(e)\n    else:\n        assert False, \"Expected AttributeError\"\n\n\n@cocotb.xfail(\n    SIM_NAME.startswith(\"icarus\"),\n    raises=AttributeError,\n    reason=\"iverilog fails to discover string inputs (gh-2585)\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"ghdl\"),\n    reason=\"GHDL fails to discover string input properly (gh-2584)\",\n)\n@cocotb.test\nasync def test_string_handle_takes_bytes(dut):\n    assert isinstance(dut.stream_in_string, StringObject)\n    dut.stream_in_string.value = b\"bytes\"\n    await cocotb.triggers.Timer(10, \"ns\")\n    val = dut.stream_in_string.value\n    assert isinstance(val, bytes)\n    assert val == b\"bytes\"\n\n\n@cocotb.skipif(\n    LANGUAGE in [\"verilog\"] and SIM_NAME.startswith(\"riviera\"),\n    reason=\"Riviera is unhappy for an unknown reason\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"icarus\"),\n    raises=AttributeError,\n    reason=\"iverilog fails to discover string inputs (gh-2585)\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"ghdl\"),\n    reason=\"GHDL fails to discover string input properly (gh-2584)\",\n)\nasync def test_string_ansi_color(dut):\n    \"\"\"Check how different simulators treat ANSI-colored strings, see gh-2328\"\"\"\n    assert isinstance(dut.stream_in_string, StringObject)\n    teststr = \"\\x1b[33myellow\\x1b[49m\\x1b[39m\"\n    asciival_sum = sum(ord(char) for char in teststr)\n    await cocotb.triggers.Timer(10, \"ns\")\n    dut.stream_in_string.value = bytes(teststr.encode(\"ascii\"))\n    await cocotb.triggers.Timer(10, \"ns\")\n    val = dut.stream_in_string.value\n    assert isinstance(val, bytes)\n    if LANGUAGE in [\"vhdl\"] and SIM_NAME.startswith(\"riviera\"):\n        # Riviera-PRO doesn't return anything with VHDL:\n        assert val == b\"\"\n        # ...and the value shows up differently in the HDL:\n        assert dut.stream_in_string_asciival_sum.value == sum(\n            ord(char) for char in teststr.replace(\"\\x1b\", \"\\0\")\n        )\n    elif LANGUAGE in [\"verilog\"] and SIM_NAME.startswith((\"ncsim\", \"xmsim\")):\n        # Xcelium with VPI strips the escape char when reading:\n        assert val == bytes(teststr.replace(\"\\x1b\", \"\").encode(\"ascii\"))\n        # the HDL gets the correct value though:\n        assert dut.stream_in_string_asciival_sum.value == asciival_sum\n    else:\n        assert val == bytes(teststr.encode(\"ascii\"))\n        assert dut.stream_in_string_asciival_sum.value == asciival_sum\n\n\n@cocotb.test\nasync def test_delayed_assignment_still_errors(dut):\n    \"\"\"Writing a bad value should fail even if the write is scheduled to happen later\"\"\"\n\n    with pytest.raises(ValueError):\n        dut.stream_in_data.value = Immediate(\"1010 not a real binary string\")\n    with pytest.raises(TypeError):\n        dut.stream_in_data.value = Immediate([])\n\n    with pytest.raises(ValueError):\n        dut.stream_in_data.value = \"1010 not a real binary string\"\n    with pytest.raises(TypeError):\n        dut.stream_in_data.value = []\n\n\n@cocotb.xfail(\n    SIM_NAME.startswith(\"icarus\"),\n    raises=AttributeError,\n    reason=\"iverilog unable to find real signals (gh-2590)\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"ghdl\"),\n    raises=AttributeError,\n    reason=\"GHDL unable to find real signals (gh-2589)\",\n)\n@cocotb.test\nasync def test_real_assign_double(dut):\n    \"\"\"\n    Assign a random floating point value, read it back from the DUT and check\n    it matches what we assigned\n    \"\"\"\n    val = random.uniform(-1e307, 1e307)\n    log = logging.getLogger(\"cocotb.test\")\n    timer_shortest = Timer(1, \"step\")\n    await timer_shortest\n    log.info(\"Setting the value %g\", val)\n    dut.stream_in_real.value = val\n    await timer_shortest\n    await timer_shortest  # FIXME: Workaround for VHPI scheduling - needs investigation\n    got = dut.stream_out_real.value\n    log.info(\"Read back value %g\", got)\n    assert got == val, \"Values didn't match!\"\n\n\n@cocotb.xfail(\n    SIM_NAME.startswith(\"icarus\"),\n    raises=AttributeError,\n    reason=\"iverilog unable to find real signals (gh-2590)\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"ghdl\"),\n    raises=AttributeError,\n    reason=\"GHDL unable to find real signals (gh-2589)\",\n)\n@cocotb.test\nasync def test_real_assign_int(dut):\n    \"\"\"Assign a random integer value to ensure we can write types convertible to\n    int, read it back from the DUT and check it matches what we assigned.\n    \"\"\"\n    val = random.randint(-(2**31), 2**31 - 1)\n    log = logging.getLogger(\"cocotb.test\")\n    timer_shortest = Timer(1, \"step\")\n    await timer_shortest\n    log.info(\"Setting the value %i\", val)\n    dut.stream_in_real.value = val\n    await timer_shortest\n    await timer_shortest  # FIXME: Workaround for VHPI scheduling - needs investigation\n    got = dut.stream_out_real.value\n    log.info(\"Read back value %d\", got)\n    assert got == val, \"Values didn't match!\"\n\n\n@cocotb.skipif(\n    LANGUAGE == \"vhdl\", reason=\"identifiers starting with `_` are illegal in VHDL\"\n)\n@cocotb.test\nasync def test_access_underscore_name(dut):\n    \"\"\"Test accessing HDL name starting with an underscore\"\"\"\n    # direct access does not work because we consider such names cocotb-internal\n    with pytest.raises(AttributeError):\n        dut._underscore_name\n\n    # indirect access works\n    dut[\"_underscore_name\"].value = 0\n    await Timer(1, \"ns\")\n    assert dut[\"_underscore_name\"].value == 0\n    dut[\"_underscore_name\"].value = 1\n    await Timer(1, \"ns\")\n    assert dut[\"_underscore_name\"].value == 1\n    dut[\"_underscore_name\"].value = 0\n    await Timer(1, \"ns\")\n    assert dut[\"_underscore_name\"].value == 0\n\n\n@cocotb.test()\nasync def test_assign_LogicArray(dut):\n    value = LogicArray(dut.stream_in_data.value)\n    value &= LogicArray(\"0x1X011z\")\n    dut.stream_in_data.value = value\n    with pytest.raises(ValueError):\n        dut.stream_in_data.value = LogicArray(\"010\")  # not the correct size\n\n\n@cocotb.xfail(\n    SIM_NAME.startswith(\"verilator\"),\n    reason=\"verilator does not support 4-state signals\",\n)\n@cocotb.test\nasync def test_assign_Logic(dut):\n    dut.stream_in_ready.value = Logic(\"X\")\n    await Timer(1, \"ns\")\n    assert dut.stream_in_ready.value == \"x\"\n    with pytest.raises(ValueError):\n        dut.stream_in_data.value = Logic(\"U\")  # not the correct size\n\n\n@cocotb.skipif(\n    LANGUAGE != \"verilog\" and not SIM_NAME.startswith(\"ghdl\"),\n    reason=\"For testing Verilog simulators, or GHDL which uses VPI\",\n)\n@cocotb.skipif(\n    SIM_NAME.startswith(\"verilator\"), reason=\"Verilator only supports 2-state values.\"\n)\n@cocotb.test\nasync def test_assign_Logic_4value(dut):\n    for value in [\"X\", \"0\", \"1\", \"Z\"]:\n        dut.stream_in_ready.value = Logic(value)\n        await Timer(1, \"ns\")\n        assert dut.stream_in_ready.value == value\n\n\n@cocotb.skipif(LANGUAGE != \"vhdl\", reason=\"For testing VHDL simulators.\")\n@cocotb.skipif(SIM_NAME.startswith(\"ghdl\"), reason=\"GHDL only supports 4-state values.\")\n@cocotb.test\nasync def test_assign_Logic_9value(dut):\n    for value in [\"U\", \"X\", \"0\", \"1\", \"Z\", \"W\", \"L\", \"H\", \"-\"]:\n        dut.stream_in_ready.value = Logic(value)\n        await Timer(1, \"ns\")\n        assert dut.stream_in_ready.value == value\n\n\n@cocotb.skipif(LANGUAGE != \"vhdl\", reason=\"For testing VHDL simulators.\")\n@cocotb.skipif(SIM_NAME.startswith(\"ghdl\"), reason=\"GHDL only supports 4-state values.\")\n@cocotb.test\nasync def test_assign_LogicArray_9value(dut):\n    # Reset to zero.\n    dut.stream_in_data.value = LogicArray(0, 8)\n    await Timer(1, \"ns\")\n    assert dut.stream_in_data.value == 0\n\n    # Write 8 values (except 0) and check.\n    dut.stream_in_data.value = LogicArray(\"UX1ZWLH-\")\n    await Timer(1, \"ns\")\n    assert dut.stream_in_data.value == LogicArray(\"UX1ZWLH-\")\n\n\n@cocotb.test\nasync def test_assign_string(dut):\n    assert len(dut.stream_in_data) == 8\n    cocotb.log.info(\"dut.stream_in_data type is %s\", dut.stream_in_data._type)\n    dut.stream_in_data.value = \"10101010\"\n    await Timer(1, \"ns\")\n    assert dut.stream_in_data.value == \"10101010\"\n    with pytest.raises(ValueError):\n        dut.stream_in_data.value = \"XXX\"  # not the correct size\n    with pytest.raises(ValueError):\n        dut.stream_in_data.value = \"lol\"  # not the correct values\n    await Timer(1, \"ns\")\n    assert dut.stream_in_data.value == \"10101010\"\n\n\n@cocotb.skipif(LANGUAGE == \"vhdl\", reason=\"VHDL does not support immediate assignment.\")\n@cocotb.test\nasync def test_assign_immediate(dut):\n    dut.mybits_uninitialized.value = Immediate(2)\n    assert dut.mybits_uninitialized.value == 2\n\n    dut.mybits_uninitialized.value = Immediate(\"01\")\n    assert dut.mybits_uninitialized.value == \"01\"\n\n    dut.mybits_uninitialized.value = Immediate(LogicArray(\"11\"))\n    assert dut.mybits_uninitialized.value == LogicArray(\"11\")\n\n\n@cocotb.skipif(LANGUAGE == \"vhdl\", reason=\"VHDL does not support immediate assignment.\")\n@cocotb.test\nasync def test_immediate_reentrace(dut):\n    dut.mybits_uninitialized.value = 0\n    await Timer(1, \"ns\")\n    seen = 0\n\n    async def nested_watch():\n        await FallingEdge(dut.mybit)\n        raise RuntimeError(\"Should have been cancelled\")\n\n    nested = cocotb.start_soon(nested_watch())\n\n    async def watch():\n        nonlocal seen, nested\n        await ValueChange(dut.mybits_uninitialized)\n        seen += 1\n        dut.mybit.value = Immediate(0)\n        nested.cancel()\n\n    cocotb.start_soon(watch())\n    await Timer(1, \"ns\")\n\n    dut.mybits_uninitialized.value = Immediate(2)\n    await Timer(1, \"ns\")\n    assert seen == 1\n\n\n@cocotb.xfail(\n    SIM_NAME.startswith(\"ghdl\"),\n    reason=\"GHDL uses the VPI, which does not have a way to infer null ranges.\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"modelsim\")\n    and os.getenv(\"VHDL_GPI_INTERFACE\", \"fli\") == \"vhpi\",\n    reason=\"Questa's implementation of the VHPI sets vhpiIsUpP incorrectly\",\n)\n@cocotb.test\nasync def test_null_range_width(dut):\n    # Normal arrays should have the same length regardless of language\n    assert len(dut.array_7_downto_4) == 4\n    if LANGUAGE in [\"vhdl\"]:\n        # But in VHDL, `4 downto 7` should result in a null range\n        assert len(dut.array_4_downto_7) == 0\n    else:\n        # Not so in (System)Verilog though\n        assert len(dut.array_4_downto_7) == 4\n\n\n@cocotb.test\nasync def test_assign_str_logic_scalar(dut) -> None:\n    dut.stream_in_valid.value = 1\n    await Timer(1, \"ns\")\n    assert dut.stream_in_valid.value == \"1\"\n\n    dut.stream_in_valid.value = \"0\"\n    await Timer(1, \"ns\")\n    assert dut.stream_in_valid.value == \"0\"\n\n    dut.stream_in_valid.value = Logic(\"1\")\n    await Timer(1, \"ns\")\n    assert dut.stream_in_valid.value == \"1\"\n\n    dut.stream_in_valid.value = LogicArray(\"0\")\n    await Timer(1, \"ns\")\n    assert dut.stream_in_valid.value == \"0\"\n\n    with pytest.raises(TypeError):\n        dut.stream_in_valid.value = (1, 0)  # not the correct type\n\n    with pytest.raises(ValueError):\n        dut.stream_in_valid.value = LogicArray(\"0101\")  # too long\n\n    with pytest.raises(ValueError):\n        dut.stream_in_valid.value = \"1010\"  # too long\n\n    # Veirlator doesn't support 4-state signals\n    if not SIM_NAME.startswith(\"verilator\"):\n        dut.stream_in_valid.value = \"Z\"\n        await Timer(1, \"ns\")\n        assert dut.stream_in_valid.value == \"Z\"\n\n    if LANGUAGE in [\"vhdl\"]:\n        dut.stream_in_valid.value = \"H\"\n        await Timer(1, \"ns\")\n        assert dut.stream_in_valid.value == \"H\"\n\n\n@cocotb.test\nasync def test_extended_identifiers(dut):\n    if LANGUAGE == \"vhdl\":\n        names = [\n            \"\\\\weird.signal(1)\\\\\",\n            \"\\\\weird.signal(2)\\\\\",\n            \"\\\\(.*|this looks like a regex)\\\\\",\n        ]\n    elif SIM_NAME.startswith(\"icarus\"):\n        # Icarus normalizes extended identifier names to not include the\n        # preceding \\ or the trailing space\n        names = [\n            \"weird.signal[1]\",\n            \"weird.signal[2]\",\n            \"(.*|this_looks_like_a_regex)\",\n        ]\n    else:\n        names = [\n            \"\\\\weird.signal[1] \",\n            \"\\\\weird.signal[2] \",\n            \"\\\\(.*|this_looks_like_a_regex) \",\n        ]\n\n    # Icarus, NVC, and Xcelium can't find the signals by name unless we scan\n    # all signals\n    dut._discover_all()\n\n    # Debugging\n    for name in dut._keys():\n        cocotb.log.info(\"Found %r\", name)\n\n    for name in names:\n        assert dut[name]._name == name\n\n\n@cocotb.test\nasync def test_set_at_end_of_test(dut) -> None:\n    \"\"\"Tests that writes at the end of the test are still applied.\"\"\"\n    dut.stream_in_data.value = 0\n    await Timer(1)\n    dut.stream_in_data.value = 5\n\n\n@cocotb.test\nasync def test_set_at_end_of_test_check(dut) -> None:\n    assert dut.stream_in_data.value == 5\n\n\n@cocotb.test\nasync def test_invalid_indexing(dut) -> None:\n    # Slicing not supported by ArrayObject.\n    with pytest.raises(TypeError):\n        dut.array_7_downto_4[6:5]\n\n\n@cocotb.test\nasync def test_setattr_error_msg(dut: Any) -> None:\n    with pytest.raises(AttributeError, match=r\"'example'.*[Nn]o.*exist\"):\n        dut.example = 1\n    with pytest.raises(AttributeError, match=r\"'stream_in_data'.*\\.value\"):\n        dut.stream_in_data = 1\n\n\n@cocotb.test\nasync def test_pickling_prohibited(dut: object) -> None:\n    with pytest.raises(NotImplementedError):\n        pickle.dumps(dut)\n\n\n@cocotb.test\nasync def test_handle_str_with_separators(dut: Any) -> None:\n    \"\"\"Test that LogicArray handles string inputs with visual separators correctly.\"\"\"\n    dut.stream_in_data.value = \"1010_1101\"\n    await Timer(1, \"ns\")\n    assert dut.stream_in_data.value == LogicArray(\"10101101\")\n\n    dut.stream_in_data.value = \"11__00__11__00\"\n    await Timer(1, \"ns\")\n    assert dut.stream_in_data.value == LogicArray(\"11001100\")\n\n    dut.stream_in_data.value = \"__01010011__\"\n    await Timer(1, \"ns\")\n    assert dut.stream_in_data.value == LogicArray(\"01010011\")\n\n\n@cocotb.test\n@cocotb.skipif(\n    SIM_NAME.startswith(\"modelsim\") and LANGUAGE == \"verilog\",\n    reason=\"Questa legacy flow doesn't support value change callbacks on vectors.\",\n)\nasync def test_edge_on_vectors(dut: Any) -> None:\n    \"\"\"Test that RisingEdge/FallingEdge works on 1-bit LogicArrayObject and fails on multi-bit LogicArrayObject.\"\"\"\n\n    assert len(dut.stream_in_data) > 1\n    with pytest.raises(TypeError):\n        # RisingEdge on multi-bit signal\n        await cocotb.triggers.RisingEdge(dut.stream_in_data)\n    with pytest.raises(TypeError):\n        # FallingEdge on multi-bit signal\n        await cocotb.triggers.FallingEdge(dut.stream_in_data)\n\n    assert len(dut.one_bit_vector) == 1\n\n    cocotb.clock.Clock(dut.one_bit_vector, 10, \"ns\").start()\n\n    # Test that edges on 1-bit signal don't raise an error\n    await cocotb.triggers.RisingEdge(dut.one_bit_vector)\n    await cocotb.triggers.FallingEdge(dut.one_bit_vector)\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_logging.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests for the cocotb logger\n\"\"\"\n\nfrom __future__ import annotations\n\nimport contextlib\nimport logging\nimport warnings\nfrom collections.abc import Generator\n\nimport cocotb\nimport cocotb.logging as cocotb_logging\nfrom cocotb.logging import ANSI\n\n\nclass LogCaptureHandler(logging.Handler):\n    def __init__(self) -> None:\n        super().__init__()\n        self.records: list[logging.LogRecord] = []\n        self.msgs: list[str] = []\n\n    def emit(self, record: logging.LogRecord) -> None:\n        self.records.append(record)\n        msg = self.format(record)\n        self.msgs.append(msg)\n\n\n@contextlib.contextmanager\ndef capture_logs(\n    logger_name: str | None = None,\n    formatter: logging.Formatter | None = None,\n) -> Generator[LogCaptureHandler, None, None]:\n    handler = LogCaptureHandler()\n    if formatter is None:\n        formatter = cocotb_logging.SimLogFormatter()\n    handler.setFormatter(formatter)\n    logger = logging.getLogger(logger_name)\n    logger.addHandler(handler)\n    try:\n        yield handler\n    finally:\n        logger.removeHandler(handler)\n\n\nclass StrCallCounter:\n    def __init__(self):\n        self.str_counter = 0\n\n    def __str__(self):\n        self.str_counter += 1\n        return f\"__str__ called {self.str_counter} time(s)\"\n\n\n@cocotb.test()\nasync def test_logging_with_args(dut):\n    counter = StrCallCounter()\n    cocotb.log.setLevel(\n        logging.INFO\n    )  # To avoid logging debug message, to make next line run without error\n    cocotb.log.debug(\"%s\", counter)\n    assert counter.str_counter == 0\n\n    cocotb.log.info(\"%s\", counter)\n    assert counter.str_counter == 1\n\n    cocotb.log.info(\"No substitution\")\n\n    cocotb.log.warning(\"Testing multiple line\\nmessage\")\n\n\n@cocotb.test()\nasync def test_custom_logging_levels(dut):\n    logging.basicConfig(level=logging.NOTSET)\n    logging.addLevelName(7, \"SUPER_DEBUG\")\n    logger = logging.getLogger(\"name\")\n    logger.setLevel(5)\n    with capture_logs() as logs:\n        logger.log(5, \"SUPER DEBUG MESSAGE!\")\n    assert len(logs.msgs) == 1\n    assert \"SUPER DEBUG MESSAGE!\" in logs.msgs[0]\n\n\n@cocotb.test\nasync def test_ansi_stripping(_: object) -> None:\n    old_string_ansi = cocotb_logging.strip_ansi\n    cocotb_logging.strip_ansi = True\n    try:\n        with capture_logs() as logs:\n            cocotb.log.info(\n                f\"{ANSI.YELLOW_FG}That {ANSI.GREEN_BG}boy {ANSI.BLUE_FG}ain't {ANSI.BRIGHT_RED_BG}right.{ANSI.DEFAULT_FG}\"\n            )\n        assert len(logs.msgs) == 1\n        assert logs.msgs[0].endswith(\"That boy ain't right.\")\n    finally:\n        cocotb_logging.strip_ansi = old_string_ansi\n\n\n@cocotb.test\nasync def test_warning_capture(_: object) -> None:\n    with warnings.catch_warnings(), capture_logs() as logs:\n        warnings.simplefilter(\"always\")\n        warnings.warn(\"This is a test warning\", UserWarning)\n    assert len(logs.msgs) == 1\n    assert \"This is a test warning\" in logs.msgs[0]\n\n\n@cocotb.test\nasync def test_ljust_rjust(_: object) -> None:\n    ljust = cocotb_logging.SimLogFormatter.ljust\n    rjust = cocotb_logging.SimLogFormatter.rjust\n    assert ljust(\"0123\", 5) == \"0123 \"\n    assert rjust(\"0123\", 5) == \" 0123\"\n    assert ljust(\"01234\", 5) == \"01234\"\n    assert rjust(\"01234\", 5) == \"01234\"\n    assert ljust(\"012345\", 5) == \"..345\"\n    assert rjust(\"012345\", 5) == \"..345\"\n\n\n@cocotb.test\nasync def test_multiline_indent(_: object) -> None:\n    stripped_formatter = cocotb_logging.SimLogFormatter(strip_ansi=True)\n    with capture_logs(formatter=stripped_formatter) as logs:\n        cocotb.log.info(\"First line\\nSecond line\")\n    assert len(logs.msgs) == 1\n    lines = logs.msgs[0].splitlines()\n    assert len(lines) == 2\n    first_index = lines[0].find(\"First line\")\n    second_index = lines[1].find(\"Second line\")\n    assert first_index == second_index\n    assert first_index != -1\n\n    indent_formatter = cocotb_logging.SimLogFormatter(\n        strip_ansi=True, multiline_indent=first_index + 1\n    )\n    with capture_logs(formatter=indent_formatter) as logs:\n        cocotb.log.info(\"First line\\nSecond line\")\n    assert len(logs.msgs) == 1\n    lines = logs.msgs[0].splitlines()\n    assert len(lines) == 2\n    assert lines[0].find(\"First line\") == first_index\n    assert lines[1].find(\"Second line\") == first_index + 1\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_queues.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests relating to cocotb.queue.Queue, cocotb.queue.LifoQueue, cocotb.queue.PriorityQueue\n\"\"\"\n\nfrom __future__ import annotations\n\nimport pytest\n\nimport cocotb\nfrom cocotb.queue import LifoQueue, PriorityQueue, Queue, QueueEmpty, QueueFull\nfrom cocotb.triggers import NullTrigger, gather\n\n\n@cocotb.test\n@cocotb.parametrize(queue_type=[Queue, PriorityQueue, LifoQueue])\nasync def run_queue_nonblocking_test(dut, queue_type):\n    QUEUE_SIZE = 10\n\n    q = queue_type(maxsize=QUEUE_SIZE)\n\n    # queue empty\n    assert q.maxsize == QUEUE_SIZE\n    assert q.qsize() == 0\n    assert q.empty()\n    assert not q.full()\n\n    # put one item\n    q.put_nowait(0)\n\n    assert q.qsize() == 1\n    assert not q.empty()\n    assert not q.full()\n\n    # fill queue\n    if queue_type is PriorityQueue:\n        for k in range(QUEUE_SIZE - 1, 0, -1):\n            q.put_nowait(k)\n    else:\n        for k in range(1, QUEUE_SIZE):\n            q.put_nowait(k)\n\n    assert q.qsize() == QUEUE_SIZE\n    assert not q.empty()\n    assert q.full()\n\n    # overflow\n    with pytest.raises(QueueFull):\n        q.put_nowait(100)\n\n    # check queue contents\n    if queue_type is LifoQueue:\n        for k in range(QUEUE_SIZE - 1, -1, -1):\n            assert q.get_nowait() == k\n    else:\n        for k in range(QUEUE_SIZE):\n            assert q.get_nowait() == k\n\n    assert q.qsize() == 0\n    assert q.empty()\n    assert not q.full()\n\n    # underflow\n    with pytest.raises(QueueEmpty):\n        q.get_nowait()\n\n\n@cocotb.test()\nasync def test_queue_contention(dut):\n    NUM_PUTTERS = 20\n    QUEUE_SIZE = 10\n\n    q = Queue(maxsize=QUEUE_SIZE)\n\n    async def putter(lst, item):\n        await q.put(item)\n        lst.append(item)\n\n    async def getter(lst, item):\n        assert item == await q.get()\n        lst.append(item)\n\n    coro_list = []\n    putter_list = []\n    getter_list = []\n\n    # test put contention\n    for k in range(NUM_PUTTERS):\n        coro_list.append(cocotb.start_soon(putter(putter_list, k)))\n    await NullTrigger()\n\n    assert q.qsize() == QUEUE_SIZE\n\n    # test killed putter\n    coro = cocotb.start_soon(putter(putter_list, 100))\n    coro.cancel()\n    coro_list.append(cocotb.start_soon(putter(putter_list, 101)))\n\n    for k in range(NUM_PUTTERS):\n        coro_list.append(cocotb.start_soon(getter(getter_list, k)))\n\n    coro_list.append(cocotb.start_soon(getter(getter_list, 101)))\n\n    await gather(*coro_list)\n\n    assert putter_list == [*range(NUM_PUTTERS), 101]\n    assert getter_list == [*range(NUM_PUTTERS), 101]\n\n    assert q.qsize() == 0\n\n    coro_list = []\n    putter_list = []\n    getter_list = []\n\n    # test get contention\n    for k in range(NUM_PUTTERS):\n        coro_list.append(cocotb.start_soon(getter(getter_list, k)))\n\n    # test killed getter\n    coro2 = cocotb.start_soon(getter(getter_list, 100))\n    coro2.cancel()\n    coro_list.append(cocotb.start_soon(getter(getter_list, 101)))\n\n    for k in range(NUM_PUTTERS):\n        coro_list.append(cocotb.start_soon(putter(putter_list, k)))\n\n    coro_list.append(cocotb.start_soon(putter(putter_list, 101)))\n\n    await gather(*coro_list)\n\n    assert putter_list == [*range(NUM_PUTTERS), 101]\n    assert getter_list == [*range(NUM_PUTTERS), 101]\n\n    assert q.qsize() == 0\n\n\n@cocotb.test()\nasync def test_fair_scheduling(dut):\n    NUM_PUTTERS = 10\n    NUM_PUTS = 10\n\n    q = Queue(maxsize=1)\n\n    async def putter(i):\n        for _ in range(NUM_PUTS):\n            await q.put(i)\n\n    # fill queue to force contention\n    q.put_nowait(None)\n\n    # create NUM_PUTTER contending putters\n    putters = [cocotb.start_soon(putter(i)) for i in range(NUM_PUTTERS)]\n    await NullTrigger()\n\n    # remove value that forced contention\n    assert q.get_nowait() is None, \"Popped unexpected value\"\n\n    # test fair scheduling by ensuring that each putter is serviced for its first\n    # write before the second write on any putter is serviced.\n    for _ in range(NUM_PUTS):\n        remaining = set(range(NUM_PUTTERS))\n        for _ in range(NUM_PUTTERS):\n            v = await q.get()\n            assert v in remaining, \"Unfair scheduling occurred\"\n            remaining.remove(v)\n\n    assert all(p.done() for p in putters), \"Not all putters finished?\"\n\n\n@cocotb.test\n@cocotb.parametrize(queue_type=[Queue, PriorityQueue, LifoQueue])\nasync def run_queue_blocking_test(dut, queue_type):\n    NUM_PUTTERS = 20\n    QUEUE_SIZE = 10\n\n    q = queue_type(maxsize=QUEUE_SIZE)\n    ref_q = queue_type()\n\n    async def putter(lst, item):\n        await q.put(item)\n        ref_q.put_nowait(item)\n        lst.append(item)\n\n    async def getter(lst, num):\n        item = await q.get()\n        assert ref_q.get_nowait() == item\n        lst.append(num)\n\n    coro_list = []\n    putter_list = []\n    getter_list = []\n\n    # test put contention\n    for k in range(NUM_PUTTERS):\n        coro_list.append(cocotb.start_soon(putter(putter_list, k)))\n    await NullTrigger()\n\n    assert q.qsize() == QUEUE_SIZE\n\n    for k in range(NUM_PUTTERS):\n        coro_list.append(cocotb.start_soon(getter(getter_list, k)))\n    await NullTrigger()\n\n    await gather(*coro_list)\n\n    assert putter_list == list(range(NUM_PUTTERS))\n    assert getter_list == list(range(NUM_PUTTERS))\n\n    assert q.qsize() == 0\n    assert ref_q.qsize() == 0\n\n    coro_list = []\n    putter_list = []\n    getter_list = []\n\n    # test get contention\n    for k in range(NUM_PUTTERS):\n        coro_list.append(cocotb.start_soon(getter(getter_list, k)))\n    await NullTrigger()\n\n    for k in range(NUM_PUTTERS):\n        coro_list.append(cocotb.start_soon(putter(putter_list, k)))\n    await NullTrigger()\n\n    await gather(*coro_list)\n\n    assert putter_list == list(range(NUM_PUTTERS))\n    assert getter_list == list(range(NUM_PUTTERS))\n\n    assert q.qsize() == 0\n    assert ref_q.qsize() == 0\n\n\n@cocotb.test()\nasync def test_str_and_repr(_):\n    q = Queue[int](maxsize=1)\n\n    q.put_nowait(0)\n    cocotb.start_soon(q.put(1))\n    await NullTrigger()\n\n    s = repr(q)\n    assert \"maxsize\" in s\n    assert \"_queue\" in s\n    assert \"_putters\" in s\n    assert str(q)[:-1] in s\n\n    assert q.get_nowait() == 0\n    # There's now room in the queue and putter has been signalled to wake up\n    await NullTrigger()\n\n    # putter has put into queue\n    s = repr(q)\n    assert \"_queue\" in s\n    assert \"_putters\" not in s\n\n    assert q.get_nowait() == 1\n    getter = cocotb.start_soon(q.get())\n    await NullTrigger()\n\n    s = repr(q)\n    assert \"_putters\" not in s\n    assert \"_getters\" in s\n    assert str(q)[:-1] in s\n\n    cocotb.start_soon(q.put(2))\n\n    await getter\n\n    s = repr(q)\n    assert \"_getters\" not in s\n    assert str(q)[:-1] in s\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_scheduler.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTest for scheduler and coroutine behavior\n\n* fork\n* join\n* kill\n\"\"\"\n\nfrom __future__ import annotations\n\nimport contextlib\nimport logging\nimport os\nimport random\nimport re\nfrom asyncio import CancelledError, InvalidStateError\nfrom collections.abc import Awaitable, Coroutine, Generator\nfrom typing import Any\n\nimport pytest\nfrom common import MyException, assert_takes\n\nimport cocotb\nimport cocotb.regression\nfrom cocotb.clock import Clock\nfrom cocotb.task import Task, current_task\nfrom cocotb.triggers import (\n    Combine,\n    Event,\n    First,\n    NullTrigger,\n    RisingEdge,\n    Timer,\n    Trigger,\n    gather,\n)\n\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\n\n@cocotb.test()\nasync def test_task_kill(dut):\n    \"\"\"Test that killing a task causes pending task to continue\"\"\"\n\n    test_flag = False\n\n    async def waiter(task):\n        try:\n            await task\n        finally:\n            nonlocal test_flag\n            test_flag = True\n\n    async def coro():\n        await Timer(1000, \"ns\")\n\n    task = cocotb.start_soon(coro())\n    await Timer(1)\n    waiter_task = cocotb.start_soon(waiter(task))\n    await Timer(1)\n    task.cancel()\n\n    # task should be cancelled, but waiter_task hasn't resumed yet\n    await NullTrigger()\n    assert task.cancelled()\n    assert not waiter_task.done()\n    assert not test_flag\n\n    # waiter should resume and finish\n    await NullTrigger()\n    assert waiter_task.done()\n    assert test_flag\n\n\n# worst case wait is max(time of task_one, time of task_two)\n# worst case of task_one is 5*(clock+wait) = 5*(10+100) = 550\n# worst case of task_two is 5*(clock+wait) = 5*(10+1000) = 5050\n@cocotb.test(timeout_time=5100, timeout_unit=\"ns\")\nasync def test_task_close_down(dut) -> None:\n    \"\"\"Test tasks completing allows awaiting task to continue.\"\"\"\n\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n\n    async def wait_on_clock_and_timer(time_ns: int) -> None:\n        for _ in range(5):\n            await RisingEdge(dut.clk)\n            await Timer(time_ns, \"ns\")\n\n    task_one = cocotb.start_soon(wait_on_clock_and_timer(time_ns=100))\n    task_two = cocotb.start_soon(wait_on_clock_and_timer(time_ns=1000))\n\n    await task_one\n    await task_two\n\n\n@cocotb.test()\nasync def join_finished(dut):\n    \"\"\"\n    Test that joining a coroutine that has already been joined gives\n    the same result as it did the first time.\n    \"\"\"\n\n    retval = None\n\n    async def some_coro():\n        await Timer(1, \"ns\")\n        return retval\n\n    task = cocotb.start_soon(some_coro())\n\n    retval = 1\n    x = await task\n    assert x == 1\n\n    # joining the second time should give the same result.\n    # we change retval here to prove it does not run again\n    retval = 2\n    x = await task\n    assert x == 1\n\n\n@cocotb.test()\nasync def consistent_join(dut):\n    \"\"\"\n    Test that joining a coroutine returns the finished value\n    \"\"\"\n\n    async def wait_for(clk, cycles):\n        rising_edge = RisingEdge(clk)\n        for _ in range(cycles):\n            await rising_edge\n        return cycles\n\n    cocotb.start_soon(Clock(dut.clk, 2000, \"ps\").start())\n\n    short_wait = cocotb.start_soon(wait_for(dut.clk, 10))\n    long_wait = cocotb.start_soon(wait_for(dut.clk, 30))\n\n    a = await wait_for(dut.clk, 20)\n    assert a == 20\n    b = await short_wait\n    assert b == 10\n    c = await long_wait\n    assert c == 30\n\n\n@cocotb.test()\nasync def test_kill_twice(dut):\n    \"\"\"\n    Test that killing a coroutine that has already been killed does not crash\n    \"\"\"\n\n    async def coro() -> None:\n        await Timer(100, \"ns\")\n\n    task = cocotb.start_soon(coro())\n    await Timer(1, \"ns\")\n    task.cancel()\n    await Timer(1, \"ns\")\n    task.cancel()\n\n\n@cocotb.test()\nasync def test_trigger_with_failing_prime(dut):\n    \"\"\"Test that a trigger failing to prime throws\"\"\"\n\n    class ABadTrigger(Trigger):\n        def __init__(self):\n            super().__init__()\n\n        def _prime(self):\n            raise RuntimeError(\"oops\")\n\n    await Timer(1, \"ns\")\n    try:\n        await ABadTrigger()\n    except RuntimeError as exc:\n        assert \"oops\" in str(exc)\n    else:\n        assert False\n\n\n@cocotb.test()\nasync def test_stack_overflow(dut):\n    \"\"\"\n    Test against stack overflows when starting many coroutines that terminate\n    before passing control to the simulator.\n    \"\"\"\n\n    # gh-637\n    async def null_coroutine():\n        await NullTrigger()\n\n    for _ in range(10_000):\n        await null_coroutine()\n\n    await Timer(100, \"ns\")\n\n\n@cocotb.test()\nasync def test_stack_overflow_pending_coros(dut):\n    \"\"\"\n    Test against stack overflow when queueing many pending coroutines\n    before yielding to scheduler.\n    \"\"\"\n\n    # gh-2489\n    async def simple_coroutine():\n        await Timer(10, \"step\")\n\n    await gather(*(cocotb.start_soon(simple_coroutine()) for _ in range(1024)))\n\n\n@cocotb.test()\nasync def test_kill_coroutine_waiting_on_the_same_trigger(dut):\n    # gh-1348\n    # NOTE: this test depends on scheduling priority.\n    # It assumes that the first task to wait on a trigger will be woken first.\n    # The fix for gh-1348 should prevent that from mattering.\n    dut.clk.value = 0\n\n    victim_resumed = False\n\n    async def victim():\n        await Timer(1, \"step\")  # prevent scheduling of RisingEdge before killer\n        await RisingEdge(dut.clk)\n        nonlocal victim_resumed\n        victim_resumed = True\n\n    victim_task = cocotb.start_soon(victim())\n\n    async def killer():\n        await RisingEdge(dut.clk)\n        victim_task.cancel()\n\n    cocotb.start_soon(killer())\n\n    await Timer(\n        2, \"step\"\n    )  # allow Timer in victim to pass making it schedule RisingEdge after the killer\n    dut.clk.value = 1\n    await Timer(1, \"step\")\n    assert not victim_resumed\n\n\n@cocotb.test()\nasync def test_nulltrigger_reschedule(dut):\n    \"\"\"\n    Test that NullTrigger doesn't immediately reschedule the waiting coroutine.\n\n    The NullTrigger will be added to the end of the list of pending triggers.\n    \"\"\"\n    log = logging.getLogger(\"cocotb.test\")\n    last_fork = None\n\n    async def reschedule(n):\n        nonlocal last_fork\n        for i in range(4):\n            log.info(\"Fork %d, iteration %d, last fork was %s\", n, i, last_fork)\n            assert last_fork != n\n            last_fork = n\n            await NullTrigger()\n\n    # Test should start in event loop\n    await gather(*(cocotb.start_soon(reschedule(i)) for i in range(4)))\n\n    await Timer(1, \"ns\")\n\n    # Event loop when simulator returns\n    await gather(*(cocotb.start_soon(reschedule(i)) for i in range(4)))\n\n\n@cocotb.test()\nasync def test_nulltrigger_repr(_):\n    n = NullTrigger()\n    assert re.match(r\"<NullTrigger at \\w+>\", repr(n))\n    n = NullTrigger(name=\"my_nulltrigger\")\n    assert re.match(r\"<NullTrigger for my_nulltrigger at \\w+>\", repr(n))\n\n\n@cocotb.test()\nasync def test_event_set_schedule(dut):\n    \"\"\"\n    Test that Event.set() doesn't cause an immediate reschedule.\n\n    The coroutine waiting with Event.wait() will be woken after\n    the current coroutine awaits a trigger.\n    \"\"\"\n\n    e = Event()\n    waiter_scheduled = False\n\n    async def waiter(event):\n        await event.wait()\n        nonlocal waiter_scheduled\n        waiter_scheduled = True\n\n    cocotb.start_soon(waiter(e))\n    await NullTrigger()\n\n    e.set()\n\n    # waiter() shouldn't run until after test awaits a trigger\n    assert waiter_scheduled is False\n\n    await NullTrigger()\n\n    assert waiter_scheduled is True\n\n\n@cocotb.test()\nasync def test_last_scheduled_write_wins(dut):\n    \"\"\"\n    Test that the last scheduled write for a signal handle is the value that is written.\n    \"\"\"\n    dut.stream_in_data.value = 0\n    await Timer(10, \"ns\")\n    assert dut.stream_in_data.value == 0\n    dut.stream_in_data.value = 1\n    dut.stream_in_data.value = 2\n    await Timer(1, \"ns\")\n    assert dut.stream_in_data.value == 2\n\n\n# GHDL unable to put values on nested array types (gh-2588)\n@cocotb.test(\n    expect_error=Exception if cocotb.SIM_NAME.lower().startswith(\"ghdl\") else ()\n)\nasync def test_last_scheduled_write_wins_array(dut):\n    \"\"\"\n    Test that the last scheduled write for an *arrayed* signal handle is the value that is written.\n    \"\"\"\n    dut.array_7_downto_4.value = [1, 2, 3, 4]\n    dut.array_7_downto_4[7].value = 10\n\n    await Timer(1, \"ns\")\n\n    assert dut.array_7_downto_4.value == [10, 2, 3, 4]\n\n\n@cocotb.test\nasync def test_task_repr(_) -> None:\n    \"\"\"Test Task.__repr__.\"\"\"\n    log = logging.getLogger(\"cocotb.test\")\n\n    coro_e = Event()\n\n    async def coroutine_wait():\n        await Timer(1, unit=\"ns\")\n\n    async def coroutine_inner():\n        await coro_e.wait()\n        # cr_await is None while the coroutine is running, so we can't get the stack...\n        log.info(repr(coro_task))\n        assert re.match(r\"<Task \\d+ running coro=coroutine_outer\\(\\)>\", repr(coro_task))\n\n        with pytest.warns(DeprecationWarning):\n            await Combine(*(cocotb.start_soon(coroutine_wait()) for _ in range(2)))\n\n        return \"Combine done\"\n\n    async def coroutine_middle():\n        return await coroutine_inner()\n\n    async def coroutine_outer():\n        return await coroutine_middle()\n\n    coro_task = cocotb.start_soon(coroutine_outer())\n    await NullTrigger()\n\n    # let coroutine_inner run up to the await Combine\n    coro_e.set()\n    await NullTrigger()\n\n    log.info(repr(coro_task))\n    assert re.match(\n        (\n            r\"<Task \\d+ pending coro=coroutine_inner\\(\\) trigger=Combine\\(\"\n            r\"<Task \\d+ scheduled coro=coroutine_wait\\(\\)>, \"\n            r\"<Task \\d+ scheduled coro=coroutine_wait\\(\\)>\"\n            r\"\\)>\"\n        ),\n        repr(coro_task),\n    )\n\n    # wait for coroutine_waits to start\n    await NullTrigger()\n\n    log.info(repr(coro_task))\n    assert re.match(\n        (\n            r\"<Task \\d+ pending coro=coroutine_inner\\(\\) trigger=Combine\\(\"\n            r\"<Task \\d+ pending coro=coroutine_wait\\(\\) trigger=<Timer of 1000.00ps at \\w+>>, \"\n            r\"<Task \\d+ pending coro=coroutine_wait\\(\\) trigger=<Timer of 1000.00ps at \\w+>>\"\n            r\"\\)>\"\n        ),\n        repr(coro_task),\n    )\n\n    await Timer(2, unit=\"ns\")\n\n    log.info(repr(coro_task))\n    assert re.match(\n        r\"<Task \\d+ finished coro=coroutine_outer\\(\\) outcome='Combine done'\",\n        repr(coro_task),\n    )\n\n    async def coroutine_first():\n        task = Task(coroutine_wait())\n        with pytest.warns(DeprecationWarning):\n            await First(task, Timer(2, unit=\"ns\"))\n        task.cancel()\n\n    coro_task = cocotb.start_soon(coroutine_first())\n    assert re.match(r\"<Task \\d+ scheduled coro=coroutine_first\\(\\)>\", repr(coro_task))\n\n    await NullTrigger()\n\n    log.info(repr(coro_task))\n    assert re.match(\n        (\n            r\"<Task \\d+ pending coro=coroutine_first\\(\\) trigger=First\\(\"\n            r\"<Task \\d+ created coro=coroutine_wait\\(\\)>, \"\n            r\"<Timer of 2000.00ps at \\w+>\"\n            r\"\\)>\"\n        ),\n        repr(coro_task),\n    )\n\n    # wait for coroutine_wait to start\n    await NullTrigger()  # start_soon on _wait_callback\n\n    log.info(repr(coro_task))\n    assert re.match(\n        (\n            r\"<Task \\d+ pending coro=coroutine_first\\(\\) trigger=First\\(\"\n            r\"<Task \\d+ scheduled coro=coroutine_wait\\(\\)>, \"\n            r\"<Timer of 2000.00ps at \\w+>\"\n            r\"\\)>\"\n        ),\n        repr(coro_task),\n    )\n\n    await NullTrigger()  # awaiting Task in _wait_callback\n\n    log.info(repr(coro_task))\n    assert re.match(\n        (\n            r\"<Task \\d+ pending coro=coroutine_first\\(\\) trigger=First\\(\"\n            r\"<Task \\d+ pending coro=coroutine_wait\\(\\) trigger=<Timer of 1000.00ps at \\w+>>, \"\n            r\"<Timer of 2000.00ps at \\w+>\"\n            r\"\\)>\"\n        ),\n        repr(coro_task),\n    )\n\n    async def coroutine_timer():\n        await Timer(1, unit=\"ns\")\n\n    coro_task = cocotb.start_soon(coroutine_timer())\n    await NullTrigger()\n\n    # Trigger.__await__ should be popped from the coroutine stack\n    log.info(repr(coro_task))\n    assert re.match(\n        r\"<Task \\d+ pending coro=coroutine_timer\\(\\) trigger=<Timer of 1000.00ps at \\w+>>\",\n        repr(coro_task),\n    )\n\n    # start task\n    coro_task = cocotb.start_soon(coroutine_outer())\n\n    log.info(repr(coro_task))\n    assert re.match(r\"<Task \\d+ scheduled coro=coroutine_outer\\(\\)>\", repr(coro_task))\n\n    log.info(str(coro_task))\n    assert re.match(r\"<Task \\d+>\", str(coro_task))\n\n    class CoroutineClass(Coroutine):\n        def __init__(self):\n            self._coro = self.run()\n\n        async def run(self):\n            pass\n\n        def send(self, value):\n            self._coro.send(value)\n\n        def throw(self, exception):\n            self._coro.throw(exception)\n\n        def close(self):\n            self._coro.close()\n\n        def __await__(self):\n            yield from self._coro.__await__()\n\n    object_task = cocotb.create_task(CoroutineClass())\n    log.info(repr(object_task))\n    assert re.match(r\"<Task \\d+ created coro=CoroutineClass\\(\\)>\", repr(object_task))\n\n    object_task.cancel()  # prevent RuntimeWarning of unwatched coroutine\n    await NullTrigger()\n\n\n@cocotb.test()\nasync def test_test_repr(_):\n    \"\"\"Test RunningTest.__repr__\"\"\"\n    log = logging.getLogger(\"cocotb.test\")\n\n    current_test = cocotb._test_manager._current_test._main_task\n    log.info(repr(current_test))\n    assert re.match(\n        r\"<Test test_test_repr running coro=test_test_repr\\(\\)>\", repr(current_test)\n    )\n\n    log.info(str(current_test))\n    assert re.match(r\"<Test test_test_repr>\", str(current_test))\n\n\n@cocotb.test()\nclass TestClassRepr(Coroutine):\n    def __init__(self, dut):\n        self._coro = self.check_repr(dut)\n\n    async def check_repr(self, dut):\n        log = logging.getLogger(\"cocotb.test\")\n\n        current_test = cocotb._test_manager._current_test._main_task\n        log.info(repr(current_test))\n        assert re.match(\n            r\"<Test TestClassRepr running coro=TestClassRepr\\(\\)>\", repr(current_test)\n        )\n\n        log.info(str(current_test))\n        assert re.match(r\"<Test TestClassRepr>\", str(current_test))\n\n    def send(self, value):\n        self._coro.send(value)\n\n    def throw(self, exception):\n        self._coro.throw(exception)\n\n    def close(self):\n        self._coro.close()\n\n    def __await__(self):\n        yield from self._coro.__await__()\n\n\n@cocotb.test()\nasync def test_start_soon_async(_):\n    \"\"\"Tests start_soon works with coroutines\"\"\"\n    a = 0\n\n    async def example():\n        nonlocal a\n        a = 1\n\n    cocotb.start_soon(example())\n    assert a == 0\n    await NullTrigger()\n    assert a == 1\n\n\n@cocotb.test()\nasync def test_await_start_soon(_):\n    \"\"\"Test awaiting start_soon queued coroutine before it starts.\"\"\"\n\n    async def coro():\n        await Timer(1, \"ns\")\n\n    coro = cocotb.start_soon(coro())\n\n    with assert_takes(1, \"ns\"):\n        await coro\n\n\n@cocotb.test()\nasync def test_kill_start_soon_task(_):\n    \"\"\"Test killing task queued by start_soon.\"\"\"\n    coro_scheduled = False\n\n    async def coro():\n        nonlocal coro_scheduled\n        coro_scheduled = True\n\n    task = cocotb.start_soon(coro())\n    task.cancel()\n\n    await NullTrigger()\n    assert coro_scheduled is False\n    assert task.done()\n\n\nstart_soon_started = False\n\n\n@cocotb.test()\nasync def test_test_end_after_start_soon(_):\n    \"\"\"Test ending test before start_soon queued coroutine starts.\"\"\"\n\n    async def coro():\n        global start_soon_started\n        start_soon_started = True\n\n    cocotb.start_soon(coro())\n\n\n@cocotb.test()\nasync def test_previous_start_soon_not_scheduled(_):\n    \"\"\"Test that queued coroutine from previous test did not run.\n\n    NOTE: This test must be after test_test_end_after_start_soon.\n    \"\"\"\n    assert start_soon_started is False\n\n\n@cocotb.test()\nasync def test_test_end_with_multiple_pending_tasks(_):\n    \"\"\"Test ending a test with multiple tasks queued by start_soon.\"\"\"\n\n    async def coro():\n        return 0\n\n    # gh-3354\n    cocotb.start_soon(coro())\n    cocotb.start_soon(coro())\n\n\n@cocotb.test\nasync def test_start(_) -> None:\n    async def coro():\n        await Timer(1, \"step\")\n\n    task1 = cocotb.start_soon(coro())\n    assert type(task1) is Task\n    assert not task1.done()\n\n    await Timer(2, \"step\")\n    assert task1.done()\n\n    task2 = cocotb.create_task(coro())\n    task3 = cocotb.start_soon(task2)\n    assert task3 is task2\n\n    async def coro_val():\n        return 1\n\n    task6 = cocotb.start_soon(coro_val())\n    await NullTrigger()\n    assert task6.done()\n    assert await task6 == 1\n\n\n@cocotb.test()\nasync def test_create_task(_):\n    # proper construction from coroutines\n    async def coro():\n        pass\n\n    assert type(cocotb.create_task(coro())) is Task\n\n    # proper construction from Coroutine objects\n    class CoroType(Coroutine):\n        def __init__(self):\n            self._coro = coro()\n\n        def send(self, value):\n            return self._coro.send(value)\n\n        def throw(self, exception):\n            self._coro.throw(exception)\n\n        def close(self):\n            self._coro.close()\n\n        def __await__(self):\n            yield from self._coro.__await__()\n\n    assert type(cocotb.create_task(CoroType())) is Task\n\n    # fail if given async generators\n    async def agen():\n        yield None\n\n    with pytest.raises(TypeError):\n        cocotb.create_task(agen())\n\n    # fail if given coroutine function\n    with pytest.raises(TypeError):\n        cocotb.create_task(coro)\n\n    # fail if given Coroutine Type\n    with pytest.raises(TypeError):\n        cocotb.create_task(CoroType)\n\n    # fail if given async generator function\n    with pytest.raises(TypeError):\n        cocotb.create_task(agen)\n\n    # fail if given random type\n    with pytest.raises(TypeError):\n        cocotb.create_task(object())\n\n\n@cocotb.test()\nasync def test_task_completes(_):\n    async def coro():\n        return 123\n\n    task = cocotb.start_soon(coro())\n    assert not task.cancelled()\n    assert not task.done()\n    assert await task == 123\n    assert not task.cancelled()\n    assert task.done()\n    assert task.result() == 123\n    assert task.exception() is None\n\n\n@cocotb.test()\nasync def test_task_exception(_):\n    async def coro():\n        raise MyException(\"msg1234\")\n\n    task = cocotb.start_soon(coro())\n    assert not task.cancelled()\n    assert not task.done()\n    with pytest.raises(MyException, match=\"msg1234\"):\n        await task\n    assert not task.cancelled()\n    assert task.done()\n    with pytest.raises(MyException, match=\"msg1234\"):\n        task.result()\n    assert type(task.exception()) is MyException\n    assert str(task.exception()) == \"msg1234\"\n\n\n@cocotb.test\nasync def test_cancel_task(_: object) -> None:\n    cancelled: bool = False\n\n    async def coro(will_be_cancelled: bool) -> None:\n        try:\n            await Timer(10, \"ns\")\n        except CancelledError:\n            nonlocal cancelled\n            cancelled = True\n            raise\n        else:\n            assert not will_be_cancelled\n\n    # Test Task succeeds successfully.\n    task = cocotb.start_soon(coro(False))\n    assert not cancelled\n    assert not task.cancelled()\n    assert not task.done()\n    await task\n    assert not cancelled\n    assert not task.cancelled()\n    assert task.done()\n\n    cancelled = False\n    task = cocotb.start_soon(coro(True))\n    await NullTrigger()\n    task.cancel(\"msg1234\")\n    await Timer(1, \"ns\")\n    assert cancelled\n    assert task.cancelled()\n    assert task.done()\n    with pytest.raises(CancelledError, match=\"msg1234\"):\n        task.result()\n    with pytest.raises(CancelledError, match=\"msg1234\"):\n        task.exception()\n\n    # Test cancel before task starts\n    task = cocotb.start_soon(coro(True))\n    task.cancel()\n    await Timer(1, \"ns\")\n    assert cancelled\n    assert task.cancelled()\n    assert task.done()\n\n\n@cocotb.test(expect_error=RuntimeError)\nasync def test_cancel_task_cancellation_error(_: object) -> None:\n    a = Event()\n\n    async def coro():\n        with contextlib.suppress(CancelledError):\n            await a.wait()\n\n    task = cocotb.start_soon(coro())\n    await NullTrigger()\n    task.cancel()\n    await Timer(1, \"ns\")\n\n\n@cocotb.test()\nasync def test_invalid_operations_task(_):\n    async def coro():\n        return 123\n\n    task = cocotb.start_soon(coro())\n    with pytest.raises(InvalidStateError):\n        task.result()\n    with pytest.raises(InvalidStateError):\n        task.exception()\n\n\n@cocotb.test(expect_fail=True)\nasync def test_multiple_concurrent_test_fails(_) -> None:\n    async def call_error(thing: Awaitable[Any]) -> None:\n        await thing\n        assert False\n\n    thing = Timer(1, \"ns\")\n    cocotb.start_soon(call_error(thing))\n    cocotb.start_soon(call_error(thing))\n    await Timer(10, \"ns\")\n\n\n@cocotb.test\nasync def test_task_done_callback_passing(_) -> None:\n    callback_ran = False\n\n    def done_callback(_: Task) -> None:\n        nonlocal callback_ran\n        callback_ran = True\n\n    async def passing_coro() -> None:\n        pass\n\n    passing_task = cocotb.start_soon(passing_coro())\n    passing_task._add_done_callback(done_callback)\n    await passing_task\n    assert callback_ran\n\n\n@cocotb.test\nasync def test_task_done_callback_erroring(_) -> None:\n    callback_ran = False\n\n    def done_callback(_: Task) -> None:\n        nonlocal callback_ran\n        callback_ran = True\n\n    async def erroring_coro() -> None:\n        raise Exception\n\n    erroring_task = cocotb.start_soon(erroring_coro())\n    callback_ran = False\n    erroring_task._add_done_callback(done_callback)\n    with contextlib.suppress(Exception):\n        await erroring_task\n    assert callback_ran\n\n\n@cocotb.test\nasync def test_task_done_callback_cancelled(_) -> None:\n    callback_ran = False\n\n    def done_callback(_: Task) -> None:\n        nonlocal callback_ran\n        callback_ran = True\n\n    async def cancelled_coro() -> None:\n        e = Event()\n        await e.wait()\n\n    cancelled_task = cocotb.start_soon(cancelled_coro())\n    callback_ran = False\n    cancelled_task._add_done_callback(done_callback)\n    await Timer(1, \"ns\")\n    cancelled_task.cancel()\n    await NullTrigger()\n    assert callback_ran\n\n\n@cocotb.test\nasync def test_task_done_callback_added_after_done(_) -> None:\n    async def noop() -> None:\n        pass\n\n    callback_ran = False\n\n    def done_callback(_: Task) -> None:\n        nonlocal callback_ran\n        callback_ran = True\n\n    task = cocotb.start_soon(noop())\n    await task\n    task._add_done_callback(done_callback)\n    await NullTrigger()\n    assert callback_ran\n\n\n@cocotb.test\nasync def test_task_complete(_) -> None:\n    async def noop() -> None:\n        pass\n\n    task = cocotb.start_soon(noop())\n    assert not task.done()\n    tc = task.complete\n    assert tc.task is task\n    res = await tc\n    assert res is tc\n    assert res is task.complete\n    assert task.done()\n\n\n@cocotb.test\nasync def test_joins_in_first(_) -> None:\n    async def wait(ns: int) -> None:\n        await Timer(ns, \"ns\")\n\n    task1 = cocotb.start_soon(wait(10))\n    task2 = cocotb.start_soon(wait(20))\n    j = await First(task1.complete, task2.complete)\n    assert j is task1.complete\n\n\n@cocotb.test(expect_error=MyException)\nasync def test_start_after_create(_) -> None:\n    async def fail():\n        raise MyException()\n\n    a = cocotb.create_task(fail())\n    cocotb.start_soon(a)\n    await a\n\n\n@cocotb.test\nasync def test_start_again_while_scheduled(_) -> None:\n    async def noop() -> None:\n        pass\n\n    a = cocotb.start_soon(noop())\n    b = cocotb.start_soon(a)\n    assert b is a\n    await a\n\n\n@cocotb.test\nasync def test_start_again_while_pending(_) -> None:\n    async def noop() -> None:\n        await Timer(1, \"ns\")\n\n    a = cocotb.start_soon(noop())\n    await NullTrigger()\n    b = cocotb.start_soon(a)\n    assert b is a\n    await a\n\n\n@cocotb.test(expect_error=RuntimeError)\nasync def test_test_end_cancellation_error(_) -> None:\n    \"\"\"Test that test-end Cancellation causes test failure.\"\"\"\n\n    async def coro() -> None:\n        with contextlib.suppress(CancelledError):\n            await Timer(1000, \"ns\")\n\n    cocotb.start_soon(coro())\n    await Timer(1)\n\n\n@cocotb.test\nasync def test_task_name(_: object) -> None:\n    async def coro() -> None:\n        await Timer(1)\n\n    t = Task(coro(), name=\"Task123\")\n    assert t.get_name() == \"Task123\"\n\n    t.set_name(\"different\")\n    assert t.get_name() == \"different\"\n    t.cancel()\n\n    t = cocotb.create_task(coro(), name=\"foo\")\n    assert t.get_name() == \"foo\"\n    t.cancel()\n\n    t = cocotb.start_soon(coro(), name=\"bar\")\n    assert t.get_name() == \"bar\"\n    t.cancel()\n\n    with pytest.warns(DeprecationWarning):\n        t = await cocotb.start(coro(), name=\"baz\")\n    assert t.get_name() == \"baz\"\n    t.cancel()\n\n\n@cocotb.test\nasync def test_start_again_finished_task(_: object) -> None:\n    async def coro() -> None:\n        await Timer(1, \"ns\")\n\n    a = cocotb.start_soon(coro())\n    await a\n\n    with pytest.raises(RuntimeError):\n        cocotb.start_soon(a)\n\n\n@cocotb.test\nasync def test_start_again_cancelled_task(_: object) -> None:\n    async def coro() -> None:\n        await Timer(1, \"ns\")\n\n    a = cocotb.start_soon(coro())\n    await NullTrigger()\n    a.cancel()\n\n    with pytest.raises(CancelledError):\n        await a\n\n    with pytest.raises(RuntimeError):\n        cocotb.start_soon(a)\n\n\ncarryover_task: Task\n\n\n@cocotb.test\nasync def test_create_carryover_task(_: object) -> None:\n    async def coro() -> None:\n        await Timer(1, \"ns\")\n\n    global carryover_task\n    carryover_task = cocotb.create_task(coro())\n\n\n@cocotb.test\nasync def test_start_carryover_task(_: object) -> None:\n    with pytest.raises(RuntimeError):\n        cocotb.start_soon(carryover_task)\n\n\n@cocotb.test\nasync def test_task_local_variables(_: object) -> None:\n    \"\"\"Test that task-local variables are not shared between tasks.\"\"\"\n\n    def get_rng() -> random.Random:\n        try:\n            return current_task().locals.rng\n        except AttributeError:\n            rng = random.Random()\n            current_task().locals.rng = rng\n            return rng\n\n    async def coro() -> None:\n        exp = get_rng()\n        await Timer(1, \"ns\")\n        assert get_rng() is exp\n\n    task = cocotb.start_soon(coro())\n    await task\n\n\n@cocotb.test(expect_error=RuntimeError)\nasync def test_Task_ignored_CancelledError_return(_: object) -> None:\n    async def bad() -> None:\n        try:\n            await Timer(10, \"ns\")\n        except CancelledError:\n            return\n\n    task = cocotb.start_soon(bad())\n    await Timer(1)\n    task.cancel()\n\n\n@cocotb.test(expect_error=RuntimeError)\nasync def test_Task_ignored_CancelledError_await(_: object) -> None:\n    async def bad() -> None:\n        try:\n            await Timer(10, \"ns\")\n        except CancelledError:\n            await Timer(1)\n\n    task = cocotb.start_soon(bad())\n    await Timer(1)\n    task.cancel()\n\n\n@cocotb.test\nasync def test_Task_cancel_running(_: object) -> None:\n    async def example() -> None:\n        task = current_task()\n        with pytest.raises(RuntimeError):\n            task.cancel()\n        assert not task.done()\n        await Timer(1)\n        # things still work after the failed kill\n        assert not task.done()\n\n    task = cocotb.start_soon(example())\n    await task\n    assert task.done()\n\n\n@cocotb.test\nasync def test_Task_yield_bad_value(_: object) -> None:\n    class NotATrigger:\n        def __await__(self) -> Generator[int, None, None]:\n            yield 1\n\n    with pytest.raises(TypeError):\n        await NotATrigger()\n\n    await Timer(1)\n    # things still work after the bad yield\n\n\n@cocotb.test\nasync def test_write_in_Task_occurs_on_same_cycle(dut) -> None:\n    \"\"\"Test that writing to a signal in a Task writes on the same cycle.\"\"\"\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n\n    async def writer():\n        dut.stream_in_valid.value = 1\n        await Timer(1, \"step\")\n\n    dut.stream_in_valid.value = 0\n    await RisingEdge(dut.clk)\n    cocotb.start_soon(writer())\n    assert dut.stream_in_valid.value == 0\n    await RisingEdge(dut.clk)\n    assert dut.stream_in_valid.value == 1\n\n\nasync def wait_edge(dut: Any) -> None:\n    # this trigger never fires\n    await First(RisingEdge(dut.stream_out_ready))\n\n\n@cocotb.test\nasync def test_957_1(dut: Any) -> None:\n    cocotb.start_soon(wait_edge(dut))\n    await Timer(10, \"ns\")\n\n\n@cocotb.test\nasync def test_957_2(dut: Any) -> None:\n    # This test *MUST* be after test_957_1 to test that the previous test's\n    # pending coroutine doesn't interfere with this test.\n    cocotb.start_soon(wait_edge(dut))\n    await Timer(10, \"ns\")\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_sim_time_utils.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport pytest\n\nimport cocotb\nfrom cocotb import utils\n\n\n@cocotb.test()\nasync def test_get_sim_steps(_):\n    # test invalid round_mode specifier\n    with pytest.raises(ValueError, match=\"^Invalid round_mode specifier: notvalid\"):\n        utils.get_sim_steps(1, \"step\", round_mode=\"notvalid\")\n\n    # test default, update if default changes\n    with pytest.raises(ValueError):\n        utils.get_sim_steps(0.5, \"step\")\n\n    # test valid\n    with pytest.raises(ValueError):\n        utils.get_sim_steps(0.5, \"step\", round_mode=\"error\")\n    assert utils.get_sim_steps(24.0, \"step\", round_mode=\"error\") == 24\n    assert utils.get_sim_steps(1.2, \"step\", round_mode=\"floor\") == 1\n    assert utils.get_sim_steps(1.2, \"step\", round_mode=\"ceil\") == 2\n    assert utils.get_sim_steps(1.2, \"step\", round_mode=\"round\") == 1\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_start_soon.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_start_soon_doesnt_start_immediately(_):\n    a = 0\n\n    async def increments():\n        nonlocal a\n        a += 1\n\n    # start_soon doesn't run incremenents() immediately, so \"a\" is never incremented\n    cocotb.start_soon(increments())\n    assert a == 0\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_synchronization_primitives.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests for synchronization primitives like Lock and Event\n\"\"\"\n\nfrom __future__ import annotations\n\nimport random\nimport re\nfrom typing import Any\n\nimport pytest\nfrom common import assert_takes\n\nimport cocotb\nfrom cocotb._base_triggers import Trigger, _InternalEvent\nfrom cocotb.task import Task\nfrom cocotb.triggers import (\n    Event,\n    Lock,\n    NullTrigger,\n    ReadOnly,\n    Timer,\n    with_timeout,\n)\n\n\n@cocotb.test()\nasync def test_trigger_lock(dut):\n    \"\"\"\n    Simple test that checks to see if context management is kept. The\n    resource value is checked at certain points if it equals the expected\n    amount, which is easily predictable if the context management is working.\n    \"\"\"\n    resource = 0\n    lock = Lock()\n\n    async def co():\n        nonlocal resource\n        await Timer(10, \"ns\")\n        async with lock:\n            for _ in range(4):\n                await Timer(10, \"ns\")\n                resource += 1\n\n    cocotb.start_soon(co())\n    async with lock:\n        for _ in range(4):\n            resource += 1\n            await Timer(10, \"ns\")\n    assert resource == 4\n    await Timer(10, \"ns\")\n    async with lock:\n        assert resource == 8\n\n\n@cocotb.test(timeout_time=100, timeout_unit=\"ns\")\nasync def test_except_lock(dut):\n    \"\"\"\n    Checks to see if exceptions cause the lock to be\n    released.\n    \"\"\"\n    lock = Lock()\n    try:\n        async with lock:\n            raise RuntimeError()\n    except RuntimeError:\n        pass\n    async with lock:\n        pass\n\n\n@cocotb.test()\nasync def test_lock_release_without_acquire(_):\n    \"\"\"Test that Lock will error when released without first being acquired.\"\"\"\n    lock = Lock()\n    with pytest.raises(RuntimeError):\n        lock.release()\n\n\n@cocotb.test()\nasync def test_lock_repr(dut):\n    lock = Lock()\n\n    assert re.match(r\"<Lock \\[0 waiting\\] at \\w+>\", repr(lock))\n\n    with pytest.warns(DeprecationWarning):\n        lock = Lock(name=\"my_lock\")\n\n    async def task():\n        async with lock:\n            await Timer(1, \"ns\")\n\n    for _ in range(3):\n        cocotb.start_soon(task())\n\n    assert not lock.locked()\n\n    await NullTrigger()\n\n    assert re.match(r\"<Lock for my_lock \\[2 waiting\\] at \\w+>\", repr(lock))\n\n    assert lock.locked()\n\n    l = lock.acquire()\n\n    assert re.match(\n        r\"<<Lock for my_lock \\[2 waiting\\] at \\w+>\\.acquire\\(\\) at \\w+>\", repr(l)\n    )\n\n    await l\n\n\n@cocotb.test()\nasync def test_internalevent(dut):\n    \"\"\"Test _InternalEvent trigger.\"\"\"\n    e = _InternalEvent(\"test parent\")\n    assert repr(e) == \"'test parent'\"\n\n    async def set_internalevent():\n        await Timer(1, unit=\"ns\")\n        e.set()\n\n    # Test waiting more than once\n    cocotb.start_soon(set_internalevent())\n    with assert_takes(1, \"ns\"):\n        await e\n    assert e.is_set()\n    # _InternalEvent can only be awaited once\n    with pytest.raises(RuntimeError):\n        await e\n\n    e = _InternalEvent(None)\n    assert repr(e) == \"None\"\n    ran = False\n\n    async def await_internalevent():\n        nonlocal ran\n        await e\n        ran = True\n\n    # Test multiple coroutines waiting\n    cocotb.start_soon(await_internalevent())\n    await NullTrigger()\n    assert not e.is_set()\n    assert not ran\n    # _InternalEvent can only be awaited by one coroutine\n    with pytest.raises(RuntimeError):\n        await e\n    e.set()\n    await Timer(1)\n    assert e.is_set()\n    assert ran\n\n    # Test waiting after set\n    e = _InternalEvent(None)\n    assert not e.is_set()\n    cocotb.start_soon(set_internalevent())\n    await Timer(2, unit=\"ns\")\n    assert e.is_set()\n    with assert_takes(0, \"ns\"):\n        await e\n\n\n@cocotb.test\nasync def test_Lock_fair_scheduling(_) -> None:\n    \"\"\"Ensure that Lock acquisition is given in FIFO order to ensure fair access.\"\"\"\n\n    # test config\n    n_waiters = 500\n    waiter_ns = 1\n    average_kills = 50\n    average_test_time = (n_waiters - average_kills) * waiter_ns\n    average_killer_wakeup = average_test_time / average_kills\n\n    last_scheduled: int = -1\n    lock = Lock()\n\n    async def waiter(n: int) -> None:\n        # Ensure the waiter didn't hang due another waiter being killed.\n        with assert_takes(waiter_ns * (n + 1), \"ns\", lambda a, e: a <= e):\n            await lock.acquire()\n\n        # Ensure acquisition is in order.\n        nonlocal last_scheduled\n        assert n > last_scheduled\n        last_scheduled = n\n\n        # Hold the Lock for some time to give a chance for other waiters to be cancelled.\n        await Timer(waiter_ns, \"ns\")\n        lock.release()\n\n    tasks: list[Task[None]] = []\n\n    for i in range(n_waiters):\n        tasks.append(cocotb.start_soon(waiter(i)))\n        # Run the waiter until it gets the acquire()\n        await NullTrigger()\n\n    # We cancel tasks randomly to ensure that doesn't effect acquisition order.\n    while not all(t.done() for t in tasks):\n        # Randomly kill a remaining waiter.\n        tasks[random.randrange(last_scheduled, len(tasks))].cancel()\n        # Wait some random time until killing another.\n        await Timer(\n            (random.random() * 2 * average_killer_wakeup), \"ns\", round_mode=\"ceil\"\n        )\n        # So we don't depend upon the relative scheduling order of the waiter Timers and the above Timer.\n        await ReadOnly()\n\n\n@cocotb.test(expect_error=RuntimeError)\nasync def test_Lock_multiple_users_acquire_triggers(_) -> None:\n    \"\"\"Ensure that multiple Tasks using the same Lock.acquire() Triggers is not possible.\"\"\"\n\n    async def wait(trigger: Trigger) -> None:\n        await trigger\n\n    lock = Lock()\n    acquire_trigger = lock.acquire()\n\n    cocotb.start_soon(wait(acquire_trigger))\n    cocotb.start_soon(wait(acquire_trigger))\n    await Timer(1, \"ns\")\n\n\n@cocotb.test\nasync def test_Event_multiple_task_share_trigger(_) -> None:\n    \"\"\"Test that multiple tasks aren't allowed to share an Event trigger.\"\"\"\n\n    async def waiter(trigger: Trigger) -> None:\n        await trigger\n\n    e = Event()\n    e_trigger = e.wait()\n    cocotb.start_soon(waiter(e_trigger))\n    cocotb.start_soon(waiter(e_trigger))\n\n    await Timer(1, \"ns\")\n\n\n@cocotb.test\nasync def test_Event_wait_after_set(_: Any) -> None:\n    \"\"\"Test that getting the _Event Trigger, setting it, then awaiting the Trigger doesn't hang.\"\"\"\n\n    e = Event()\n    trigger = e.wait()\n\n    e.set()\n\n    # Should not block\n    await with_timeout(trigger, 1, \"step\")\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_task_manager.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nfrom __future__ import annotations\n\nimport sys\nfrom asyncio import CancelledError\nfrom collections.abc import AsyncGenerator\nfrom typing import TYPE_CHECKING, Any\n\nimport pytest\nfrom common import assert_takes\n\nimport cocotb\nfrom cocotb.task import Task\nfrom cocotb.triggers import Event, NullTrigger, TaskManager, Timer, Trigger\n\nif TYPE_CHECKING:\n    from collections.abc import Generator\n\nif sys.version_info < (3, 11):\n    from exceptiongroup import BaseExceptionGroup\n\n\nasync def coro(wait: int, ret: int = 0) -> int:\n    await Timer(wait)\n    return ret\n\n\nclass AwaitableThing:\n    def __init__(self, wait: int, ret: int = 0) -> None:\n        self._wait = wait\n        self._ret = ret\n\n    def __await__(self) -> Generator[Trigger, None, int]:\n        yield from coro(self._wait).__await__()\n        return self._ret\n\n\nclass MyException(Exception): ...\n\n\nasync def raises_after(wait: int) -> None:\n    await Timer(wait)\n    raise MyException()\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_passes(_: object, continue_on_error: bool) -> None:\n    timer = Timer(2)\n\n    with assert_takes(5, \"step\"):\n        async with TaskManager(default_continue_on_error=continue_on_error) as tm:\n            task1 = tm.start_soon(timer)\n            task2 = tm.start_soon(AwaitableThing(3, ret=123))\n            task3 = tm.start_soon(coro(4, ret=456))\n\n            @tm.fork\n            async def task4() -> int:\n                await Timer(5)\n                return 789\n\n    assert task1.done()\n    assert task1.result() == timer\n    assert task2.done()\n    assert task2.result() == 123\n    assert task3.done()\n    assert task3.result() == 456\n    assert task4.done()\n    assert task4.result() == 789\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_no_tasks_passes(_: object, continue_on_error: bool) -> None:\n    async with TaskManager(default_continue_on_error=continue_on_error):\n        pass\n\n\n@cocotb.test\n@cocotb.parametrize(inner_continue_on_error=[True, False])\n@cocotb.parametrize(outer_continue_on_error=[True, False])\nasync def test_nested_passes(\n    _: object, inner_continue_on_error: bool, outer_continue_on_error: bool\n) -> None:\n    timer = Timer(2)\n\n    with assert_takes(8, \"step\"):\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            task_outer = tm_outer.start_soon(coro(8, ret=808))\n\n            with assert_takes(5, \"step\"):\n                async with TaskManager(\n                    default_continue_on_error=inner_continue_on_error\n                ) as tm_inner:\n                    task1 = tm_inner.start_soon(timer)\n                    task2 = tm_inner.start_soon(AwaitableThing(3, ret=123))\n                    task3 = tm_inner.start_soon(coro(4, ret=456))\n\n                    @tm_inner.fork\n                    async def task4() -> int:\n                        await Timer(5)\n                        return 789\n\n    assert task_outer.result() == 808\n    assert task1.result() == timer\n    assert task2.result() == 123\n    assert task3.result() == 456\n    assert task4.result() == 789\n\n\n@cocotb.test\n@cocotb.parametrize(inner_continue_on_error=[True, False])\n@cocotb.parametrize(outer_continue_on_error=[True, False])\nasync def test_nested_in_child_passes(\n    _: object, inner_continue_on_error: bool, outer_continue_on_error: bool\n) -> None:\n    timer = Timer(2)\n\n    task1: Task[Any] | None = None\n    task2: Task[Any] | None = None\n    task3: Task[Any] | None = None\n    task4: Task[Any] | None = None\n\n    async with TaskManager(\n        default_continue_on_error=outer_continue_on_error\n    ) as tm_outer:\n        task_outer = tm_outer.start_soon(coro(5, ret=808))\n\n        @tm_outer.fork\n        async def outer_task() -> None:\n            async with TaskManager(\n                default_continue_on_error=inner_continue_on_error\n            ) as tm_inner:\n                nonlocal task1, task2, task3, task4\n\n                task1 = tm_inner.start_soon(timer)\n                task2 = tm_inner.start_soon(AwaitableThing(3, ret=123))\n                task3 = tm_inner.start_soon(coro(4, ret=456))\n\n                @tm_inner.fork\n                async def task4() -> int:\n                    await Timer(5)\n                    return 789\n\n    assert task_outer.result() == 808\n    assert task1 is not None\n    assert task2 is not None\n    assert task3 is not None\n    assert task4 is not None\n    assert task1.result() == timer\n    assert task2.result() == 123\n    assert task3.result() == 456\n    assert task4.result() == 789\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_failure_in_block(_: object, continue_on_error: bool) -> None:\n    try:\n        async with TaskManager(default_continue_on_error=continue_on_error) as tm:\n            task = tm.start_soon(coro(3, ret=789))\n            raise MyException()\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert rest is None\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n\n    if continue_on_error:\n        assert task.result() == 789\n    else:\n        assert task.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_failure_in_nested_block(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    try:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            task_outer = tm_outer.start_soon(coro(5, ret=9))\n\n            async with TaskManager(\n                default_continue_on_error=inner_continue_on_error\n            ) as tm_inner:\n                task_inner = tm_inner.start_soon(coro(3, ret=789))\n                raise MyException()\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert rest is None\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n\n    if outer_continue_on_error:\n        assert task_outer.result() == 9\n    else:\n        assert task_outer.cancelled()\n\n    if inner_continue_on_error:\n        assert task_inner.result() == 789\n    else:\n        assert task_inner.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_failure_in_nested_child_block(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    task_inner: Task[Any] | None = None\n\n    try:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            task_outer = tm_outer.start_soon(coro(5, ret=9))\n\n            @tm_outer.fork\n            async def inner_block() -> None:\n                async with TaskManager(\n                    default_continue_on_error=inner_continue_on_error\n                ) as tm_inner:\n                    nonlocal task_inner\n                    task_inner = tm_inner.start_soon(coro(3, ret=789))\n\n                    raise MyException()\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert rest is None\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n\n    if outer_continue_on_error:\n        assert task_outer.result() == 9\n    else:\n        assert task_outer.cancelled()\n\n    assert task_inner is not None\n    if inner_continue_on_error:\n        assert task_inner.result() == 789\n    else:\n        assert task_inner.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_child_failure_in_block(_: object, continue_on_error: bool) -> None:\n    takes = 5 if continue_on_error else 1\n\n    with assert_takes(takes, \"step\"):\n        try:\n            async with TaskManager(default_continue_on_error=continue_on_error) as tm:\n                task_failure = tm.start_soon(raises_after(1))\n                task = tm.start_soon(coro(3, ret=789))\n\n                try:\n                    await Timer(5)\n                except CancelledError:\n                    assert not continue_on_error\n                    raise  # can't use pytest.raises as that causes CancelledError to be swallowed\n                else:\n                    assert continue_on_error\n\n        except BaseExceptionGroup as e:\n            my_exc, rest = e.split(MyException)\n            assert rest is None\n            assert my_exc is not None\n            assert len(my_exc.exceptions) == 1\n\n    assert task_failure.exception() is not None\n\n    if continue_on_error:\n        assert task.result() == 789\n    else:\n        assert task.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_child_failure_in_nested_block(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    try:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            task_outer = tm_outer.start_soon(coro(5, ret=9))\n\n            async with TaskManager(\n                default_continue_on_error=inner_continue_on_error\n            ) as tm_inner:\n                task_inner_failure = tm_inner.start_soon(raises_after(1))\n                task_inner = tm_inner.start_soon(coro(3, ret=789))\n\n                try:\n                    await Timer(4)\n                except CancelledError:\n                    assert not inner_continue_on_error\n                    raise  # can't use pytest.raises as that causes CancelledError to be swallowed\n                else:\n                    assert inner_continue_on_error\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert rest is None\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n\n    assert task_inner_failure.exception() is not None\n\n    if outer_continue_on_error:\n        assert task_outer.result() == 9\n    else:\n        assert task_outer.cancelled()\n\n    if inner_continue_on_error:\n        assert task_inner.result() == 789\n    else:\n        assert task_inner.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_child_failure_in_nested_child_block(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    task_inner_failure: Task[Any] | None = None\n    task_inner: Task[Any] | None = None\n\n    try:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            task_outer = tm_outer.start_soon(coro(5, ret=9))\n\n            @tm_outer.fork\n            async def inner_block() -> None:\n                async with TaskManager(\n                    default_continue_on_error=inner_continue_on_error\n                ) as tm_inner:\n                    nonlocal task_inner_failure, task_inner\n                    task_inner_failure = tm_inner.start_soon(raises_after(1))\n                    task_inner = tm_inner.start_soon(coro(3, ret=789))\n\n                    try:\n                        await Timer(4)\n                    except CancelledError:\n                        assert not inner_continue_on_error\n                        raise  # can't use pytest.raises as that causes CancelledError to be swallowed\n                    else:\n                        assert inner_continue_on_error\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert rest is None\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n\n    assert task_inner_failure is not None\n    assert task_inner_failure.exception() is not None\n\n    if outer_continue_on_error:\n        assert task_outer.result() == 9\n    else:\n        assert task_outer.cancelled()\n\n    assert task_inner is not None\n    if inner_continue_on_error:\n        assert task_inner.result() == 789\n    else:\n        assert task_inner.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_child_failure_in_exit(_: object, continue_on_error: bool) -> None:\n    takes = 3 if continue_on_error else 2\n\n    with assert_takes(takes, \"step\"):\n        try:\n            async with TaskManager(default_continue_on_error=continue_on_error) as tm:\n                task_failure = tm.start_soon(raises_after(2))\n                task = tm.start_soon(coro(3, ret=789))\n\n        except BaseExceptionGroup as e:\n            my_exc, rest = e.split(MyException)\n            assert rest is None\n            assert my_exc is not None\n            assert len(my_exc.exceptions) == 1\n\n    assert task_failure.exception() is not None\n\n    if continue_on_error:\n        assert task.result() == 789\n    else:\n        assert task.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_child_failure_in_nested_exit(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    try:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            task_outer = tm_outer.start_soon(coro(5, ret=9))\n\n            async with TaskManager(\n                default_continue_on_error=inner_continue_on_error\n            ) as tm_inner:\n                task_inner_failure = tm_inner.start_soon(raises_after(2))\n                task_inner = tm_inner.start_soon(coro(3, ret=789))\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert rest is None\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n\n    assert task_inner_failure.exception() is not None\n\n    if outer_continue_on_error:\n        assert task_outer.result() == 9\n    else:\n        assert task_outer.cancelled()\n\n    if inner_continue_on_error:\n        assert task_inner.result() == 789\n    else:\n        assert task_inner.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_child_failure_in_nested_child_exit(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    task_inner_failure: Task[Any] | None = None\n    task_inner: Task[Any] | None = None\n    try:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            task_outer = tm_outer.start_soon(coro(5, ret=9))\n\n            @tm_outer.fork\n            async def inner_block() -> None:\n                nonlocal task_inner_failure, task_inner\n                async with TaskManager(\n                    default_continue_on_error=inner_continue_on_error\n                ) as tm_inner:\n                    task_inner_failure = tm_inner.start_soon(raises_after(2))\n                    task_inner = tm_inner.start_soon(coro(3, ret=789))\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert rest is None\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n\n    assert task_inner_failure is not None\n    assert task_inner_failure.exception() is not None\n\n    if outer_continue_on_error:\n        assert task_outer.result() == 9\n    else:\n        assert task_outer.cancelled()\n\n    assert task_inner is not None\n    if inner_continue_on_error:\n        assert task_inner.result() == 789\n    else:\n        assert task_inner.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_external_cancel_in_block(_: object, continue_on_error: bool) -> None:\n    cancelled = False\n    e = Event()\n\n    async def run_task_manager() -> None:\n        async with TaskManager(default_continue_on_error=continue_on_error):\n            try:\n                await e.wait()\n            finally:\n                nonlocal cancelled\n                cancelled = True\n\n    task = cocotb.start_soon(run_task_manager())\n\n    # wait until run_task_manager's TaskManager is blocking\n    await Timer(1)\n\n    # cancel run_task_manager externally\n    task.cancel()\n    await task.complete\n\n    # ensure run_task_manager's children are also cancelled\n    assert cancelled\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_external_cancel_in_nested_block(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    cancelled = False\n    e = Event()\n\n    outer_task: Task[Any] | None = None\n\n    async def run_task_manager() -> None:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            nonlocal outer_task\n            outer_task = tm_outer.start_soon(coro(5, ret=9))\n\n            async with TaskManager(default_continue_on_error=inner_continue_on_error):\n                try:\n                    await e.wait()\n                finally:\n                    nonlocal cancelled\n                    cancelled = True\n\n    task = cocotb.start_soon(run_task_manager())\n\n    # wait until run_task_manager's TaskManager is blocking\n    await Timer(1)\n\n    # cancel run_task_manager externally\n    task.cancel()\n    await task.complete\n\n    # ensure run_task_manager's children are also cancelled\n    assert outer_task is not None\n    assert outer_task.cancelled()\n    assert cancelled\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_external_cancel_in_nested_child_block(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    cancelled = False\n    e = Event()\n\n    outer_task: Task[Any] | None = None\n    inner_block: Task[Any] | None = None\n\n    async def run_task_manager() -> None:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            nonlocal outer_task, inner_block\n            outer_task = tm_outer.start_soon(coro(5, ret=9))\n\n            @tm_outer.fork\n            async def inner_block() -> None:\n                async with TaskManager(\n                    default_continue_on_error=inner_continue_on_error\n                ):\n                    try:\n                        await e.wait()\n                    finally:\n                        nonlocal cancelled\n                        cancelled = True\n\n    task = cocotb.start_soon(run_task_manager())\n\n    # wait until run_task_manager's TaskManager is blocking\n    await Timer(1)\n\n    # cancel run_task_manager externally\n    task.cancel()\n    await task.complete\n\n    # ensure run_task_manager's children are also cancelled\n    assert cancelled\n    assert inner_block is not None\n    assert inner_block.cancelled()\n    assert outer_task is not None\n    assert outer_task.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_external_cancel_in_aexit(_: object, continue_on_error: bool) -> None:\n    inner_task: Task[Any] | None = None\n\n    async def run_task_manager() -> None:\n        async with TaskManager(default_continue_on_error=continue_on_error) as tm:\n            nonlocal inner_task\n            inner_task = tm.start_soon(coro(5, ret=9))\n\n    task = cocotb.start_soon(run_task_manager())\n\n    # wait until run_task_manager's TaskManager is in __aexit__\n    await Timer(1)\n\n    # cancel run_task_manager to see what happens when a TaskManager is cancelled when\n    # waiting for finish in __aexit__\n    task.cancel()\n    await task.complete\n\n    # ensure run_task_manager's children are also cancelled\n    assert inner_task is not None\n    assert inner_task.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_external_cancel_in_nested_aexit(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    outer_task: Task[Any] | None = None\n    inner_task: Task[Any] | None = None\n\n    async def run_task_manager() -> None:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            nonlocal outer_task\n            outer_task = tm_outer.start_soon(coro(5, ret=9))\n\n            async with TaskManager(\n                default_continue_on_error=inner_continue_on_error\n            ) as tm_inner:\n                nonlocal inner_task\n                inner_task = tm_inner.start_soon(coro(5, ret=9))\n\n    task = cocotb.start_soon(run_task_manager())\n\n    # wait until run_task_manager's TaskManager is in __aexit__\n    await Timer(1)\n\n    # cancel run_task_manager to see what happens when a TaskManager is cancelled when\n    # waiting for finish in __aexit__\n    task.cancel()\n    await task.complete\n\n    # ensure run_task_manager's children are also cancelled\n    assert inner_task is not None\n    assert inner_task.cancelled()\n    assert outer_task is not None\n    assert outer_task.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(outer_continue_on_error=[True, False])\n@cocotb.parametrize(inner_continue_on_error=[True, False])\nasync def test_external_cancel_in_nested_child_aexit(\n    _: object, outer_continue_on_error: bool, inner_continue_on_error: bool\n) -> None:\n    outer_task: Task[Any] | None = None\n    inner_task: Task[Any] | None = None\n\n    async def run_task_manager() -> None:\n        async with TaskManager(\n            default_continue_on_error=outer_continue_on_error\n        ) as tm_outer:\n            nonlocal outer_task\n            outer_task = tm_outer.start_soon(coro(5, ret=9))\n\n            @tm_outer.fork\n            async def inner_block() -> None:\n                async with TaskManager(\n                    default_continue_on_error=inner_continue_on_error\n                ) as tm_inner:\n                    nonlocal inner_task\n                    inner_task = tm_inner.start_soon(coro(5, ret=9))\n\n    task = cocotb.start_soon(run_task_manager())\n\n    # wait until run_task_manager's TaskManager is in __aexit__\n    await Timer(1)\n\n    # cancel run_task_manager to see what happens when a TaskManager is cancelled when\n    # waiting for finish in __aexit__\n    task.cancel()\n\n    # ensure run_task_manager's children are cancelled, but outer_task will complete as CancelledError is ignored\n    await task.complete\n    # NullTrigger is necessary since cancellation will cause children to be cancelled,\n    # but we can't wait for cancellation to complete, we must immediately propagate it.\n    await NullTrigger()\n    assert inner_task is not None\n    assert inner_task.result() == 9\n    assert outer_task is not None\n    assert outer_task.cancelled()\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_external_cancel_in_block_ignored_at_end_of_block(\n    _: object,\n    continue_on_error: bool,\n) -> None:\n    async def run_task_manager() -> None:\n        async with TaskManager(default_continue_on_error=continue_on_error):\n            try:\n                await Timer(2)\n            except CancelledError:\n                pass\n\n    task = cocotb.start_soon(run_task_manager())\n\n    # wait until run_task_manager's TaskManager is blocking\n    await Timer(1)\n\n    # cancel run_task_manager externally\n    task.cancel()\n    await task.complete\n    assert not task.cancelled()\n    assert task.exception() is not None\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_external_cancel_in_block_ignored_new_raise(\n    _: object,\n    continue_on_error: bool,\n) -> None:\n    async def run_task_manager() -> None:\n        async with TaskManager(default_continue_on_error=continue_on_error):\n            try:\n                await Timer(2)\n            except CancelledError:\n                raise MyException()\n\n    task = cocotb.start_soon(run_task_manager())\n\n    # wait until run_task_manager's TaskManager is blocking\n    await Timer(1)\n\n    # cancel run_task_manager externally\n    task.cancel()\n    await task.complete\n    assert not task.cancelled()\n    assert task.exception() is not None\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_external_cancel_in_block_ignored_and_await(\n    _: object,\n    continue_on_error: bool,\n) -> None:\n    async def run_task_manager() -> None:\n        async with TaskManager(default_continue_on_error=continue_on_error):\n            try:\n                await Timer(2)\n            except CancelledError:\n                pass\n\n            await Timer(1)\n\n    task = cocotb.start_soon(run_task_manager())\n\n    # wait until run_task_manager's TaskManager is blocking\n    await Timer(1)\n\n    # cancel run_task_manager externally\n    task.cancel()\n    await task.complete\n    assert not task.cancelled()\n    assert task.exception() is not None\n\n\n@cocotb.test\n@cocotb.xfail(raises=RuntimeError, reason=\"Ignored CancelledError\")\nasync def test_child_fails_ignore_cancel_at_end_of_block(_: object) -> None:\n    async with TaskManager() as tm:\n        tm.start_soon(raises_after(1))\n\n        try:\n            await Timer(2)\n        except CancelledError:\n            pass\n\n    await Timer(1)\n\n\n@cocotb.test\n@cocotb.xfail(raises=RuntimeError, reason=\"Ignored CancelledError\")\nasync def test_child_fails_ignore_cancel_and_await(_: object) -> None:\n    async with TaskManager() as tm:\n        tm.start_soon(raises_after(1))\n\n        try:\n            await Timer(2)\n        except CancelledError:\n            pass\n\n        await Timer(1)\n\n\n@cocotb.test\n@cocotb.xfail(raises=RuntimeError, reason=\"Ignored CancelledError\")\nasync def test_child_fails_ignore_cancel_new_raise(_: object) -> None:\n    async with TaskManager() as tm:\n        tm.start_soon(raises_after(1))\n\n        try:\n            await Timer(2)\n        except CancelledError:\n            raise MyException()\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_reused_context(_: object, continue_on_error: bool) -> None:\n    tm = TaskManager(default_continue_on_error=continue_on_error)\n\n    async with tm:\n        tm.start_soon(coro(1))\n\n    with pytest.raises(RuntimeError):\n        async with tm:\n            pass\n\n\n@cocotb.test\nasync def test_start_soon_after_cancel_no_continue(_: object) -> None:\n    try:\n        async with TaskManager(default_continue_on_error=False) as tm:\n            tm.start_soon(raises_after(1))\n\n            try:\n                await Timer(2)\n            finally:\n                c = coro(2)\n                with pytest.raises(RuntimeError):\n                    tm.start_soon(c)\n                c.close()  # avoid ResourceWarning since we didn't await it.\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n        assert rest is None\n\n\n@cocotb.test\nasync def test_start_soon_after_cancel_continue(_: object) -> None:\n    try:\n        async with TaskManager(default_continue_on_error=True) as tm:\n            tm.start_soon(raises_after(1))\n            await Timer(2)\n            tm.start_soon(coro(2))\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n        assert rest is None\n\n\n@cocotb.test\nasync def test_reraised_child_exception(_: object) -> None:\n    try:\n        async with TaskManager(default_continue_on_error=True) as tm:\n            task = tm.start_soon(raises_after(1))\n            # task will raise, but since continue_on_error=True, we will continue,\n            # which will cause this await to re-raise the exception.\n            await task\n\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n        assert rest is None\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_start_soon_outside_context(_: object, continue_on_error: bool) -> None:\n    tm = TaskManager(default_continue_on_error=continue_on_error)\n\n    c = coro(1)\n    with pytest.raises(RuntimeError):\n        tm.start_soon(c)\n    c.close()  # avoid ResourceWarning since we didn't await it.\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_fork_outside_context(_: object, continue_on_error: bool) -> None:\n    async def coro_noargs() -> None:\n        await Timer(1)\n\n    tm = TaskManager(default_continue_on_error=continue_on_error)\n    with pytest.raises(RuntimeError):\n        tm.fork(coro_noargs)\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_add_tasks_from_another_task(_: object, continue_on_error: bool) -> None:\n    async def tm_coro(tm: TaskManager, ev: Event) -> int:\n        async with tm:\n            await ev.wait()\n        return 10\n\n    tm = TaskManager(default_continue_on_error=continue_on_error)\n    ev = Event()\n    tm_task = cocotb.start_soon(tm_coro(tm, ev))\n\n    await NullTrigger()\n\n    c = coro(1)\n    with pytest.raises(RuntimeError):\n        tm.start_soon(c)\n    c.close()  # avoid ResourceWarning since we didn't await it.\n\n    ev.set()\n\n    await tm_task\n    assert tm_task.result() == 10\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_start_soon_after_finished(_: object, continue_on_error: bool) -> None:\n    async with TaskManager(default_continue_on_error=continue_on_error) as tm:\n        tm.start_soon(coro(1))\n\n    c = coro(1)\n    with pytest.raises(RuntimeError):\n        tm.start_soon(c)\n    c.close()  # avoid ResourceWarning since we didn't await it.\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_cancel_child_task_in_block_and_exit(\n    _: object, continue_on_error: bool\n) -> None:\n    cancelled = False\n\n    async with TaskManager(default_continue_on_error=continue_on_error) as tm:\n\n        @tm.fork\n        async def child() -> None:\n            try:\n                await Timer(5)\n            finally:\n                nonlocal cancelled\n                cancelled = True\n\n        await Timer(1)\n        child.cancel()\n\n    assert cancelled\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_cancel_child_task_in_block_and_continue(\n    _: object, continue_on_error: bool\n) -> None:\n    cancelled = False\n\n    async with TaskManager(default_continue_on_error=continue_on_error) as tm:\n\n        @tm.fork\n        async def child() -> None:\n            try:\n                await Timer(5)\n            finally:\n                nonlocal cancelled\n                cancelled = True\n\n        await Timer(1)\n        child.cancel()\n\n        @tm.fork\n        async def other() -> None:\n            await Timer(1)\n\n    assert cancelled\n    assert other.done()\n\n\n@cocotb.test\nasync def test_KeyboardInterrupt_in_block(_: object) -> None:\n    with pytest.raises(KeyboardInterrupt):\n        async with TaskManager() as tm:\n            tm.start_soon(coro(5))\n\n            await Timer(1)\n            raise KeyboardInterrupt()\n\n\n# Can't test KeyboardInterrupt in child Task since that will take a path to shut down\n# the simulation.\n\n\n@cocotb.test\nasync def test_KeyboardInterrupt_in_nested_block(_: object) -> None:\n    with pytest.raises(KeyboardInterrupt):\n        async with TaskManager() as tm_outer:\n            tm_outer.start_soon(coro(5))\n\n            async with TaskManager() as tm_inner:\n                tm_inner.start_soon(coro(5))\n\n                await Timer(1)\n                raise KeyboardInterrupt()\n\n\n@cocotb.test\nasync def test_override_continue_on_error_continue(_: object) -> None:\n    with assert_takes(2, \"step\"):\n        try:\n            async with TaskManager(default_continue_on_error=False) as tm:\n                task1 = tm.start_soon(coro(2, ret=123))\n                task2 = tm.start_soon(raises_after(1), continue_on_error=True)\n        except BaseExceptionGroup as e:\n            my_exc, rest = e.split(MyException)\n            assert rest is None\n            assert my_exc is not None\n            assert len(my_exc.exceptions) == 1\n\n    assert task1.result() == 123\n    assert task2.exception() is not None\n\n\n@cocotb.test\nasync def test_override_continue_on_error_fail(_: object) -> None:\n    with assert_takes(1, \"step\"):\n        try:\n            async with TaskManager(default_continue_on_error=True) as tm:\n                task1 = tm.start_soon(coro(2, ret=123))\n                task2 = tm.start_soon(raises_after(1), continue_on_error=False)\n        except BaseExceptionGroup as e:\n            my_exc, rest = e.split(MyException)\n            assert rest is None\n            assert my_exc is not None\n            assert len(my_exc.exceptions) == 1\n\n    assert task1.cancelled()\n    assert task2.exception() is not None\n\n\n@cocotb.test\nasync def test_override_continue_on_error_fork_continue(_: object) -> None:\n    with assert_takes(2, \"step\"):\n        try:\n            async with TaskManager(default_continue_on_error=False) as tm:\n                task1 = tm.start_soon(coro(2, ret=123))\n\n                @tm.fork(continue_on_error=True)\n                async def task2() -> None:\n                    await raises_after(1)\n        except BaseExceptionGroup as e:\n            my_exc, rest = e.split(MyException)\n            assert rest is None\n            assert my_exc is not None\n            assert len(my_exc.exceptions) == 1\n\n    assert task1.result() == 123\n    assert task2.exception() is not None\n\n\n@cocotb.test\nasync def test_override_continue_on_error_fork_fail(_: object) -> None:\n    with assert_takes(1, \"step\"):\n        try:\n            async with TaskManager(default_continue_on_error=True) as tm:\n                task1 = tm.start_soon(coro(2, ret=123))\n\n                @tm.fork(continue_on_error=False)\n                async def task2() -> None:\n                    await raises_after(1)\n        except BaseExceptionGroup as e:\n            my_exc, rest = e.split(MyException)\n            assert rest is None\n            assert my_exc is not None\n            assert len(my_exc.exceptions) == 1\n\n    assert task1.cancelled()\n    assert task2.exception() is not None\n\n\n@cocotb.test\nasync def test_bad_args(_: object) -> None:\n    async with TaskManager() as tm:\n        with pytest.raises(TypeError):\n            tm.start_soon(123)  # type: ignore\n\n        with pytest.raises(TypeError):\n            tm.fork(123)  # type: ignore\n\n        async def oops_async_generator() -> AsyncGenerator[None, None, None]:\n            yield None\n\n        c = oops_async_generator()\n        with pytest.raises(TypeError):\n            tm.start_soon(c)  # type: ignore\n        await c.aclose()  # avoid ResourceWarning since we didn't await it.\n\n        with pytest.raises(TypeError):\n            tm.fork(oops_async_generator)  # type: ignore\n\n        with pytest.raises(TypeError):\n            tm.start_soon()  # type: ignore\n\n        with pytest.raises(TypeError):\n            tm.fork()  # type: ignore\n\n\n@cocotb.test\n@cocotb.parametrize(continue_on_error=[True, False])\nasync def test_context_block_continue_on_error(\n    _: object, continue_on_error: bool\n) -> None:\n    timer = Timer(2)\n\n    try:\n        async with TaskManager(context_continue_on_error=continue_on_error) as tm:\n            task1 = tm.start_soon(timer)\n            task2 = tm.start_soon(AwaitableThing(3, ret=123))\n            task3 = tm.start_soon(coro(4, ret=456))\n\n            raise MyException()\n    except BaseExceptionGroup as e:\n        my_exc, rest = e.split(MyException)\n        assert rest is None\n        assert my_exc is not None\n        assert len(my_exc.exceptions) == 1\n\n    if continue_on_error:\n        assert task1.result() == timer\n        assert task2.result() == 123\n        assert task3.result() == 456\n    else:\n        assert task1.cancelled()\n        assert task2.cancelled()\n        assert task3.cancelled()\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_testfactory.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests of cocotb.regression.TestFactory functionality\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import Coroutine\n\nimport cocotb\nimport cocotb.regression\n\ntestfactory_test_names = set()\ntestfactory_test_args = set()\n\n\n@cocotb.test\n@cocotb.parametrize(\n    (\"arg1\", [\"a1v1\", \"a1v2\"]), ((\"arg2\", \"arg3\"), [(\"a2v1\", \"a3v1\"), (\"a2v2\", \"a3v2\")])\n)\nasync def run_testfactory_test(dut, arg1, arg2, arg3):\n    testfactory_test_names.add(cocotb.regression._manager_inst._test.name)\n    testfactory_test_args.add((arg1, arg2, arg3))\n\n\n@cocotb.test()\nasync def test_testfactory_verify_args(dut):\n    assert testfactory_test_args == {\n        (\"a1v1\", \"a2v1\", \"a3v1\"),\n        (\"a1v2\", \"a2v1\", \"a3v1\"),\n        (\"a1v1\", \"a2v2\", \"a3v2\"),\n        (\"a1v2\", \"a2v2\", \"a3v2\"),\n    }\n\n\n@cocotb.test\nasync def test_testfactory_verify_names(dut):\n    assert testfactory_test_names == {\n        \"run_testfactory_test/arg1=a1v1/arg2=a2v1/arg3=a3v1\",\n        \"run_testfactory_test/arg1=a1v1/arg2=a2v2/arg3=a3v2\",\n        \"run_testfactory_test/arg1=a1v2/arg2=a2v1/arg3=a3v1\",\n        \"run_testfactory_test/arg1=a1v2/arg2=a2v2/arg3=a3v2\",\n    }\n\n\n@cocotb.test\n@cocotb.parametrize(myarg=[1])\nclass TestClass(Coroutine):\n    def __init__(self, dut, myarg):\n        self._coro = self.run(dut, myarg)\n\n    async def run(self, dut, myarg):\n        assert myarg == 1\n\n    def send(self, value):\n        self._coro.send(value)\n\n    def throw(self, exception):\n        self._coro.throw(exception)\n\n    def __await__(self):\n        yield from self._coro.__await__()\n\n\np_testfactory_test_names = set()\np_testfactory_test_args = set()\n\n\n@cocotb.parametrize(arg1=[\"a1v1\", \"a1v2\"])\n@cocotb.parametrize(arg2=[\"a2v1\", \"a2v2\"])\nasync def p_run_testfactory_test(dut, arg1, arg2):\n    p_testfactory_test_names.add(cocotb.regression._manager_inst._test.name)\n    p_testfactory_test_args.add((arg1, arg2))\n\n\n@cocotb.test()\nasync def test_params_verify_args(dut):\n    assert p_testfactory_test_args == {\n        (\"a1v1\", \"a2v1\"),\n        (\"a1v2\", \"a2v1\"),\n        (\"a1v1\", \"a2v2\"),\n        (\"a1v2\", \"a2v2\"),\n    }\n\n\n@cocotb.test\nasync def test_params_verify_names(dut):\n    assert p_testfactory_test_names == {\n        \"p_run_testfactory_test/arg1=a1v1/arg2=a2v1\",\n        \"p_run_testfactory_test/arg1=a1v1/arg2=a2v2\",\n        \"p_run_testfactory_test/arg1=a1v2/arg2=a2v1\",\n        \"p_run_testfactory_test/arg1=a1v2/arg2=a2v2\",\n    }\n\n\ntestfactory_no_empty_call_test_args = set()\n\n\n@cocotb.test\n@cocotb.parametrize(\n    arg1=[\"a1v1\", \"a1v2\"],\n    arg2=[\"a2v1\", \"a2v2\"],\n)\nasync def test_testfactory_no_empty_call(dut, arg1, arg2):\n    testfactory_no_empty_call_test_args.add((arg1, arg2))\n\n\n@cocotb.test()\nasync def test_testfactory_no_empty_call_verify_args(dut):\n    assert testfactory_no_empty_call_test_args == {\n        (\"a1v1\", \"a2v1\"),\n        (\"a1v2\", \"a2v1\"),\n        (\"a1v1\", \"a2v2\"),\n        (\"a1v2\", \"a2v2\"),\n    }\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests of cocotb.test functionality\n\n* expect_error\n* expect_fail\n* timeout\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom collections.abc import Coroutine\n\nimport pytest\nfrom common import MyBaseException, MyException\n\nimport cocotb\nfrom cocotb.triggers import NullTrigger, SimTimeoutError, Timer\n\n\n@cocotb.test(expect_error=NameError)\nasync def test_error(dut):\n    \"\"\"Error in the test\"\"\"\n    await Timer(100, \"ns\")\n    fail  # noqa\n\n\n# just to be sure...\n@cocotb.test(expect_fail=True)\nasync def test_async_test_can_fail(dut):\n    assert False\n\n\n@cocotb.test()\nasync def test_immediate_test(dut):\n    \"\"\"Test that tests can return immediately\"\"\"\n    return\n\n\n@cocotb.test(expect_fail=True)\nasync def test_assertion_is_failure(dut):\n    assert False\n\n\n@cocotb.test(expect_error=MyException)\nasync def test_expect_particular_exception(dut):\n    raise MyException()\n\n\n@cocotb.test(expect_error=(MyException, ValueError))\nasync def test_expect_exception_list(dut):\n    raise MyException()\n\n\n@cocotb.test(expect_error=SimTimeoutError, timeout_time=1, timeout_unit=\"ns\")\nasync def test_timeout_testdec_fail(dut):\n    await Timer(10, \"ns\")\n\n\n@cocotb.test(timeout_time=100, timeout_unit=\"ns\")\nasync def test_timeout_testdec_pass(dut):\n    await Timer(10, \"ns\")\n\n\n# these tests should run in definition order, not lexicographic order\nlast_ordered_test = None\n\n\n@cocotb.test()\nasync def test_ordering_3(dut):\n    global last_ordered_test\n    val, last_ordered_test = last_ordered_test, 3\n    assert val is None\n\n\n@cocotb.test()\nasync def test_ordering_2(dut):\n    global last_ordered_test\n    val, last_ordered_test = last_ordered_test, 2\n    assert val == 3\n\n\n@cocotb.test()\nasync def test_ordering_1(dut):\n    global last_ordered_test\n    val, last_ordered_test = last_ordered_test, 1\n    assert val == 2\n\n\n@cocotb.test()\nclass TestClass(Coroutine):\n    def __init__(self, dut):\n        self._coro = self.run(dut)\n\n    async def run(self, dut):\n        pass\n\n    def send(self, value):\n        self._coro.send(value)\n\n    def throw(self, exception):\n        self._coro.throw(exception)\n\n    def __await__(self):\n        yield from self._coro.__await__()\n\n\n@cocotb.test()\nasync def test_empty_docstring(dut) -> None:\n    \"\"\"\"\"\"\n\n\n@cocotb.test(expect_fail=True)\nasync def test_pytest_raises_fail(dut):\n    with pytest.raises(AssertionError):\n        assert True\n\n\n@cocotb.test(expect_fail=True)\nasync def test_pytest_warns_fail(dut):\n    def test_func():\n        pass\n\n    with pytest.warns(RuntimeWarning):\n        test_func()\n\n\n@cocotb.test(expect_fail=True)\nasync def test_pytest_deprecated_call_fail(dut):\n    def test_func():\n        pass\n\n    with pytest.deprecated_call():\n        test_func()\n\n\n@cocotb.test(expect_fail=True)\nasync def test_pytest_raises_fail_in_task(dut):\n    async def test_func():\n        with pytest.raises(AssertionError):\n            assert True\n\n    cocotb.start_soon(test_func())\n    await NullTrigger()\n\n\n@cocotb.test(expect_fail=True)\nasync def test_pytest_warns_fail_in_task(dut):\n    def inner_func():\n        pass\n\n    async def test_func():\n        with pytest.warns(RuntimeWarning):\n            inner_func()\n\n    cocotb.start_soon(test_func())\n    await NullTrigger()\n\n\n@cocotb.test(expect_fail=True)\nasync def test_pytest_deprecated_call_fail_in_task(dut):\n    def inner_func():\n        pass\n\n    async def test_func():\n        with pytest.deprecated_call():\n            inner_func()\n\n    cocotb.start_soon(test_func())\n    await NullTrigger()\n\n\n@cocotb.test(expect_error=MyBaseException)\nasync def test_base_exception_expect_fail(dut):\n    raise MyBaseException\n\n\n@cocotb.test(expect_error=MyBaseException)\nasync def test_base_exception_in_task_expect_fail(dut):\n    async def test_func():\n        raise MyBaseException\n\n    cocotb.start_soon(test_func())\n    await NullTrigger()\n\n\na = 0\n\n\n@cocotb.test\nasync def test_without_parenthesis(dut):\n    global a\n    a = 1\n\n\n@cocotb.test()\nasync def test_test_without_parenthesis_ran(dut):\n    assert a == 1\n\n\n@cocotb.test\nasync def test_bad_xfail(dut: object) -> None:\n    with pytest.raises(TypeError):\n\n        @cocotb.xfail(\n            raises=\"not an exception\"  # type: ignore\n        )\n        async def dummy(_: object) -> None:\n            pass\n\n    with pytest.raises(TypeError):\n\n        @cocotb.xfail(\n            raises=[ValueError, \"not an exception\"]  # type: ignore\n        )\n        async def dummy(_: object) -> None:\n            pass\n\n    with pytest.raises(TypeError):\n\n        @cocotb.xfail(\n            raises=object()  # type: ignore\n        )\n        async def dummy(_: object) -> None:\n            pass\n\n\n@cocotb.test\nasync def test_end_in_main_coro(dut: object) -> None:\n    cocotb.end_test(\"Finished test early\")\n    assert False, \"Test should have ended before this assertion\"\n\n\n@cocotb.test\nasync def test_end_in_task(dut: object) -> None:\n    async def end_test() -> None:\n        await Timer(1, unit=\"ns\")\n        cocotb.end_test(\"Finished test early\")\n\n    cocotb.start_soon(end_test())\n    await Timer(10, unit=\"ns\")\n    assert False, \"Test should have ended before this assertion\"\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_timing_triggers.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests related to timing triggers\n\n* Timer\n* ReadWrite\n* ReadOnly\n* NextTimeStep\n* with_timeout\n\"\"\"\n\nfrom __future__ import annotations\n\nimport os\nimport re\nfrom collections.abc import Generator\nfrom decimal import Decimal\nfrom fractions import Fraction\n\nimport pytest\nfrom common import assert_takes\n\nimport cocotb\nfrom cocotb._base_triggers import Trigger\nfrom cocotb.clock import Clock\nfrom cocotb.simulator import get_precision\nfrom cocotb.triggers import (\n    Event,\n    NextTimeStep,\n    NullTrigger,\n    ReadOnly,\n    ReadWrite,\n    RisingEdge,\n    SimTimeoutError,\n    Timer,\n    current_gpi_trigger,\n    with_timeout,\n)\n\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\nSIM_NAME = cocotb.SIM_NAME.lower()\nif LANGUAGE == \"verilog\":\n    INTF = \"vpi\"\nelif SIM_NAME.startswith(\"modelsim\"):\n    INTF = os.environ.get(\"VHDL_GPI_INTERFACE\", \"fli\")\nelse:\n    INTF = \"vhpi\"\n\n\n@cocotb.test()\nasync def test_function_reentrant_clock(dut):\n    \"\"\"Test awaiting a reentrant clock\"\"\"\n    clock = dut.clk\n    timer = Timer(100, \"ns\")\n    for _ in range(10):\n        clock.value = 0\n        await timer\n        clock.value = 1\n        await timer\n\n\n# Xcelium/VHDL does not correctly report the simulator precision.\n# See also https://github.com/cocotb/cocotb/issues/3419\n# NVC does not support setting precision and always uses 1 fs\n# (https://github.com/nickg/nvc/issues/607).\n@cocotb.test(skip=(LANGUAGE == \"vhdl\" and SIM_NAME.startswith((\"xmsim\", \"nvc\"))))\nasync def test_timer_with_units(dut):\n    # The following test assumes a time precision of 1ps. Update the simulator\n    # invocation if this assert hits!\n    assert get_precision() == -12\n    # Await for one simulator time step\n    with assert_takes(1, \"step\"):\n        await Timer(1)  # NOTE: explicitly no units argument here!\n\n    pattern = \"Unable to accurately represent .* with the simulator precision of .*\"\n    with pytest.raises(ValueError, match=pattern):\n        await Timer(2.5, unit=\"step\")\n\n    with assert_takes(3, \"ns\"):\n        await Timer(3, \"ns\")\n\n    with assert_takes(1.5, \"ns\"):\n        await Timer(1.5, \"ns\")\n\n    with assert_takes(10, \"ps\"):\n        await Timer(10.0, \"ps\")\n\n    with assert_takes(1.0, \"us\"):\n        await Timer(1.0, \"us\")\n\n\n@cocotb.test()\nasync def test_timer_with_rational_units(dut):\n    \"\"\"Test that rounding errors are not introduced in exact values\"\"\"\n    # now with fractions\n    with assert_takes(1, \"ns\"):\n        await Timer(Fraction(1, int(1e9)), unit=\"sec\")\n\n    # now with decimals\n    with assert_takes(1, \"ns\"):\n        await Timer(Decimal(\"1e-9\"), unit=\"sec\")\n\n\nasync def do_test_afterdelay_in_readonly(dut, delay):\n    global exited\n    await RisingEdge(dut.clk)\n    exited = True\n\n\n@cocotb.test\nasync def test_cached_write_in_readonly(dut):\n    \"\"\"Test doing invalid sim operation\"\"\"\n    await ReadOnly()\n    with pytest.raises(RuntimeError):\n        dut.stream_in_data.value = 0\n\n\n@cocotb.test\nasync def test_afterdelay_in_readonly_valid(dut):\n    \"\"\"Test Timer delay after ReadOnly phase\"\"\"\n    # This *should* fail on VHPI simulators as it is not a legal transition\n    # but apparently all simulators support it (gh-3967).\n    await ReadOnly()\n    await Timer(1, \"ns\")\n\n\n@cocotb.test()\nasync def test_writes_have_taken_effect_after_readwrite(dut):\n    \"\"\"Test that ReadWrite fires first for the background write coro\"\"\"\n    dut.stream_in_data.value = 0\n\n    async def write_manually():\n        await ReadWrite()\n        # this should overwrite the write written below\n        dut.stream_in_data.value = 2\n\n    # queue a background task to do a manual write\n    waiter = cocotb.start_soon(write_manually())\n\n    # do a delayed write. This will be overwritten\n    dut.stream_in_data.value = 3\n    await waiter\n\n    # check that the write we expected took precedence\n    await ReadOnly()\n    assert dut.stream_in_data.value == 2\n\n\nasync def example() -> int:\n    await Timer(10, \"ns\")\n    return 1\n\n\n@cocotb.test\nasync def test_timeout_func_coro_fail(dut: object) -> None:\n    with pytest.raises(SimTimeoutError):\n        await with_timeout(\n            cocotb.start_soon(example()), timeout_time=1, timeout_unit=\"ns\"\n        )\n\n\n@cocotb.test\nasync def test_timeout_func_coro_pass(dut: object) -> None:\n    res = await with_timeout(\n        cocotb.start_soon(example()), timeout_time=100, timeout_unit=\"ns\"\n    )\n    assert res == 1\n\n\n@cocotb.test\nasync def test_timeout_func_fail(dut: object) -> None:\n    with pytest.raises(SimTimeoutError):\n        await with_timeout(example(), timeout_time=1, timeout_unit=\"ns\")\n\n\n@cocotb.test\nasync def test_timeout_func_pass(dut: object) -> None:\n    res = await with_timeout(example(), timeout_time=100, timeout_unit=\"ns\")\n    assert res == 1\n\n\nclass MyAwaitable:\n    def __await__(self) -> Generator[Trigger, None, int]:\n        yield from Timer(10, \"ns\").__await__()\n        return 42\n\n\n@cocotb.test\nasync def test_timeout_awaitable_fail(dut: object) -> None:\n    with pytest.raises(SimTimeoutError):\n        await with_timeout(MyAwaitable(), timeout_time=1, timeout_unit=\"ns\")\n\n\n@cocotb.test\nasync def test_timeout_awaitable_pass(dut: object) -> None:\n    res = await with_timeout(MyAwaitable(), timeout_time=100, timeout_unit=\"ns\")\n    assert res == 42\n\n\n@cocotb.test()\nasync def test_readwrite(dut):\n    \"\"\"Test that ReadWrite can be waited on\"\"\"\n    # gh-759\n    await Timer(1, \"ns\")\n    dut.clk.value = 1\n    t = ReadWrite()\n    result = await t\n    assert isinstance(result, ReadWrite)\n    assert result is t\n\n\n@cocotb.test()\nasync def test_singleton_isinstance(dut):\n    \"\"\"\n    Test that the result of trigger expression have a predictable type\n    \"\"\"\n    assert isinstance(NextTimeStep(), NextTimeStep)\n    assert isinstance(ReadOnly(), ReadOnly)\n    assert isinstance(ReadWrite(), ReadWrite)\n\n\n@cocotb.test()\nasync def test_timing_trigger_repr(_):\n    nts = NextTimeStep()\n    assert repr(nts) == \"NextTimeStep()\"\n    ro = ReadOnly()\n    assert repr(ro) == \"ReadOnly()\"\n    rw = ReadWrite()\n    assert repr(rw) == \"ReadWrite()\"\n    t = Timer(1)\n    assert re.match(\n        r\"<Timer of \\d+\\.\\d+ps at \\w+>\",\n        repr(t),\n    )\n\n\n@cocotb.test\nasync def test_neg_timer(_):\n    \"\"\"Test negative timer values are forbidden\"\"\"\n    with pytest.raises(ValueError):\n        Timer(-42)  # no need to even `await`, constructing it is an error\n    with pytest.raises(ValueError):\n        Timer(0)\n\n\n@cocotb.test\nasync def test_timer_rounds_to_0(_) -> None:\n    with assert_takes(1, \"step\"):\n        await Timer(0.1, \"step\", round_mode=\"round\")\n\n\n@cocotb.test()\nasync def test_timer_round_mode(_):\n    # test invalid round_mode specifier\n    with pytest.raises(ValueError, match=\"^Invalid round_mode specifier: notvalid\"):\n        Timer(1, \"step\", round_mode=\"notvalid\")\n\n    # test default, update if default changes\n    with pytest.raises(ValueError):\n        Timer(0.5, \"step\")\n\n    # test valid\n    with pytest.raises(ValueError):\n        Timer(0.5, \"step\", round_mode=\"error\")\n    assert Timer(24.0, \"step\", round_mode=\"error\")._sim_steps == 24\n    assert Timer(1.2, \"step\", round_mode=\"floor\")._sim_steps == 1\n    assert Timer(1.2, \"step\", round_mode=\"ceil\")._sim_steps == 2\n    assert Timer(1.2, \"step\", round_mode=\"round\")._sim_steps == 1\n\n    # test with_timeout round_mode\n    with pytest.raises(ValueError):\n        await with_timeout(\n            Timer(1, \"step\"), timeout_time=2.5, timeout_unit=\"step\", round_mode=\"error\"\n        )\n    await with_timeout(\n        Timer(1, \"step\"), timeout_time=2, timeout_unit=\"step\", round_mode=\"error\"\n    )\n    await with_timeout(\n        Timer(1, \"step\"), timeout_time=2.5, timeout_unit=\"step\", round_mode=\"floor\"\n    )\n    await with_timeout(\n        Timer(1, \"step\"), timeout_time=2.5, timeout_unit=\"step\", round_mode=\"ceil\"\n    )\n    await with_timeout(\n        Timer(1, \"step\"), timeout_time=2.5, timeout_unit=\"step\", round_mode=\"round\"\n    )\n\n\n# Riviera VHPI ReadOnly in ValueChange moves to next time step (gh-4119)\n@cocotb.test(expect_fail=SIM_NAME.startswith(\"riviera\") and INTF == \"vhpi\")\nasync def test_readonly_in_valuechange(dut):\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n    await RisingEdge(dut.clk)\n    with assert_takes(0, \"step\"):\n        await ReadOnly()\n\n\n@cocotb.test\nasync def test_readonly_in_timer(dut):\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n    await Timer(3, \"ns\")\n    with assert_takes(0, \"step\"):\n        await ReadOnly()\n\n\n# Riviera VHPI ReadOnly in ReadWrite moves to next time step (gh-4120)\n@cocotb.test(expect_fail=SIM_NAME.startswith(\"riviera\") and INTF == \"vhpi\")\nasync def test_readonly_in_readwrite(dut):\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n    await RisingEdge(dut.clk)\n    with assert_takes(0, \"step\"):\n        await ReadWrite()\n        with assert_takes(0, \"step\"):\n            await ReadOnly()\n\n\n@cocotb.test\nasync def test_current_gpi_trigger(dut) -> None:\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n    assert isinstance(current_gpi_trigger(), Timer)\n    await ReadWrite()\n    assert isinstance(current_gpi_trigger(), ReadWrite)\n    await ReadOnly()\n    assert isinstance(current_gpi_trigger(), ReadOnly)\n    await RisingEdge(dut.clk)\n    assert isinstance(current_gpi_trigger(), RisingEdge)\n    t = current_gpi_trigger()\n\n    e = Event()\n\n    async def check_after_python_trigger() -> None:\n        await e.wait()\n        assert current_gpi_trigger() is t\n\n    cocotb.start_soon(check_after_python_trigger())\n    await NullTrigger()\n    e.set()\n    await Timer(1, \"ns\")\n\n\n@cocotb.test\nasync def test_readwrite_in_readonly(_) -> None:\n    await ReadOnly()\n    with pytest.raises(RuntimeError):\n        await ReadWrite()\n\n\n@cocotb.test\nasync def test_readonly_in_readonly(_) -> None:\n    await ReadOnly()\n    with pytest.raises(RuntimeError):\n        await ReadOnly()\n\n\n@cocotb.test(skip=SIM_NAME.startswith(\"modelsim\"))\nasync def test_next_time_step(_) -> None:\n    \"\"\"Test Timer causes NextTimeStep to wake up after Timer fires.\"\"\"\n\n    # We can't really test if the NextTimeStep is accurate with this test as a part of\n    # the regression. There are many events which will trigger a simulator wakeup. And\n    # for the simulators where cancelling triggers does not work and we just mark them\n    # as \"removed\", the next time step caused by them is unavoidable, making this\n    # totally non-deterministic. This test really exists only to ensure that the code\n    # paths work and the Trigger fires.\n\n    async def wait_ns(time_ns: int) -> None:\n        await Timer(time_ns, \"ns\")\n\n    cocotb.start_soon(wait_ns(10))\n    await NextTimeStep()\n"
  },
  {
    "path": "tests/test_cases/test_cocotb/test_waiters.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nfrom __future__ import annotations\n\nfrom collections.abc import Generator\n\nimport pytest\n\nimport cocotb\nfrom cocotb.triggers import NullTrigger, Timer, Trigger, gather, select, wait\n\n\nasync def coro(wait: int, ret: int = 0) -> int:\n    await Timer(wait)\n    return ret\n\n\nclass AwaitableThing:\n    def __init__(self, wait: int, ret: int = 0) -> None:\n        self._wait = wait\n        self._ret = ret\n\n    def __await__(self) -> Generator[Trigger, None, int]:\n        yield from coro(self._wait).__await__()\n        return self._ret\n\n\nclass MyException(Exception): ...\n\n\nasync def raises_after(wait: int) -> None:\n    await Timer(wait)\n    raise MyException()\n\n\n@cocotb.test\nasync def test_wait(_: object) -> None:\n    a1, b1, c1, d1 = await wait(\n        coro(1),\n        Timer(2),\n        AwaitableThing(3),\n        raises_after(4),\n        return_when=\"ALL_COMPLETED\",\n    )\n    assert a1.done()\n    assert b1.done()\n    assert c1.done()\n    assert d1.exception() is not None\n\n    a2, b2, c2 = await wait(\n        coro(1), Timer(2), AwaitableThing(3), return_when=\"FIRST_EXCEPTION\"\n    )\n    assert a2.done()\n    assert b2.done()\n    assert c2.done()\n\n    a3, b3, c3, d3 = await wait(\n        Timer(1),\n        raises_after(2),\n        AwaitableThing(3),\n        coro(4),\n        return_when=\"FIRST_EXCEPTION\",\n    )\n    # Wait for cancellations to finish\n    await NullTrigger()\n    assert a3.done()\n    assert b3.exception() is not None\n    assert c3.cancelled()\n    assert d3.cancelled()\n\n    a4, b4, c4, d4 = await wait(\n        coro(1),\n        Timer(2),\n        AwaitableThing(3),\n        raises_after(4),\n        return_when=\"FIRST_COMPLETED\",\n    )\n    # Wait for cancellations to finish\n    await NullTrigger()\n    assert a4.done()\n    assert b4.cancelled()\n    assert c4.cancelled()\n    assert d4.cancelled()\n\n\n@cocotb.test\nasync def test_wait_doesnt_cancel_tasks(_: object) -> None:\n    async def completes() -> int:\n        await Timer(10)\n        return 123\n\n    task = cocotb.start_soon(completes())\n    await wait(task, Timer(1), return_when=\"FIRST_COMPLETED\")\n    await NullTrigger()\n    assert not task.cancelled()\n    assert await task == 123\n\n\n@cocotb.test\nasync def test_gather(_: object) -> None:\n    timer1 = Timer(1)\n    a1, b1, c1 = await gather(\n        coro(wait=3, ret=123),\n        AwaitableThing(2, ret=9),\n        timer1,\n    )\n    assert a1 == 123\n    assert b1 == 9\n    assert c1 == timer1\n\n    with pytest.raises(MyException):\n        await gather(\n            raises_after(wait=3),\n            AwaitableThing(2, ret=9),\n            Timer(1),\n        )\n\n    timer2 = Timer(2)\n    a2, b2, c2 = await gather(\n        raises_after(wait=3),\n        AwaitableThing(1, ret=56),\n        timer2,\n        return_exceptions=True,\n    )\n    assert isinstance(a2, MyException)\n    assert b2 == 56\n    assert c2 == timer2\n\n    assert await gather() == ()\n\n\n@cocotb.test\nasync def test_select(_: object) -> None:\n    timer1 = Timer(1)\n    idx, res1 = await select(\n        coro(wait=3, ret=123),\n        AwaitableThing(2, ret=9),\n        timer1,\n    )\n    assert idx == 2\n    assert res1 == timer1\n\n    idx, res2 = await select(\n        raises_after(wait=3),\n        AwaitableThing(1, ret=31),\n        Timer(2),\n        return_exception=True,\n    )\n    assert idx == 1\n    assert res2 == 31\n    await Timer(5)  # ensure failing task was killed\n\n    with pytest.raises(MyException):\n        await select(\n            raises_after(wait=1),\n            AwaitableThing(2, ret=9),\n            Timer(3),\n        )\n\n    idx, res3 = await select(\n        raises_after(wait=1),\n        AwaitableThing(2, ret=12),\n        Timer(3),\n        return_exception=True,\n    )\n    assert idx == 0\n    assert isinstance(res3, MyException)\n\n    with pytest.raises(ValueError):\n        await select()\n\n\n@cocotb.test\nasync def test_cancel_while_waiting(_: object) -> None:\n    async def waiter() -> None:\n        await wait(Timer(2), return_when=\"ALL_COMPLETED\")\n\n    task = cocotb.start_soon(waiter())\n    await Timer(1)\n    task.cancel()\n    await Timer(1)\n"
  },
  {
    "path": "tests/test_cases/test_compare/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/basic_hierarchy_module/Makefile\n\nCOCOTB_TEST_MODULES=test_compare\n"
  },
  {
    "path": "tests/test_cases/test_compare/test_compare.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test for comparing handle classes\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.handle import SimHandleBase, ValueObjectBase\nfrom cocotb.triggers import FallingEdge, RisingEdge\n\n\nclass Testbench:\n    def __init__(self, dut):\n        self.dut = dut\n        self.clkedge = RisingEdge(dut.clk)\n\n    async def initialise(self):\n        \"\"\"Initialise the testbench\"\"\"\n        cocotb.start_soon(Clock(self.dut.clk, 10).start())\n        self.dut.reset.value = 0\n        for _ in range(2):\n            await self.clkedge\n        self.dut.reset.value = 1\n        for _ in range(3):\n            await self.clkedge\n\n\n@cocotb.test()\nasync def test_compare_simhandlebase(dut):\n    \"\"\"Test for SimHandleBase comparisons\"\"\"\n    tb = Testbench(dut)\n    await tb.initialise()\n    for _ in range(3):\n        await tb.clkedge\n\n    # Want to check the __eq__ comparator in SimHandleBase\n    # (overridden in ValueObjectBase)\n    assert isinstance(dut.i_module_a, SimHandleBase)\n    assert not isinstance(dut.i_module_a, ValueObjectBase)\n    assert isinstance(dut.i_module_b, SimHandleBase)\n    assert not isinstance(dut.i_module_b, ValueObjectBase)\n\n    # Same handle\n    assert dut.i_module_a == dut.i_module_a\n    # Different handles\n    assert dut.i_module_a != dut.i_module_b\n    # Compare against non-handle not implemented\n    assert dut.i_module_a.__eq__(1) == NotImplemented\n    assert dut.i_module_a.__ne__(1) == NotImplemented\n\n\n@cocotb.test()\nasync def test_compare_valueobject(dut):\n    \"\"\"Test for ValueObjectBase comparisons.\"\"\"\n    tb = Testbench(dut)\n    await tb.initialise()\n    for _ in range(3):\n        await tb.clkedge\n\n    # Check that all these signals are ValueObjectBase children\n    assert isinstance(dut.counter_plus_two, ValueObjectBase)\n    assert isinstance(dut.counter_plus_five, ValueObjectBase)\n    assert isinstance(dut.clk, ValueObjectBase)\n    assert isinstance(dut.i_module_a.clk, ValueObjectBase)\n\n    # Two different handles\n    assert dut.counter_plus_two != dut.counter_plus_five\n    # Two different handles with the same value\n    # Because they are handles, it is checked if they are the same handle\n    assert dut.clk != dut.i_module_a.clk\n    # A handle and a value\n    # Because one is a value, it is compared against the value of the handle\n    await tb.clkedge\n    assert dut.clk.value == 1\n    assert dut.clk.value != 0\n    await FallingEdge(tb.dut.clk)\n    assert dut.clk.value == 0\n    assert dut.clk.value != 1\n"
  },
  {
    "path": "tests/test_cases/test_configuration/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/vhdl_configurations/Makefile\nCOCOTB_TEST_MODULES = test_configurations\n"
  },
  {
    "path": "tests/test_cases/test_configuration/test_configurations.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test\nasync def test_configuration(dut):\n    for item in dut.dut_inst:\n        cocotb.log.info(\"Found %r\", item)\n"
  },
  {
    "path": "tests/test_cases/test_custom_entry/.gitignore",
    "content": "results.log\n"
  },
  {
    "path": "tests/test_cases/test_custom_entry/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nexport PYTHONPATH := .\nexport PYGPI_USERS := custom_entry:entry_func\n\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t@rm -f results.log\n\t-$(MAKE) all\n\tpython -c 'import filecmp; assert filecmp.cmp(\"results.log\", \"expected_results.log\")'\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_custom_entry/custom_entry.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\n\ndef entry_func() -> None:\n    with open(\"results.log\", \"w\") as file:\n        print(\"got entry\", file=file)\n"
  },
  {
    "path": "tests/test_cases/test_custom_entry/expected_results.log",
    "content": "got entry\n"
  },
  {
    "path": "tests/test_cases/test_deadlock/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES = test_deadlock\n"
  },
  {
    "path": "tests/test_cases/test_deadlock/test_deadlock.py",
    "content": "\"\"\"\nTest that once a simulation failure occurs, no further tests are run\n\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.regression import SimFailure\nfrom cocotb.triggers import RisingEdge\n\n\n@cocotb.test(\n    skip=cocotb.SIM_NAME.lower().startswith(\"riviera\"),  # gh-1859\n    expect_error=SimFailure,\n)\nasync def test_sim_failure_a(dut):\n    # invoke a deadlock, as nothing is driving this clock\n    await RisingEdge(dut.clk)\n\n\n@cocotb.test(\n    skip=cocotb.SIM_NAME.lower().startswith(\"riviera\"),  # gh-1859\n    expect_error=SimFailure,\n)\nasync def test_sim_failure_b(dut):\n    assert False, \"This test should never run\"\n"
  },
  {
    "path": "tests/test_cases/test_defaultless_parameter/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifeq ($(SIM),)\nUSING_ICARUS := 1\nendif\n\nifeq ($(shell echo $(SIM) | tr A-Z a-z),icarus)\nUSING_ICARUS := 1\nendif\n\nifneq ($(USING_ICARUS),)\nICARUS_MIN := 12.0\nICARUS_VERSION := $(shell iverilog -V 2>/dev/null | head -n1 | cut -d ' ' -f 4)\nMIN_VERSION := $(shell printf \"%s\\n%s\\n\" \"$(ICARUS_MIN)\" \"$(ICARUS_VERSION)\" | sort -g | head -1)\nifneq ($(MIN_VERSION),$(ICARUS_MIN))\nSKIP := 1\n$(info \"Skipping test_defaultless_parameter since icarus < v12.0 doesn't support defaultless parameters\")\nendif\nendif\n\nTOPLEVEL_LANG ?= verilog\nifneq ($(TOPLEVEL_LANG),verilog)\nSKIP := 1\n$(info \"Skipping . . . Verilog only\")\nendif\n\nifeq ($(SKIP),)\n\nVERILOG_SOURCES = $(PWD)/test_defaultless_parameter.sv\n# Needed for defaultless parameter support in Xcelium\nexport CADENCE_ENABLE_AVSREQ_44905_PHASE_1=1\nCOCOTB_TOPLEVEL := cocotb_defaultless_parameter\nCOCOTB_TEST_MODULES = test_defaultless_parameter\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nelse\n\nall:\n\t@echo \"Skipping test_defaultless_parameter\"\n\nclean::\n# nothing to clean, just define target in this branch\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_defaultless_parameter/test_defaultless_parameter.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"\nA test to demonstrate defaultless parameter access\n\"\"\"\n\nfrom __future__ import annotations\n\nimport logging\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_params(dut):\n    \"\"\"Test module parameter access\"\"\"\n    tlog = logging.getLogger(\"cocotb.test\")\n\n    tlog.info(\"Checking Parameters:\")\n    assert dut.the_foo.has_default.value == 2\n    assert dut.the_foo.has_no_default.value == 3\n"
  },
  {
    "path": "tests/test_cases/test_defaultless_parameter/test_defaultless_parameter.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\nmodule foo #(\n    parameter int has_default = 7,\n    parameter int has_no_default\n) (\n    input clk\n);\n\nendmodule\n\nmodule cocotb_defaultless_parameter (\n    input clk\n);\n\n    foo #(\n        .has_default (2),\n        .has_no_default (3))\n    the_foo (\n        .clk(clk)\n    );\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_discovery/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES = test_discovery\n"
  },
  {
    "path": "tests/test_cases/test_discovery/test_discovery.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\n\nimport pytest\n\nimport cocotb\nfrom cocotb.handle import (\n    ArrayObject,\n    GPIDiscovery,\n    HierarchyArrayObject,\n    HierarchyObject,\n    Immediate,\n    IntegerObject,\n    LogicArrayObject,\n    StringObject,\n)\nfrom cocotb.triggers import Timer\nfrom cocotb.types import LogicArray\nfrom cocotb_tools.sim_versions import NvcVersion, RivieraVersion, VerilatorVersion\n\nSIM_NAME = cocotb.SIM_NAME.lower()\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\nSIM_VERSION = cocotb.SIM_VERSION\n\nriviera_before_2025_04 = SIM_NAME.startswith(\"riviera\") and RivieraVersion(\n    SIM_VERSION\n) < RivieraVersion(\"2025.04\")\n\n\n# GHDL is unable to access signals in generate loops (gh-2594)\n# Verilator doesn't support vpiGenScope or vpiGenScopeArray (gh-1884)\n# VCS is unable to access signals in generate loops (gh-4328)\n@cocotb.test(\n    expect_error=IndexError\n    if SIM_NAME.startswith(\"ghdl\")\n    else AttributeError\n    if SIM_NAME.startswith(\"verilator\")\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else ()\n)\nasync def pseudo_region_access(dut):\n    \"\"\"Test that pseudo-regions are accessible before iteration\"\"\"\n\n    # Ensure pseudo-region lookup will fail\n    if len(dut._sub_handles) != 0:\n        dut._sub_handles = {}\n\n    dut.genblk1[0]\n\n\ndef verilog_test(skip=False, **kwargs):\n    return cocotb.test(skip=skip or LANGUAGE in [\"vhdl\"], **kwargs)\n\n\nverilator_less_than_5024 = SIM_NAME.startswith(\"verilator\") and VerilatorVersion(\n    cocotb.SIM_VERSION\n) < VerilatorVersion(\"5.024\")\n\n\n# VCS is unable to access signals in generate loops (gh-4328)\n@verilog_test(\n    expect_error=AttributeError\n    if verilator_less_than_5024\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else ()\n)\nasync def test_cond_scope(dut):\n    assert dut.cond_scope.scoped_sub._path == f\"{dut._path}.cond_scope.scoped_sub\"\n\n\n@verilog_test(expect_error=AttributeError)\nasync def test_bad_var(dut):\n    print(dut.cond_scope_else_asdf._path)\n\n\n# VCS is unable to access signals in generate loops (gh-4328)\n@verilog_test(expect_error=IndexError if \"vcs\" in SIM_NAME else ())\nasync def test_arr_scope(dut):\n    assert dut.arr[1].arr_sub._path == f\"{dut._path}.arr[1].arr_sub\"\n\n\n# VCS is unable to access signals in generate loops\n@verilog_test(\n    expect_error=AttributeError\n    if verilator_less_than_5024\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else ()\n)\nasync def test_nested_scope(dut):\n    assert (\n        dut.outer_scope[1].inner_scope[1]._path\n        == f\"{dut._path}.outer_scope[1].inner_scope[1]\"\n    )\n\n\n# VCS is unable to access signals in generate loops\n@verilog_test(\n    expect_error=AttributeError\n    if verilator_less_than_5024\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else (),\n)\nasync def test_scoped_params(dut):\n    assert dut.cond_scope.scoped_param.value == 1\n    assert dut.outer_scope[1].outer_param.value == 2\n    assert dut.outer_scope[1].inner_scope[1].inner_param.value == 3\n\n\n@verilog_test(\n    expect_error=AttributeError\n    if verilator_less_than_5024\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else (),\n    expect_fail=SIM_NAME.startswith(\"riviera\"),\n)\nasync def test_intf_array(dut):\n    assert len(dut.intf_arr) == 2\n    for i, intf in enumerate(dut.intf_arr):\n        assert intf._name == f\"intf_arr[{i}]\"\n        assert intf._path == f\"{dut._path}.intf_arr[{i}]\"\n\n\nquesta_vhpi = (\n    SIM_NAME.startswith(\"modelsim\") and os.getenv(\"VHDL_GPI_INTERFACE\", \"fli\") == \"vhpi\"\n)\n\n\n@cocotb.test(\n    # Questa VHPI reports vhpiIsUpP incorrectly (gh-4236)\n    expect_error=IndexError if questa_vhpi else ()\n)\nasync def recursive_discover(dut):\n    \"\"\"Discover absolutely everything in the DUT\"\"\"\n\n    def _discover(obj):\n        if not isinstance(obj, (HierarchyObject, HierarchyArrayObject, ArrayObject)):\n            return\n        for thing in obj:\n            cocotb.log.debug(\"Found %s (%s)\", thing._name, type(thing))\n            _discover(thing)\n\n    _discover(dut)\n\n\nclass ScopeMissingError(Exception):\n    pass\n\n\nclass ScopeModuleMissingError(Exception):\n    pass\n\n\n# VCS is unable to access signals in generate loops\n@verilog_test(\n    expect_error=AttributeError if \"vcs\" in SIM_NAME else ScopeMissingError,\n    skip=verilator_less_than_5024,\n)\nasync def test_both_conds(dut):\n    \"\"\"\n    Xcelium returns invalid scopes with vpi_handle_by_name(), which will segfault if iterated\n    This is now accounted for in VpiImpl.cpp\n    \"\"\"\n    assert dut.cond_scope.scoped_sub._path == f\"{dut._path}.cond_scope.scoped_sub\"\n\n    try:\n        print(dut.cond_scope_else._path)\n    except AttributeError as e:\n        raise ScopeMissingError from e\n\n    try:\n        print(dut.cond_scope_else.scoped_sub_else._path)\n    except AttributeError as e:\n        raise ScopeModuleMissingError from e\n\n\n@cocotb.test()\nasync def discover_module_values(dut):\n    \"\"\"Discover everything in the DUT\"\"\"\n    count = 0\n    for _ in dut:\n        count += 1\n    assert count >= 2, \"Expected to discover things in the DUT\"\n\n\n@cocotb.test()\nasync def discover_value_not_in_dut(dut):\n    \"\"\"Try and get a value from the DUT that is not there\"\"\"\n    with pytest.raises(AttributeError):\n        dut.fake_signal\n\n\n@cocotb.test()\nasync def access_signal(dut):\n    \"\"\"Access a signal using the assignment mechanism\"\"\"\n    dut.stream_in_data.value = Immediate(1)\n    await Timer(1, \"ns\")\n    assert dut.stream_in_data.value == 1\n\n\n@cocotb.test(skip=LANGUAGE in [\"vhdl\"])\nasync def access_type_bit_verilog(dut):\n    \"\"\"Access type bit in SystemVerilog\"\"\"\n    await Timer(1, \"step\")\n    assert dut.mybit.value == 1, \"The default value was incorrect\"\n    dut.mybit.value = 0\n    await Timer(1, \"ns\")\n    assert dut.mybit.value == 0, \"The assigned value was incorrect\"\n\n    assert dut.mybits.value == 0b11, \"The default value was incorrect\"\n    dut.mybits.value = 0b00\n    await Timer(1, \"ns\")\n    assert dut.mybits.value == 0b00, \"The assigned value was incorrect\"\n\n    assert dut.mybits_uninitialized.value == 0b00, \"The default value was incorrect\"\n    dut.mybits_uninitialized.value = 0b11\n    await Timer(1, \"ns\")\n    assert dut.mybits_uninitialized.value == 0b11, \"The assigned value was incorrect\"\n\n\n@cocotb.test(skip=LANGUAGE in [\"vhdl\"])\nasync def access_type_bit_verilog_metavalues(dut):\n    \"\"\"Access type bit in SystemVerilog with metavalues that the type does not support.\n\n    Note that some simulators (wrongly) allow metavalues even for bits when taking the VPI route.\n    The metavalues still may show up as `0` and `1` in HDL (Xcelium and Riviera).\n    \"\"\"\n    await Timer(1, \"ns\")\n    dut.mybits.value = LogicArray(\"XZ\")\n    await Timer(1, \"ns\")\n    if SIM_NAME.startswith((\"icarus\", \"ncsim\", \"xmsim\")):\n        assert dut.mybits.value == \"xz\"\n    elif SIM_NAME.startswith((\"riviera\",)):\n        assert dut.mybits.value == \"10\"\n    else:\n        assert dut.mybits.value == \"00\"\n\n    dut.mybits.value = LogicArray(\"ZX\")\n    await Timer(1, \"ns\")\n    if SIM_NAME.startswith((\"icarus\", \"ncsim\", \"xmsim\")):\n        assert dut.mybits.value == \"zx\"\n    elif SIM_NAME.startswith((\"riviera\",)):\n        assert dut.mybits.value == \"01\"\n    else:\n        assert dut.mybits.value == \"00\"\n\n\n# Riviera < 2025.04 discovers integers as nets (gh-2597)\n# GHDL discovers integers as nets (gh-2596)\n# Icarus does not support integer signals (gh-2598)\n@cocotb.test(\n    expect_error=AttributeError if SIM_NAME.startswith(\"icarus\") else (),\n    expect_fail=(riviera_before_2025_04 and LANGUAGE in [\"verilog\"])\n    or SIM_NAME.startswith((\"ghdl\", \"verilator\")),\n)\nasync def access_integer(dut):\n    \"\"\"Integer should show as an IntegerObject\"\"\"\n    assert isinstance(dut.stream_in_int, IntegerObject)\n\n\n@cocotb.test(skip=LANGUAGE in [\"verilog\"])\nasync def access_ulogic(dut):\n    \"\"\"Access a std_ulogic as enum\"\"\"\n    dut.stream_in_valid\n\n\n# GHDL discovers generics as vpiParameter (gh-2722)\n@cocotb.test(\n    skip=LANGUAGE in [\"verilog\"],\n    expect_fail=SIM_NAME.startswith(\"ghdl\"),\n)\nasync def access_constant_integer(dut):\n    \"\"\"\n    Access a constant integer\n    \"\"\"\n    assert isinstance(dut.isample_module1.EXAMPLE_WIDTH, IntegerObject)\n    assert dut.isample_module1.EXAMPLE_WIDTH.value == 7\n\n\n# GHDL discovers generics as vpiParameter (gh-2722)\n@cocotb.test(\n    skip=LANGUAGE in [\"verilog\"],\n    expect_fail=SIM_NAME.startswith(\"ghdl\"),\n)\nasync def access_constant_string_vhdl(dut):\n    \"\"\"Access to a string, both constant and signal.\"\"\"\n    constant_string = dut.isample_module1.EXAMPLE_STRING\n    assert isinstance(constant_string, StringObject)\n    assert constant_string.value == b\"TESTING\"\n\n\n# GHDL discovers strings as vpiNetArray (gh-2584)\n@cocotb.test(\n    skip=LANGUAGE in [\"verilog\"],\n    expect_fail=SIM_NAME.startswith(\"ghdl\"),\n)\nasync def test_writing_string_undersized(dut):\n    assert isinstance(dut.stream_in_string, StringObject)\n    test_string = b\"cocotb\"\n    dut.stream_in_string.value = Immediate(test_string)\n    assert dut.stream_out_string.value == b\"\"\n    await Timer(1, \"ns\")\n    assert dut.stream_out_string.value == test_string\n\n\n# GHDL discovers strings as vpiNetArray (gh-2584)\n@cocotb.test(\n    skip=LANGUAGE in [\"verilog\"],\n    expect_fail=SIM_NAME.startswith(\"ghdl\"),\n)\nasync def test_writing_string_oversized(dut):\n    assert isinstance(dut.stream_in_string, StringObject)\n    test_string = b\"longer_than_the_array\"\n    dut.stream_in_string.value = Immediate(test_string)\n    await Timer(1, \"ns\")\n    assert dut.stream_out_string.value == test_string[: len(dut.stream_out_string)]\n\n\n# TODO: add tests for Verilog \"string_input_port\" and \"STRING_LOCALPARAM\" (see issue #802)\n\n\n@cocotb.test(\n    skip=LANGUAGE in [\"vhdl\"] or SIM_NAME.startswith(\"riviera\"),\n    expect_error=AttributeError if SIM_NAME.startswith(\"icarus\") else (),\n)\nasync def access_const_string_verilog(dut):\n    \"\"\"Access to a const Verilog string.\"\"\"\n\n    await Timer(10, \"ns\")\n    assert isinstance(dut.STRING_CONST, StringObject)\n    assert dut.STRING_CONST.value == b\"TESTING_CONST\"\n\n    dut.STRING_CONST.value = b\"MODIFIED\"\n    await Timer(10, \"ns\")\n    assert dut.STRING_CONST.value != b\"TESTING_CONST\"\n\n\n@cocotb.test(\n    skip=LANGUAGE in [\"vhdl\"],\n    expect_error=AttributeError if SIM_NAME.startswith(\"icarus\") else (),\n)\nasync def access_var_string_verilog(dut):\n    \"\"\"Access to a var Verilog string.\"\"\"\n\n    await Timer(10, \"ns\")\n    assert isinstance(dut.STRING_VAR, StringObject)\n    assert dut.STRING_VAR.value == b\"TESTING_VAR\"\n\n    dut.STRING_VAR.value = b\"MODIFIED\"\n    await Timer(10, \"ns\")\n    assert dut.STRING_VAR.value == b\"MODIFIED\"\n\n\n# GHDL discovers generics as vpiParameter (gh-2722)\n@cocotb.test(\n    skip=LANGUAGE in [\"verilog\"],\n    expect_fail=SIM_NAME.startswith(\"ghdl\"),\n)\nasync def access_constant_boolean(dut):\n    \"\"\"Test access to a constant boolean\"\"\"\n    assert isinstance(dut.isample_module1.EXAMPLE_BOOL, IntegerObject)\n    assert bool(dut.isample_module1.EXAMPLE_BOOL.value) is True\n\n\n# GHDL discovers booleans as vpiNet (gh-2596)\n@cocotb.test(\n    skip=LANGUAGE in [\"verilog\"],\n    expect_fail=SIM_NAME.startswith(\"ghdl\"),\n)\nasync def access_boolean(dut):\n    \"\"\"Test access to a boolean\"\"\"\n    assert isinstance(dut.stream_out_bool, IntegerObject)\n\n    curr_val = dut.stream_in_bool.value\n    dut.stream_in_bool.value = Immediate(not curr_val)\n    await Timer(1, \"ns\")\n    assert curr_val != dut.stream_out_bool.value\n\n\n@cocotb.test(skip=LANGUAGE in [\"vhdl\"])\nasync def access_internal_register_array(dut):\n    \"\"\"Test access to an internal register array\"\"\"\n    assert isinstance(dut.register_array[1], LogicArrayObject)\n    dut.register_array[1].value = 4\n    await Timer(1, \"ns\")\n    assert dut.register_array[1].value == 4\n\n\n@cocotb.test(\n    skip=LANGUAGE in [\"vhdl\"],\n    expect_error=AttributeError if SIM_NAME.startswith((\"icarus\", \"verilator\")) else (),\n)\nasync def access_gate(dut) -> None:\n    \"\"\"Test access to a gate Object\"\"\"\n    assert isinstance(dut.test_and_gate, HierarchyObject)\n\n\n# GHDL is unable to access record types (gh-2591)\n@cocotb.test(\n    skip=LANGUAGE in [\"verilog\"],\n    expect_error=AttributeError if SIM_NAME.startswith(\"ghdl\") else (),\n)\nasync def custom_type(dut):\n    \"\"\"\n    Test iteration over a custom type\n    \"\"\"\n    # Hardcoded to ensure correctness\n    expected_inner = 7\n    expected_outer = 4\n    expected_elem = 11\n\n    outer_count = 0\n    for inner_array in dut.cosLut:\n        inner_count = 0\n        for elem in inner_array:\n            assert len(elem) == expected_elem\n            inner_count += 1\n        assert inner_count == expected_inner\n        outer_count += 1\n    assert expected_outer == outer_count\n\n\n@cocotb.test(skip=LANGUAGE in [\"vhdl\"])\nasync def type_check_verilog(dut):\n    \"\"\"\n    Test if types are recognized\n    \"\"\"\n\n    test_handles = [\n        (dut.stream_in_ready, \"GPI_LOGIC\"),\n        (dut.register_array, \"GPI_ARRAY\"),\n        (dut.temp, \"GPI_PACKED_OBJECT\"),\n        (dut.logic_b, \"GPI_LOGIC\"),\n        (dut.logic_c, \"GPI_LOGIC\"),\n        (dut.INT_PARAM, \"GPI_PACKED_OBJECT\"),\n        (dut.REAL_PARAM, \"GPI_REAL\"),\n        (dut.stream_in_data, \"GPI_PACKED_OBJECT\"),\n        (dut.and_output, \"GPI_LOGIC\"),\n        (dut.logic_a, \"GPI_LOGIC\"),\n    ]\n\n    # Verilator returns vpiReg rather than vpiNet\n    # Verilator (correctly) treats parameters with implicit type, that are assigned a string literal value, as an unsigned integer. See IEEE 1800-2017 Section 5.9 and Section 6.20.2\n    if SIM_NAME.startswith(\"verilator\"):\n        test_handles.append((dut.STRING_PARAM, \"GPI_PACKED_OBJECT\"))\n    else:\n        test_handles.append((dut.STRING_PARAM, \"GPI_STRING\"))\n\n    for handle, expected in test_handles:\n        if isinstance(expected, tuple):\n            assert handle._type in expected\n        else:\n            assert handle._type == expected\n\n\n# GHDL cannot find signal in \"block\" statement, may be related to (gh-2594)\n@cocotb.test(\n    skip=LANGUAGE in [\"verilog\"],\n    expect_error=AttributeError if SIM_NAME.startswith(\"ghdl\") else (),\n)\nasync def access_block_vhdl(dut):\n    \"\"\"Access a VHDL block statement\"\"\"\n\n    dut.isample_module1.SAMPLE_BLOCK\n    dut.isample_module1.SAMPLE_BLOCK.clk_inv\n\n\n@cocotb.test(skip=LANGUAGE in [\"verilog\"])\nasync def discover_all_in_component_vhdl(dut):\n    \"\"\"Access a non local indexed name\"\"\"\n\n    questa_vhpi = (\n        SIM_NAME.startswith(\"modelsim\")\n        and os.getenv(\"VHDL_GPI_INTERFACE\", \"fli\") == \"vhpi\"\n    )\n\n    def _discover(obj):\n        if questa_vhpi and isinstance(obj, StringObject):\n            # Iterating over the elements of a string with Questa's VHPI causes a stacktrace\n            return 0\n        if not isinstance(obj, (HierarchyObject, HierarchyArrayObject, ArrayObject)):\n            return 0\n        count = 0\n        for thing in obj:\n            count += 1\n            cocotb.log.info(\"Found %s (%s)\", thing._path, type(thing))\n            count += _discover(thing)\n        return count\n\n    total_count = _discover(dut.isample_module1)\n\n    sim = SIM_NAME\n\n    # ideally should be 9:\n    #   1   EXAMPLE_STRING\n    #   1   EXAMPLE_BOOL\n    #   1   EXAMPLE_WIDTH\n    #   1   clk\n    #   1   stream_in_data\n    #   1   stream_out_data_registered\n    #   1   stream_out_data_valid\n    #   1   SAMPLE_BLOCK\n    #   1   SAMPLE_BLOCK.clk_inv\n    if sim.startswith(\"ghdl\"):\n        # finds SAMPLE_BLOCK twice\n        assert total_count == 10\n    elif sim.startswith(\"nvc\") and NvcVersion(cocotb.SIM_VERSION) < NvcVersion(\n        \"1.16.0\"\n    ):\n        # old versions of NVC find clk_inv twice\n        assert total_count == 10\n    else:\n        assert total_count == 9\n\n\n@cocotb.test(expect_error=ValueError)\nasync def test_invalid_discovery_method(dut):\n    \"\"\"Try accessing with an enum value for GPIDiscovery out of bounds.\"\"\"\n    dut._handle.get_handle_by_name(\"testsignal\", 5)\n\n\n@cocotb.test()\nasync def test_none_return_on_invalid_signal(dut):\n    \"\"\"Try accessing a signal that does not exist and make sure we get None back.\"\"\"\n    assert dut._handle.get_handle_by_name(\"notexistingsignal\") is None\n    assert (\n        dut._handle.get_handle_by_name(\"notexistingsignal\", GPIDiscovery.AUTO) is None\n    )\n    assert (\n        dut._handle.get_handle_by_name(\"notexistingsignal\", GPIDiscovery.NATIVE) is None\n    )\n\n\n@cocotb.test()\nasync def test_native_discovery(dut):\n    \"\"\"Try accessing a signal using native strategy.\"\"\"\n    assert dut._handle.get_handle_by_name(\"stream_in_data\") is not None\n    assert (\n        dut._handle.get_handle_by_name(\"stream_in_data\", GPIDiscovery.AUTO) is not None\n    )\n    assert (\n        dut._handle.get_handle_by_name(\"stream_in_data\", GPIDiscovery.NATIVE)\n        is not None\n    )\n"
  },
  {
    "path": "tests/test_cases/test_dumpfile_verilator/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\nSIM ?= verilator\nEXTRA_ARGS += --trace\n\nifneq ($(SIM),verilator)\n\nall:\n\t@echo \"Skipping test due to SIM=$(SIM) not being Verilator\"\nclean::\n\nelse\n\nVERILOG_SOURCES = $(PWD)/test_dumpfile_verilator.sv\nCOCOTB_TOPLEVEL = test_dumpfile_verilator\nCOCOTB_TEST_MODULES = test_dumpfile_verilator\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_dumpfile_verilator/test_dumpfile_verilator.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015, 2018 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom pathlib import Path\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import ClockCycles, Timer\n\n\nasync def reset_dut(reset_n, duration_ns):\n    reset_n.value = 0\n    await Timer(duration_ns)\n    reset_n.value = 1\n    cocotb.log.debug(\"Reset complete\")\n\n\n@cocotb.test()\nasync def test_dumpfile_verilator(dut):\n    await reset_dut(dut.reset_n, 20)\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n    await ClockCycles(dut.clk, 0xFF)\n\n    # check that the vcd file exists and that therefore the\n    # $dumfiles and $dumpargs are working\n    assert Path(\"waves.vcd\").exists()\n"
  },
  {
    "path": "tests/test_cases/test_dumpfile_verilator/test_dumpfile_verilator.sv",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n/*\nTest the verilog dumpfile and dumpargs in combination with cocotb\n*/\n\n`timescale 1ns / 1ps\n\nmodule test_dumpfile_verilator (\n    input clk,\n    input reset_n\n);\n\n  reg [31:0] counter;\n\n  always_ff @(posedge clk) begin\n    if (!reset_n) begin\n      counter <= 32'h0;\n    end else begin\n      counter <= counter + 1;\n    end\n  end\n\n  initial begin\n    $dumpfile(\"waves.vcd\");\n    $dumpvars(0, test_custom_vcd);\n  end\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_exit_error/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# detecting an expected failure has to happen here, as the python code is invalid\n.PHONY: override_for_this_test\noverride_for_this_test:\n\tif $(MAKE) all; then echo \"Expected this to fail\"; false; else echo \"Failed as expected\"; fi\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES = test_exit\n"
  },
  {
    "path": "tests/test_cases/test_exit_error/test_exit.py",
    "content": "from __future__ import annotations\n\nimport cocotb\nfrom cocotb.triggers import Timer\n\n\n@cocotb.test()\nasync def test_name_error(_):\n    # the exception makes the whole file unimportable, so the file contents\n    # don't really matter.\n    await Timer(100, \"ns\")\n\n\nraise Exception\n"
  },
  {
    "path": "tests/test_cases/test_failure/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCOCOTB_TEST_MODULES := test_failure\n\n# ensure the test runs, squash any error code, and ensure a failing test was reported\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t-$(MAKE) all\n\t$(call check_for_results_file)\n\ttest $$(python -m cocotb_tools.combine_results | grep \"Failure in testsuite\" | wc -l) -eq 9 && rm -f results.xml\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_failure/test_failure.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests the failure path for tests in the regression.py and xunit_reporter.py.\n\nThe Makefile in this folder is specially set up to squash any error code due\nto a failing test and ensures the failing test is reported properly.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_fail(_: object) -> None:\n    assert False\n\n\n@cocotb.test(expect_fail=True)\nasync def test_pass_expect_fail(_: object) -> None:\n    assert True\n\n\n@cocotb.test(expect_error=Exception)\nasync def test_pass_expect_error(_: object) -> None:\n    assert True\n\n\n@cocotb.test(expect_error=ValueError)\nasync def test_wrong_error(_: object) -> None:\n    raise TypeError\n\n\n@cocotb.test(expect_fail=True)\nasync def test_expect_fail_but_errors(_: object) -> None:\n    raise Exception()\n\n\n@cocotb.test\nasync def test_exception_with_nonprintable_characters(_: object) -> None:\n    raise Exception(\"This is bad! \\x00\\x0b\\x80\")\n\n\n@cocotb.test(expect_error=TypeError)\nasync def test_expect_error_get_failure(dut: object) -> None:\n    assert False\n\n\n@cocotb.test(expect_error=Exception)\nasync def test_end_test_with_expect_error(_: object) -> None:\n    cocotb.end_test()\n\n\n@cocotb.test(expect_fail=True)\nasync def test_end_test_with_expect_fail(_: object) -> None:\n    cocotb.end_test()\n"
  },
  {
    "path": "tests/test_cases/test_fatal/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\nCOCOTB_TOPLEVEL := fatal\nCOCOTB_TEST_MODULES := test_fatal\n\nPWD=$(shell pwd)\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    VERILOG_SOURCES := $(PWD)/fatal.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    VHDL_SOURCES := $(PWD)/fatal.vhd\n    ifneq ($(filter $(SIM),ius xcelium),)\n        COMPILE_ARGS += -v93\n    endif\nendif\n\nifeq ($(shell echo $(SIM) | tr A-Z a-z),verilator)\n    COMPILE_ARGS += --timing\nendif\n\n# squash error code from simulator and ensure the cocotb test passed\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t-$(MAKE) all\n\t$(call check_for_results_file)\n\tpython -m cocotb_tools.combine_results &> /dev/null\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "tests/test_cases/test_fatal/fatal.sv",
    "content": "//-----------------------------------------------------------------------------\n// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n//-----------------------------------------------------------------------------\n\n`timescale 1 ps / 1 ps\n\nmodule fatal (\n    input clk\n);\n\ninitial begin\n    #10 $fatal(1, \"This is a fatal message that finishes the test\");\nend\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_fatal/fatal.vhd",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nentity fatal is\nend entity fatal;\n\narchitecture behav of fatal is\nbegin\n\n\tfatal_proc : process is\n\tbegin\n\t\twait for 10 ns;\n\t\treport \"This is a fatal message that finishes the test\" severity FAILURE;\n\tend process fatal_proc;\n\nend architecture behav;\n"
  },
  {
    "path": "tests/test_cases/test_fatal/test_fatal.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.regression import SimFailure\nfrom cocotb.triggers import Timer\n\n\n@cocotb.test(expect_error=SimFailure)\nasync def test_fatal(_):\n    await Timer(100, \"ns\")\n"
  },
  {
    "path": "tests/test_cases/test_first_on_coincident_triggers/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\nCOCOTB_TOPLEVEL := test\nCOCOTB_TEST_MODULES := test_first_on_coincident_triggers\n\nPWD=$(shell pwd)\n\nifeq ($(TOPLEVEL_LANG),verilog)\n    VERILOG_SOURCES := $(PWD)/test.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\n    VHDL_SOURCES := $(PWD)/test.vhd\n    ifneq ($(filter $(SIM),ius xcelium),)\n        COMPILE_ARGS += -v93\n    endif\nendif\n\nifeq ($(shell echo $(SIM) | tr A-Z a-z),verilator)\n    COMPILE_ARGS += --timing\nendif\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "tests/test_cases/test_first_on_coincident_triggers/test.sv",
    "content": "//-----------------------------------------------------------------------------\n// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n//-----------------------------------------------------------------------------\n\nmodule test;\n\nreg a, b;\n\nalways begin\n    a <= 0;\n    b <= 0;\n    #10;\n    a <= 1;\n    b <= 1;\n    #10;\nend\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_first_on_coincident_triggers/test.vhd",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nentity test is\nend entity test;\n\narchitecture behav of test is\n    signal a : bit;\n    signal b : bit;\nbegin\n    process begin\n        a <= '0';\n        b <= '0';\n        wait for 10 ns;\n        a <= '1';\n        b <= '1';\n        wait for 10 ns;\n    end process;\nend architecture behav;\n"
  },
  {
    "path": "tests/test_cases/test_first_on_coincident_triggers/test_first_on_coincident_triggers.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport logging\nimport os\nimport unittest\n\nimport cocotb\nfrom cocotb.triggers import First, RisingEdge, Timer\nfrom cocotb.utils import get_sim_time\n\nSIM_NAME = cocotb.SIM_NAME.lower()\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\nVHDL_INTF = os.environ.get(\"VHDL_GPI_INTERFACE\", \"fli\").strip()\n\n\n@cocotb.test()\nasync def test_first_on_coincident_trigger(dut) -> None:\n    try:\n        with unittest.TestCase().assertLogs(\n            \"cocotb.scheduler\", level=logging.CRITICAL\n        ) as logs:\n            await First(\n                RisingEdge(dut.a),\n                RisingEdge(dut.b),\n            )\n            await Timer(10, \"ns\")\n    except AssertionError:\n        pass  # no CRITICAL logs is good\n    else:\n        # if there are CRITICAL logs, check for the one that indicated the problem\n        assert (\n            \"No coroutines waiting on trigger that fired\" not in logs.records[0].message\n        )\n\n\n@cocotb.xfail(\n    SIM_NAME.startswith(\"nvc\"),\n    reason=\"NVC doesn't fire second RisingEdge trigger for dut.b when it is registered the same time step that a change occurred (gh-5112)\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"verilator\"),\n    reason=\"Verilator doesn't fire second RisingEdge trigger for dut.b when it is registered the same time step that a change occurred (gh-5112)\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"riviera\"),\n    reason=\"Riviera doesn't fire second RisingEdge trigger for dut.b when it is registered the same time step that a change occurred (gh-5112)\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"xmsim\") and LANGUAGE in [\"vhdl\"],\n    reason=\"xcelium doesn't fire second RisingEdge trigger for dut.b when it is registered the same time step that a change occurred (gh-5112)\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"modelsim\") and LANGUAGE in [\"vhdl\"] and VHDL_INTF in [\"vhpi\"],\n    reason=\"Questa doesn't fire second RisingEdge trigger for dut.b when it is registered the same time step that a change occurred (gh-5112)\",\n)\n@cocotb.skipif(\n    SIM_NAME.startswith(\"modelsim\") and LANGUAGE in [\"vhdl\"] and VHDL_INTF in [\"fli\"],\n    reason=\"Questa will segfault\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"ghdl\"),\n    reason=\"GHDL doesn't fire second RisingEdge trigger for dut.b when it is registered the same time step that a change occurred (gh-5112)\",\n)\n# Setting timeout because even though GHDL fails the test correctly, it gets stuck and doesn't finish simulation (gh-4997)\n@cocotb.test(timeout_time=100, timeout_unit=\"ns\")\nasync def test_repeated_first_no_missed_edges(dut) -> None:\n    \"\"\"Test that waiting on First() twice will catch both triggers that happen at the same simulation time.\"\"\"\n    a_count = 0\n    b_count = 0\n\n    start_time = get_sim_time(\"ns\")\n    end_time = start_time + 30\n\n    while True:\n        trigger = await First(RisingEdge(dut.a), RisingEdge(dut.b))\n        if get_sim_time(\"ns\") > end_time:\n            break\n        signal = trigger.signal\n        cocotb.log.info(f\"Fired: {signal._name} at {get_sim_time('ns')}\")\n        if signal is dut.a:\n            a_count += 1\n        elif signal is dut.b:\n            b_count += 1\n\n    assert a_count == 2\n    assert b_count == 2\n"
  },
  {
    "path": "tests/test_cases/test_force_release/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES ?= test_force_release\n"
  },
  {
    "path": "tests/test_cases/test_force_release/test_force_release.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Tests the Force/Freeze/Release features.\"\"\"\n\nfrom __future__ import annotations\n\nimport os\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.handle import Force, Release\nfrom cocotb.triggers import ClockCycles, Timer\nfrom cocotb_tools.sim_versions import GhdlVersion, RivieraVersion\n\nSIM_NAME = cocotb.SIM_NAME.lower()\nSIM_VERSION = cocotb.SIM_VERSION\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\nquesta_fli = (\n    SIM_NAME.startswith(\"modelsim\")\n    and LANGUAGE == \"vhdl\"\n    and os.getenv(\"VHDL_GPI_INTERFACE\", \"\") == \"fli\"\n)\n\nriviera_vpi_below_2024_10 = (\n    SIM_NAME.startswith(\"riviera\")\n    and LANGUAGE == \"verilog\"\n    and RivieraVersion(cocotb.SIM_VERSION) < \"2024.10\"\n)\n\nghdl_before_5 = SIM_NAME.startswith(\"ghdl\") and GhdlVersion(SIM_VERSION) < GhdlVersion(\n    \"5\"\n)\n\nriviera_before_2022_10 = (\n    SIM_NAME.startswith(\"riviera\")\n    and LANGUAGE == \"vhdl\"\n    and RivieraVersion(SIM_VERSION) < RivieraVersion(\"2022.10\")\n)\n\n\n########################################################################################\n# All tests in this file MUST be run in the described order.\n#\n# This is because if the previous test failed, the Forced signal can still be in a\n# Forced state. So the first thing each test does is Release the previously Forced\n# signal in hope to not have previous tests affect the current test.\n########################################################################################\n\n\nasync def reset(dut) -> None:\n    dut.stream_in_data.value = 0\n    dut.stream_out_data_comb.value = Release()\n    dut.stream_out_data_registered.value = Release()\n    await Timer(1, \"ns\")\n\n\n# Force/Release doesn't work on Verilator (gh-3831)\n# Release doesn't work on GHDL < 5 (gh-3830)\n@cocotb.test(expect_fail=SIM_NAME.startswith(\"verilator\") or ghdl_before_5)\nasync def test_hdl_writes_dont_overwrite_force_combo(dut) -> None:\n    \"\"\"Test Forcing then later Releasing a combo signal.\"\"\"\n    await reset(dut)\n\n    # Force a driven signal.\n    dut.stream_out_data_comb.value = Force(5)\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 5\n\n    # Combo drive of the Forced signal.\n    dut.stream_in_data.value = 4\n\n    # Check Forced signal didn't change.\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 5\n\n    # Release the Forced signal\n    dut.stream_out_data_comb.value = Release()\n    await Timer(1, \"ns\")\n\n    # Set input signal to cause output signal to update.\n    dut.stream_in_data.value = 3\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 3\n\n\n# Release doesn't work on Riviera-PRO (VHPI) until version 2022.10.\n# Release doesn't work on GHDL < 5 (gh-3830)\n# Force/Release doesn't work on Verilator (gh-3831)\n@cocotb.test(\n    expect_fail=SIM_NAME.startswith(\"verilator\")\n    or riviera_before_2022_10\n    or ghdl_before_5\n)\nasync def test_hdl_writes_dont_overwrite_force_registered(dut) -> None:\n    \"\"\"Test Forcing then Releasing a registered output.\"\"\"\n    await reset(dut)\n\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n\n    # Force the driven signal.\n    dut.stream_out_data_registered.value = Force(5)\n    await ClockCycles(dut.clk, 2)\n    assert dut.stream_out_data_registered.value == 5\n\n    # Drive the input of the registered process.\n    dut.stream_in_data.value = 4\n\n    # Check the Forced signal didn't change\n    await ClockCycles(dut.clk, 2)\n    assert dut.stream_out_data_registered.value == 5\n\n    # Release the driven signal.\n    dut.stream_out_data_registered.value = Release()\n\n    # Check that the registered drive is now propagating the input value.\n    await ClockCycles(dut.clk, 2)\n    assert dut.stream_out_data_registered.value == 4\n\n\n# Force/Release doesn't work on Verilator (gh-3831)\n@cocotb.test(expect_fail=SIM_NAME.startswith(\"verilator\"))\nasync def test_multiple_force_in_same_cycle(dut) -> None:\n    \"\"\"Tests multiple Force in the same eval cycle write the last value.\"\"\"\n    await reset(dut)\n\n    # Write several Forces\n    dut.stream_out_data_comb.value = Force(67)\n    dut.stream_out_data_comb.value = Force(5)\n    dut.stream_out_data_comb.value = Force(9)\n\n    # Check last value is the last write.\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 9\n\n    # Check value is Forced.\n    dut.stream_in_data.value = 1\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 9\n\n\n# Force/Release doesn't work on Verilator (gh-3831)\n# Release doesn't work on GHDL < 5 (gh-3830)\n@cocotb.test(expect_fail=SIM_NAME.startswith(\"verilator\") or ghdl_before_5)\nasync def test_multiple_release_in_same_cycle(dut) -> None:\n    \"\"\"Tests multiple Force in the same eval cycle write the last value.\"\"\"\n    await reset(dut)\n\n    # Force a signal.\n    dut.stream_out_data_comb.value = Force(31)\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 31\n\n    # Issue multiple Releases.\n    async def do_realease() -> None:\n        dut.stream_out_data_comb.value = Release()\n\n    for _ in range(10):\n        cocotb.start_soon(do_realease())\n\n    await Timer(1, \"ns\")\n\n    # Check value is Released.\n    dut.stream_in_data.value = 1\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 1\n\n\n# Force/Release doesn't work on Verilator (gh-3831)\n# Release doesn't work on GHDL < 5 (gh-3830)\n# Riviera's VPI < 2024.10 stacktraces when overwriting forced signal with normal deposit (gh-3832)\n# Questa's FLI allows overwriting forced signal with normal deposit (gh-3833)\n@cocotb.test(\n    expect_fail=SIM_NAME.startswith(\"verilator\") or questa_fli or ghdl_before_5,\n    skip=riviera_vpi_below_2024_10,\n)\nasync def test_deposit_on_forced(dut) -> None:\n    \"\"\"Test Deposits following a Force don't overwrite the value on combo signals.\"\"\"\n    await reset(dut)\n\n    # Force the driven signal.\n    dut.stream_out_data_comb.value = Force(10)\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 10\n\n    # Attempt depositing on the forced signal. This shouldn't change the value.\n    dut.stream_out_data_comb.value = 11\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 10\n\n    # Release the Forced signal.\n    dut.stream_out_data_comb.value = Release()\n\n    # Check if the driven signal is actually released.\n    dut.stream_out_data_comb.value = 46\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 46\n\n\n# Force/Release doesn't work on Verilator (gh-3831)\n# Questa's FLI allows overwriting forced signal with normal deposit (gh-3833)\n# Riviera's VPI < 2024.10 stacktraces when overwriting forced signal with normal deposit (gh-3832)\n@cocotb.test(\n    expect_fail=SIM_NAME.startswith(\"verilator\") or questa_fli,\n    skip=riviera_vpi_below_2024_10,\n)\nasync def test_deposit_then_force_in_same_cycle(dut) -> None:\n    \"\"\"Tests a Force and Deposit in the same cycle results in Force winning.\"\"\"\n    await reset(dut)\n\n    # Concurrent Force and Deposit\n    dut.stream_out_data_comb.value = 2\n    dut.stream_out_data_comb.value = Force(1)\n\n    # Check Force value won\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 1\n\n    # Check signal is Forced.\n    dut.stream_in_data.value = 63\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 1\n\n\n# Force/Release doesn't work on Verilator (gh-3831)\n# Questa's FLI allows overwriting forced signal with normal deposit (gh-3833)\n# Riviera's VPI < 2024.10 stacktraces when overwriting forced signal with normal deposit (gh-3832)\n@cocotb.test(\n    expect_fail=SIM_NAME.startswith(\"verilator\") or ghdl_before_5 or questa_fli,\n    skip=riviera_vpi_below_2024_10,\n)\nasync def test_force_then_deposit_in_same_cycle(dut) -> None:\n    \"\"\"Tests a Force and Deposit in the same cycle results in Force winning.\"\"\"\n    await reset(dut)\n\n    # Concurrent Force and Deposit\n    dut.stream_out_data_comb.value = Force(1)\n    dut.stream_out_data_comb.value = 2\n\n    # Check Force value won\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 1\n\n    # Check signal is Forced.\n    dut.stream_in_data.value = 63\n    await Timer(1, \"ns\")\n    assert dut.stream_out_data_comb.value == 1\n\n\n################################################################################\n"
  },
  {
    "path": "tests/test_cases/test_forked_exception/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCOCOTB_TEST_MODULES := test_forked_exception\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_forked_exception/test_forked_exception.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nTests the failure path for tests in the regression.py and xunit_reporter.py.\n\nThe Makefile in this folder is specially set up to squash any error code due\nto a failing test and ensures the failing test is reported properly.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.triggers import Timer\n\n\nclass MyException(Exception): ...\n\n\n@cocotb.test(expect_error=MyException)\nasync def test_fail(_):\n    async def fails():\n        await Timer(10, \"ns\")\n        raise MyException\n\n    cocotb.start_soon(fails())\n    await Timer(20, \"ns\")\n"
  },
  {
    "path": "tests/test_cases/test_gpi_extra_bad_lib/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# detecting an expected failure has to happen here, as the python code is invalid\n.PHONY: override_for_this_test\noverride_for_this_test:\n\tif $(MAKE) all; then echo \"Expected this to fail\"; false; else echo \"Failed as expected\"; fi\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES = test_simple\nexport GPI_EXTRA = invalid\n"
  },
  {
    "path": "tests/test_cases/test_gpi_extra_bad_lib/test_simple.py",
    "content": "from __future__ import annotations\n\nimport cocotb\nfrom cocotb.triggers import Timer\n\n\n@cocotb.test()\nasync def test_name_error(_):\n    # GPI init will fail, so the file contents don't really matter.\n    await Timer(100, \"ns\")\n"
  },
  {
    "path": "tests/test_cases/test_gpi_users_bad_lib/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# detecting an expected failure has to happen here, as the python code is invalid\n.PHONY: override_for_this_test\noverride_for_this_test:\n\tif $(MAKE) all; then echo \"Expected this to fail\"; false; else echo \"Failed as expected\"; fi\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES = test_simple\nexport GPI_USERS = doesntexist\n"
  },
  {
    "path": "tests/test_cases/test_gpi_users_bad_lib/test_simple.py",
    "content": "from __future__ import annotations\n\nimport cocotb\nfrom cocotb.triggers import Timer\n\n\n@cocotb.test()\nasync def test_name_error(_):\n    # GPI init will fail, so the file contents don't really matter.\n    await Timer(100, \"ns\")\n"
  },
  {
    "path": "tests/test_cases/test_gpi_users_notset/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# detecting an expected failure has to happen here, as the python code is invalid\n.PHONY: override_for_this_test\noverride_for_this_test:\n\tif $(MAKE) all; then echo \"Expected this to fail\"; false; else echo \"Failed as expected\"; fi\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES = test_simple\nunexport GPI_USERS\n"
  },
  {
    "path": "tests/test_cases/test_gpi_users_notset/test_simple.py",
    "content": "from __future__ import annotations\n\nimport cocotb\nfrom cocotb.triggers import Timer\n\n\n@cocotb.test()\nasync def test_name_error(_):\n    # GPI init will fail, so the file contents don't really matter.\n    await Timer(100, \"ns\")\n"
  },
  {
    "path": "tests/test_cases/test_indexing_warning/Makefile",
    "content": ".PHONY: all\nall:\n\tpytest -s\n"
  },
  {
    "path": "tests/test_cases/test_indexing_warning/indexing_warning_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nfrom typing import Any\n\nimport pytest\n\nimport cocotb\nfrom cocotb.types import IndexingChangedWarning\n\n\n@cocotb.test\nasync def test_indexing_warnings(dut: Any) -> None:\n    with pytest.warns(IndexingChangedWarning, match=\"Update index 0 to 7\"):\n        dut.vec.value[0]\n    with pytest.raises(IndexError):  # 3:7 is TO, but the HDL 7:0 is DOWNTO\n        with pytest.warns(IndexingChangedWarning, match=\"Update slice 3:7 to 4:0\"):\n            dut.vec.value[3:7]\n\n    with pytest.raises(IndexError):  # 0 is out of range of the HDL's 1:4\n        with pytest.warns(IndexingChangedWarning, match=\"Update index 0 to 1\"):\n            dut.arr.value[0]\n    with pytest.warns(IndexingChangedWarning, match=\"Update slice 1:2 to 2:3\"):\n        dut.arr.value[1:2]\n"
  },
  {
    "path": "tests/test_cases/test_indexing_warning/test_indexing_warning.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nfrom pathlib import Path\n\nimport pytest\n\nfrom cocotb_tools.runner import get_runner\n\nLANG = os.getenv(\"TOPLEVEL_LANG\", \"verilog\")\n\n\n@pytest.mark.skipif(LANG != \"verilog\", reason=\"This test only supports Verilog\")\ndef test_indexing_warning() -> None:\n    sim = os.getenv(\"SIM\", \"icarus\")\n    runner = get_runner(sim)\n\n    pwd = Path(__file__).parent.absolute()\n\n    # select args\n    build_args = []\n    test_args = []\n    if sim == \"questa\":\n        build_args = [\"+acc\"]\n        test_args = [\"-t\", \"ps\"]\n    elif sim == \"xcelium\":\n        build_args = [\"-v93\"]\n\n    runner.build(\n        sources=[pwd / \"top.sv\"],\n        hdl_toplevel=\"top\",\n        build_args=build_args,\n    )\n\n    runner.test(\n        test_module=\"indexing_warning_tests\",\n        hdl_toplevel=\"top\",\n        hdl_toplevel_lang=LANG,\n        test_args=test_args,\n        extra_env={\"COCOTB_INDEXING_CHANGED_WARNING\": \"1\"},\n    )\n"
  },
  {
    "path": "tests/test_cases/test_indexing_warning/top.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`timescale 1 ps / 1 ps\n\nmodule top (\n    input logic [7:0] vec,\n    input logic [7:0] arr [1:4]\n);\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_inertial_writes/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n.PHONY: override_tests\noverride_tests:\n\t$(MAKE) COCOTB_TRUST_INERTIAL_WRITES=0 sim COCOTB_RESULTS_FILE=results_no_trust.xml\n\t$(MAKE) COCOTB_TRUST_INERTIAL_WRITES=1 sim COCOTB_RESULTS_FILE=results_trust.xml\n\nCOCOTB_TEST_MODULES := inertial_writes_tests\n\ninclude ../../designs/sample_module/Makefile\n\nsimulator_test:\n\t$(MAKE) COCOTB_TRUST_INERTIAL_WRITES=1 COCOTB_SIMULATOR_TEST=1 sim\n"
  },
  {
    "path": "tests/test_cases/test_inertial_writes/inertial_writes_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.handle import _trust_inertial\nfrom cocotb.triggers import (\n    ReadOnly,\n    ReadWrite,\n    RisingEdge,\n    Timer,\n    with_timeout,\n)\n\nSIM_NAME = cocotb.SIM_NAME.lower()\nvhdl = os.environ.get(\"TOPLEVEL_LANG\", \"verilog\").lower() == \"vhdl\"\nverilog = os.environ.get(\"TOPLEVEL_LANG\", \"verilog\").lower() == \"verilog\"\nif verilog:\n    intf = \"vpi\"\nelif SIM_NAME.startswith(\"modelsim\"):\n    intf = os.environ.get(\"VHDL_GPI_INTERFACE\", \"fli\").strip()\nelse:\n    intf = \"vhpi\"\n\nsimulator_test = \"COCOTB_SIMULATOR_TEST\" in os.environ\n\n# Riviera's VHPI is skipped in all tests when COCOTB_TRUST_INERTIAL_WRITES mode is enabled\n# because it behaves erratically.\nriviera_vhpi_trust_inertial = (\n    SIM_NAME.startswith(\"riviera\") and intf == \"vhpi\" and _trust_inertial\n)\n\n\n@cocotb.test(\n    skip=riviera_vhpi_trust_inertial and not simulator_test,\n)\nasync def test_writes_on_timer_seen_on_edge(dut):\n    # steady state\n    dut.clk.value = 0\n    await Timer(10, \"ns\")\n\n    # inertial write on a signal\n    dut.clk.value = 1\n\n    # check we can register an edge trigger on the signal we just changed because it hasn't taken effect yet\n    await with_timeout(RisingEdge(dut.clk), 10, \"ns\")\n\n\nif simulator_test:\n    expect_fail = False\nelif _trust_inertial:\n    expect_fail = False\nelif SIM_NAME.startswith(\"riviera\") and intf == \"vhpi\":\n    expect_fail = False\nelif SIM_NAME.startswith(\"modelsim\") and intf in (\"vhpi\", \"fli\"):\n    expect_fail = False\nelse:\n    expect_fail = True\n\n\n# Riviera and Questa on VHDL designs seem to apply inertial writes in this state immediately,\n# presumably because it's the NBA application region.\n# This test will fail because the ReadWrite write applicator task does inertial writes of its own.\n@cocotb.test(\n    expect_fail=expect_fail,\n    skip=riviera_vhpi_trust_inertial and not simulator_test,\n)\nasync def test_read_back_in_readwrite(dut):\n    # steady state\n    dut.clk.value = 0\n    await Timer(10, \"ns\")\n    assert dut.clk.value == 0\n\n    # write in the \"normal\" phase\n    dut.clk.value = 1\n\n    # assert we can read back what we wrote in the ReadWrite phase\n    await ReadWrite()\n    assert dut.clk.value == 1\n\n\nif simulator_test:\n    expect_fail = False\nelif not _trust_inertial:\n    expect_fail = False\nelif SIM_NAME.startswith(\"icarus\"):\n    expect_fail = True\nelif SIM_NAME.startswith(\"modelsim\") and verilog:\n    expect_fail = True\nelif SIM_NAME.startswith(\"xmsim\") and intf == \"vhpi\":\n    expect_fail = True\nelif \"vcs\" in SIM_NAME:\n    expect_fail = True\n\n\n# Icarus, Questa VPI, and Xcelium VHPI inertial writes aren't actually inertial.\n@cocotb.test(\n    expect_fail=expect_fail,\n    skip=riviera_vhpi_trust_inertial and not simulator_test,\n)\nasync def test_writes_dont_update_hdl_this_delta(dut):\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n\n    # assert steady state\n    dut.stream_in_data.value = 0\n    await RisingEdge(dut.clk)\n    await ReadOnly()\n    assert dut.stream_out_data_registered.value == 0\n\n    # write on the clock edge\n    await RisingEdge(dut.clk)\n    dut.stream_in_data.value = 1\n\n    # ensure that the write data wasn't used on this clock cycle\n    await ReadOnly()\n    assert dut.stream_out_data_registered.value == 0\n\n    # ensure that the write data made it on the result of the next clock cycle\n    await RisingEdge(dut.clk)\n    await ReadOnly()\n    assert dut.stream_out_data_registered.value == 1\n\n\n@cocotb.test\nasync def test_writes_in_read_write(dut):\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n    dut.stream_in_data.value = 0\n    await RisingEdge(dut.clk)\n    assert dut.stream_in_data.value == 0\n\n    # Schedule a write now so the upcoming ReadWrite has a following ReadWrite phase\n    # due to writes being scheduled.\n    dut.stream_in_data.value = 5\n\n    await ReadWrite()\n    # Do a write in the ReadWrite phase to see if it causes issues.\n    dut.stream_in_data.value = 1\n\n    await ReadOnly()\n    # Was the write applied?\n    assert dut.stream_in_data.value == 1\n\n\n@cocotb.test\nasync def test_writes_in_last_read_write(dut):\n    cocotb.start_soon(Clock(dut.clk, 10, \"ns\").start())\n    dut.stream_in_data.value = 0\n    await RisingEdge(dut.clk)\n    assert dut.stream_in_data.value == 0\n\n    await ReadWrite()\n    dut.stream_in_data.value = 1\n    # We are now in a ReadWrite phase where no writes have been applied.\n    # The simulator may accurately assess that we are at the end of the evaluation loop,\n    # as there are no more writes scheduled that it can see (only in cocotb).\n    # The above write in COCOTB_TRUST_INERTIAL_WRITES=0 mode will be scheduled for the\n    # next ReadWrite phase, which may never come.\n\n    await ReadOnly()\n    # Was the write applied?\n    assert dut.stream_in_data.value == 1\n"
  },
  {
    "path": "tests/test_cases/test_integers/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nall:\n\tpytest -s\n\nclean:\n\trm -rf sim_build/\n\trm -f results.xml\n"
  },
  {
    "path": "tests/test_cases/test_integers/integer_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nimport random\nfrom typing import Any\n\nimport pytest\n\nimport cocotb\nfrom cocotb.handle import LogicArrayObject\nfrom cocotb.triggers import Timer\nfrom cocotb.types import LogicArray\nfrom cocotb_tools.sim_versions import GhdlVersion, VerilatorVersion\n\nLANGUAGE = os.getenv(\"TOPLEVEL_LANG\").lower()\nSIM = cocotb.SIM_NAME.lower()\n\n\n@cocotb.test\n@cocotb.skipif(LANGUAGE != \"verilog\")\n@cocotb.parametrize(\n    (\n        (\"name\", \"width\", \"is_signed\"),\n        [\n            (\"enum\", 32, True),\n            (\"byte\", 8, True),\n            (\"shortint\", 16, True),\n            (\"int\", 32, True),\n            (\"longint\", 64, True),\n            (\"integer\", 32, True),\n        ],\n    )\n)\n@cocotb.parametrize(obj_type=(\"input\", \"signal\"))\n@cocotb.xfail(\n    SIM.startswith(\"verilator\")\n    and VerilatorVersion(cocotb.SIM_VERSION) < VerilatorVersion(\"5.044\"),\n    reason=\"Verilator does not support signedness testing before v5.044\",\n    raises=RuntimeError,\n)\nasync def test_int_verilog(\n    verilog_dut: Any, name: str, width: int, is_signed: bool, obj_type: str\n) -> None:\n    \"\"\"Test that Verilog integer types are handled correctly.\"\"\"\n    if name == \"longint\" and obj_type == \"input\" and SIM.startswith(\"xmsim\"):\n        # Xcelium uses different values for VPI constants and this causes longint ports to appear to return vpiRealNet.\n        # TODO Replace with pytest.xfail call once supported.\n        return\n    obj_name = f\"{name}_{obj_type}\"\n    handle = getattr(verilog_dut, obj_name)\n    assert len(handle) == width\n    assert handle.is_signed is is_signed\n\n    # For backwards compatibility, LogicArrayObjects always use (INT_MIN, UINT_MAX) for bounds.\n    # Some simulators discover integer handles as LogicArrayObjects.\n    if isinstance(handle, LogicArrayObject):\n        min_value = -(2 ** (width - 1))\n        max_value = (2**width) - 1\n\n        def check(actual: LogicArray, expected: int) -> bool:\n            if expected >= 0:\n                return actual.to_unsigned() == expected\n            else:\n                return actual.to_signed() == expected\n\n    else:\n        min_value = -(2 ** (width - 1)) if is_signed else 0\n        max_value = (2 ** (width - 1)) - 1 if is_signed else (2**width) - 1\n\n        def check(actual: int, expected: int) -> bool:\n            return actual == expected\n\n    for _ in range(100):\n        exp_value = random.randint(min_value, max_value)\n        handle.value = exp_value\n        await Timer(1)\n        assert check(handle.value, exp_value)\n\n    handle.value = 67\n    await Timer(1)\n\n    for value in (\n        # Above maximum value\n        max_value + 1,\n        random.randint(max_value + 1, 2 * max_value),\n        2 * max_value,\n        random.randint(2 * max_value, 10 * max_value),\n        10 * max_value,\n        # Below minimum value\n        min_value - 1,\n        random.randint(2 * min_value, min_value - 1),\n        2 * min_value,\n        random.randint(10 * min_value, 2 * min_value),\n        10 * min_value,\n    ):\n        cocotb.log.info(f\"Testing value={value}\")\n\n        with pytest.raises(ValueError):\n            handle.value = value\n\n        # ensure it wasn't applied\n        await Timer(1)\n        assert handle.value == 67\n\n\n@cocotb.test\n@cocotb.skipif(LANGUAGE != \"vhdl\")\n@cocotb.parametrize(\n    (\n        (\"name\", \"width\", \"is_signed\", \"min_value\", \"max_value\"),\n        [\n            (\"integer\", 32, True, -(2**31), 2**31 - 1),\n            (\"natural\", 32, True, 0, 2**31 - 1),\n            (\"positive\", 32, True, 1, 2**31 - 1),\n            (\"my_integer\", 32, True, -100, 100),\n        ],\n    )\n)\n@cocotb.parametrize(obj_type=(\"input\", \"signal\"))\n@cocotb.xfail(\n    SIM.startswith(\"ghdl\") and GhdlVersion(cocotb.SIM_VERSION) < GhdlVersion(\"5.2\"),\n    reason=\"GHDL does not support signedness testing before 5.2\",\n)\nasync def test_integer_access_vhdl(\n    vhdl_dut: Any,\n    name: str,\n    width: int,\n    is_signed: bool,\n    obj_type: str,\n    min_value: int,\n    max_value: int,\n) -> None:\n    \"\"\"Test that VHDL integer types are handled correctly.\"\"\"\n    obj_name = f\"{name}_{obj_type}\"\n    handle = getattr(vhdl_dut, obj_name)\n    assert handle.is_signed is is_signed\n    assert len(handle) == width\n\n    # For backwards compatibility, LogicArrayObjects always use (INT_MIN, UINT_MAX) for bounds.\n    # Some simulators (GHDL) discover integer handles as LogicArrayObjects.\n    if isinstance(handle, LogicArrayObject):\n\n        def check(actual: LogicArray, expected: int) -> bool:\n            if expected >= 0:\n                return actual.to_unsigned() == expected\n            else:\n                return actual.to_signed() == expected\n\n    else:\n\n        def check(actual: int, expected: int) -> bool:\n            return actual == expected\n\n    # Use bounds of the specific subtype for random testing.\n    # Otherwise we get fun range constraint violations which cause errors.\n    for _ in range(100):\n        exp_value = random.randint(min_value, max_value)\n        handle.value = exp_value\n        await Timer(1)\n        assert check(handle.value, exp_value)\n\n    # For backwards compatibility, LogicArrayObjects always use (INT_MIN, UINT_MAX) for bounds.\n    # Some simulators (GHDL) discover integer handles as LogicArrayObjects.\n    if isinstance(handle, LogicArrayObject):\n        min_value = -(2 ** (width - 1))\n        max_value = (2**width) - 1\n    else:\n        min_value = -(2 ** (width - 1)) if is_signed else 0\n        max_value = (2 ** (width - 1)) - 1 if is_signed else (2**width) - 1\n\n    handle.value = 67\n    await Timer(1)\n\n    for value in (\n        # Above maximum value\n        max_value + 1,\n        random.randint(max_value + 1, 2 * max_value),\n        2 * max_value,\n        random.randint(2 * max_value, 10 * max_value),\n        10 * max_value,\n        # Below minimum value\n        min_value - 1,\n        random.randint(2 * min_value, min_value - 1),\n        2 * min_value,\n        random.randint(10 * min_value, 2 * min_value),\n        10 * min_value,\n    ):\n        cocotb.log.info(f\"Testing value={value}\")\n\n        with pytest.raises(ValueError):\n            handle.value = value\n\n        # ensure it wasn't applied\n        await Timer(1)\n        assert handle.value == 67\n"
  },
  {
    "path": "tests/test_cases/test_integers/integers.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\ntypedef enum {\n    A,\n    B,\n    C = 45,\n    D = 123789\n} enum_e;\n\nmodule top (\n    input enum_e enum_input,\n    input byte byte_input,\n    input shortint shortint_input,\n    input int int_input,\n    input longint longint_input,\n    input integer integer_input\n);\n    enum_e enum_signal;\n    byte byte_signal;\n    shortint shortint_signal;\n    int int_signal;\n    longint longint_signal;\n    integer integer_signal;\n\n/* Icarus optimizes out the undriven signals.\n * Verilator updates the signals every evaluation cycle.\n * This should work considering most event-base simulators will only run the constant\n * assignment, overwriting the signal values, if the driver values are updated, which\n * isn't a problem for our test.\n */\n`ifndef VERILATOR\n    assign enum_signal = enum_input;\n    assign byte_signal = byte_input;\n    assign shortint_signal = shortint_input;\n    assign int_signal = int_input;\n    assign longint_signal = longint_input;\n    assign integer_signal = integer_input;\n`endif  /* VERILATOR */\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_integers/integers.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nlibrary work;\nuse work.integers_pkg.all;\n\nentity top is\nport (\n    integer_input: in integer;\n    natural_input: in natural;\n    positive_input: in positive;\n    my_integer_input: in my_integer\n);\nend entity top;\n\narchitecture rtl of top is\n    signal integer_signal: integer;\n    signal natural_signal: natural;\n    signal positive_signal: positive;\n    signal my_integer_signal: my_integer;\nbegin\nend architecture rtl;\n"
  },
  {
    "path": "tests/test_cases/test_integers/integers_pkg.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\npackage integers_pkg is\n    subtype my_integer is integer range -100 to 100;\nend package integers_pkg;\n"
  },
  {
    "path": "tests/test_cases/test_integers/test_integers.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nfrom pathlib import Path\nfrom subprocess import run\n\nimport pytest\n\nfrom cocotb_tools.runner import get_runner\nfrom cocotb_tools.sim_versions import IcarusVersion\n\nSIM = os.getenv(\"SIM\", \"icarus\").lower()\n\nif SIM == \"icarus\":\n    icarus_version = run(\n        [\"iverilog\", \"-V\"], capture_output=True, text=True, check=True\n    ).stdout\n\n\n@pytest.mark.skipif(\n    SIM == \"icarus\"\n    and IcarusVersion.from_commandline(icarus_version) < IcarusVersion(\"12.0\"),\n    reason=\"Icarus v11.0 treats integers as regs and ports cannot be of type reg\",\n)\ndef test_integers_runner():\n    hdl_toplevel_lang = os.getenv(\"TOPLEVEL_LANG\", \"verilog\").lower()\n\n    proj_path = Path(__file__).resolve().parent\n\n    if hdl_toplevel_lang == \"verilog\":\n        sources = [proj_path / \"integers.sv\"]\n    else:\n        sources = [\n            proj_path / \"integers_pkg.vhdl\",\n            proj_path / \"integers.vhdl\",\n        ]\n\n    build_args = []\n    if hdl_toplevel_lang == \"vhdl\" and SIM in (\"ius\", \"xcelium\"):\n        build_args = [\"-v93\"]\n\n    runner = get_runner(SIM)\n    runner.build(\n        sources=sources,\n        hdl_toplevel=\"top\",\n        build_args=build_args,\n    )\n    runner.test(\n        hdl_toplevel=\"top\",\n        test_module=\"integer_tests\",\n        test_args=build_args,\n    )\n\n\nif __name__ == \"__main__\":\n    test_integers_runner()\n"
  },
  {
    "path": "tests/test_cases/test_iteration_mixedlang/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifeq ($(shell echo $(SIM) | tr A-Z a-z),riviera)\nall:\n\t@echo \"Skipping test_iteration_mixedlang since Riviera-PRO crashes (see https://github.com/cocotb/cocotb/issues/3293)\"\nclean::\n\nelse\n\ninclude ../../designs/uart2bus/Makefile\nCOCOTB_TEST_MODULES = test_iteration\nendif\n"
  },
  {
    "path": "tests/test_cases/test_iteration_mixedlang/test_iteration.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport logging\n\nimport cocotb\nfrom cocotb.handle import (\n    ArrayObject,\n    GPIDiscovery,\n    HierarchyArrayObject,\n    HierarchyObject,\n    LogicArrayObject,\n)\n\n########################################################################################\n# This is testing handle caching, so it must come first!\n########################################################################################\n\n\n@cocotb.test\nasync def discovery_method(dut) -> None:\n    \"\"\"Verify that the different discovery methods work.\"\"\"\n\n    # this is a Verilog toplevel, so we should not be finding a VHDL object\n    # when we request NATIVE discovery, but we should get it with AUTO\n    assert dut._get(\"i_vhdl\", GPIDiscovery.NATIVE) is None\n    assert dut._get(\"i_vhdl\", GPIDiscovery.AUTO) is not None\n    # Now we should see the handle has been cached and can get it with NATIVE set\n    assert dut._get(\"i_vhdl\", GPIDiscovery.NATIVE) is not None\n\n\n########################################################################################\n\n\ndef recursive_dump(parent, log):\n    \"\"\"\n    Recursively iterate through every object and log a message\n\n    Returns a count of the total number of objects found\n    \"\"\"\n    if not isinstance(\n        parent,\n        (\n            HierarchyObject,\n            HierarchyArrayObject,\n            ArrayObject,\n        ),\n    ):\n        return 0\n    count = 0\n    for thing in parent:\n        count += 1\n        log.info(\"Found %s (%s)\", thing._path, type(thing))\n        count += recursive_dump(thing, log)\n    return count\n\n\n@cocotb.test\nasync def recursive_discovery(dut):\n    \"\"\"Recursively discover every single object in the design.\"\"\"\n    expected = 275\n\n    tlog = logging.getLogger(\"cocotb.test\")\n    actual = recursive_dump(dut, tlog)\n\n    assert expected == actual\n    tlog.info(\"Found a total of %d things\", actual)\n\n    assert isinstance(dut.i_verilog.uart1.baud_gen_1.baud_freq, LogicArrayObject)\n\n\n@cocotb.test\nasync def recursive_discovery_boundary(dut):\n    \"\"\"Iteration through the boundary works but this just double checks.\"\"\"\n    expected = 160\n\n    tlog = logging.getLogger(\"cocotb.test\")\n    actual = recursive_dump(dut.i_vhdl, tlog)\n    tlog.info(\"Found a total of %d things\", actual)\n    assert actual == expected\n"
  },
  {
    "path": "tests/test_cases/test_iteration_verilog/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nifneq ($(TOPLEVEL_LANG),verilog)\n\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being verilog\"\nclean::\n\nelse\n\nVERILOG_SOURCES = $(PWD)/endian_swapper.sv\nCOCOTB_TOPLEVEL = endian_swapper_sv\nCOCOTB_TEST_MODULES = test_iteration_es\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_iteration_verilog/endian_swapper.sv",
    "content": "// Copyright cocotb contributors\n// Copyright (c) 2013 Potential Ventures Ltd\n// Copyright (c) 2013 SolarFlare Communications Inc\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n/*\n\nEndian swapping module.\n\nSimple example with Avalon streaming interfaces and a CSR bus\n\nAvalon-ST has readyLatency of 0\nAvalon-MM has fixed readLatency of 1\n\nExposes 2 32-bit registers via the Avalon-MM interface\n\n   Address 0:  bit     0  [R/W] byteswap enable\n               bits 31-1: [N/A] reserved\n   Address 1:  bits 31-0: [RO]  packet count\n\n*/\n\n`timescale 1ns/1ps\n\nmodule endian_swapper_sv #(\n    parameter                              DATA_BYTES = 8\n) (\n    input                                  clk,\n    input                                  reset_n,\n\n    input [DATA_BYTES*8-1:0]               stream_in_data,\n    input [$clog2(DATA_BYTES)-1:0]         stream_in_empty,\n    input                                  stream_in_valid,\n    input                                  stream_in_startofpacket,\n    input                                  stream_in_endofpacket,\n    output reg                             stream_in_ready,\n\n    output reg [DATA_BYTES*8-1:0]          stream_out_data,\n    output reg [$clog2(DATA_BYTES)-1:0]    stream_out_empty,\n    output reg                             stream_out_valid,\n    output reg                             stream_out_startofpacket,\n    output reg                             stream_out_endofpacket,\n    input                                  stream_out_ready,\n\n    input  [1:0]                           csr_address,\n    output reg [31:0]                      csr_readdata,\n    output reg                             csr_readdatavalid,\n    input                                  csr_read,\n    input                                  csr_write,\n    output reg                             csr_waitrequest,\n    input [31:0]                           csr_writedata\n);\n\n\n\nfunction [DATA_BYTES*8-1:0] byteswap(input [DATA_BYTES*8-1:0] data);\n/*\n    // FIXME Icarus doesn't seem to like this....\n    reg [$clog2(DATA_BYTES)-1:0] i;\n\n    for (i=0; i<DATA_BYTES; i=i+1)\n        byteswap[i*8+7 -:8] = data[(DATA_BYTES-i)*8-1 -:8];\n*/\n\n    // Hardwire for now\n    byteswap = { data[7:0],\n                 data[15:8],\n                 data[23:16],\n                 data[31:24],\n                 data[39:32],\n                 data[47:40],\n                 data[55:48],\n                 data[63:56]};\nendfunction\n\n\nreg flush_pipe;\nreg in_packet;\nreg byteswapping;\nreg [31:0] packet_count;\n\n\nalways @(posedge clk or negedge reset_n) begin\n    if (!reset_n) begin\n        flush_pipe       <= 1'b0;\n        in_packet        <= 1'b0;\n        packet_count     <= 32'd0;\n\n        stream_out_startofpacket <= 1'b1;\n        stream_out_endofpacket   <= 1'b1;\n    end else begin\n\n        if (flush_pipe & stream_out_ready)\n            flush_pipe <= stream_in_endofpacket & stream_in_valid & stream_out_ready;\n        else if (!flush_pipe)\n            flush_pipe <= stream_in_endofpacket & stream_in_valid & stream_out_ready;\n\n        if (stream_out_ready & stream_in_valid) begin\n            stream_out_empty         <= stream_in_empty;\n            stream_out_startofpacket <= stream_in_startofpacket;\n            stream_out_endofpacket   <= stream_in_endofpacket;\n\n            if (!byteswapping)\n                stream_out_data      <= stream_in_data;\n            else\n                stream_out_data      <= byteswap(stream_in_data);\n\n            if (stream_in_startofpacket && stream_in_valid) begin\n                packet_count <= packet_count + 1;\n                in_packet    <= 1'b1;\n            end\n\n            if (stream_in_endofpacket && stream_in_valid)\n                in_packet    <= 1'b0;\n\n        end\n    end\nend\n\nalways @(*)\n    stream_out_valid = (stream_in_valid & ~stream_out_endofpacket) | flush_pipe;\n\n\n// Hold off CSR accesses during packet transfers to prevent changing of\n// endian configuration mid-packet\nalways @(*)\n    csr_waitrequest = !reset_n || in_packet || (stream_in_startofpacket & stream_in_valid) || flush_pipe;\n\n\n// Workaround Icarus bug where a simple assign doesn't work\nalways @(stream_out_ready)\n    stream_in_ready = stream_out_ready;\n\n\nalways @(posedge clk or negedge reset_n) begin\n    if (!reset_n) begin\n        byteswapping      <= 1'b0;\n        csr_readdatavalid <= 1'b0;\n    end else begin\n        csr_readdatavalid <= 1'b0;\n        if (csr_read) begin\n            csr_readdatavalid <= !csr_waitrequest;\n            case (csr_address)\n                0:    csr_readdata <= {31'b0, byteswapping};\n                1:    csr_readdata <= packet_count;\n            endcase\n        end else if (csr_write & !csr_waitrequest) begin\n            case (csr_address)\n                0:    byteswapping <= csr_writedata[0];\n            endcase\n        end\n    end\nend\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_iteration_verilog/test_iteration_es.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015, 2018 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport logging\n\nimport cocotb\nfrom cocotb.handle import ArrayObject, HierarchyArrayObject, HierarchyObject\nfrom cocotb.triggers import gather\n\nSIM_NAME = cocotb.SIM_NAME.lower()\n\n\n@cocotb.test()\nasync def recursive_discovery(dut):\n    \"\"\"\n    Recursively discover every single object in the design\n    \"\"\"\n    pass_total = 26\n\n    # Icarus doesn't support array indexes like get_handle_by_name(\"some_path[x]\")\n    SKIP_HANDLE_ASSERT = cocotb.SIM_NAME.lower().startswith((\"riviera\", \"icarus\"))\n\n    tlog = logging.getLogger(\"cocotb.test\")\n\n    def sim_iter(parent):\n        if not isinstance(\n            parent,\n            (\n                HierarchyObject,\n                HierarchyArrayObject,\n                ArrayObject,\n            ),\n        ):\n            return\n        for thing in parent:\n            yield thing\n            yield from sim_iter(thing)\n\n    total = 0\n    for thing in sim_iter(dut):\n        tlog.info(\"Found %s (%s)\", thing._path, type(thing))\n\n        if not SKIP_HANDLE_ASSERT:\n            subpath = thing._path.split(\".\", 1)[1]\n            assert dut._handle.get_handle_by_name(subpath) == thing._handle\n\n        total += 1\n\n    tlog.info(\"Found a total of %d things\", total)\n    assert total == pass_total\n\n\nasync def iteration_loop(dut):\n    for thing in dut:\n        cocotb.log.info(\"Found something: %s\", thing._path)\n\n\n@cocotb.test()\nasync def dual_iteration(dut):\n    loop_one = cocotb.start_soon(iteration_loop(dut))\n    loop_two = cocotb.start_soon(iteration_loop(dut))\n\n    await gather(loop_one, loop_two)\n"
  },
  {
    "path": "tests/test_cases/test_iteration_vhdl/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/viterbi_decoder_axi4s/Makefile\nCOCOTB_TEST_MODULES = test_iteration\n\nifneq ($(filter $(SIM),ius xcelium),)\n    SIM_ARGS += -notimezeroasrtmsg\nendif\n\nifeq ($(SIM),ghdl)\n    SIM_ARGS += --ieee-asserts=disable-at-0\nendif\n"
  },
  {
    "path": "tests/test_cases/test_iteration_vhdl/test_iteration.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015, 2018 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport logging\nimport os\n\nimport cocotb\nfrom cocotb.handle import ArrayObject, HierarchyArrayObject, HierarchyObject\nfrom cocotb.triggers import Timer, gather\n\n\ndef total_object_count():\n    \"\"\"Return the total object count based on simulator.\"\"\"\n    SIM_NAME = cocotb.SIM_NAME.lower()\n\n    # Questa with VHPI\n    # TODO: Why do we get massively different numbers for Questa/VHPI than for Questa/FLI or VPI?\n    if SIM_NAME.startswith(\"modelsim\") and os.environ[\"VHDL_GPI_INTERFACE\"] == \"vhpi\":\n        if os.environ.get(\"COCOTB__QUESTA_MODE\", \"compat\") == \"compat\":\n            return 5119\n        else:\n            # The QIS/Qrun flow additionally finds\n            # Found dec_viterbi_ent.#IMPLICIT# (<class 'cocotb.handle.IntegerObject'>) and\n            # many instances that look like s__218_3 (<class 'cocotb.handle.LogicObject'>)\n            # Tracked as Siemens issue QSIM-84124.\n            return 5384\n\n    if SIM_NAME.startswith(\n        (\n            \"ncsim\",\n            \"xmsim\",\n            \"modelsim\",\n            \"riviera\",\n        )\n    ):\n        return 2663\n\n    return 0\n\n\n@cocotb.test(skip=(total_object_count() == 0))\nasync def recursive_discovery(dut):\n    \"\"\"Recursively discover every single object in the design.\"\"\"\n\n    pass_total = total_object_count()\n\n    tlog = logging.getLogger(\"cocotb.test\")\n    await Timer(100)\n\n    def dump_all_the_things(parent):\n        if not isinstance(\n            parent,\n            (\n                HierarchyObject,\n                HierarchyArrayObject,\n                ArrayObject,\n            ),\n        ):\n            return 0\n        count = 0\n        for thing in parent:\n            count += 1\n            tlog.info(\"Found %s (%s)\", thing._path, type(thing))\n            count += dump_all_the_things(thing)\n        return count\n\n    total = dump_all_the_things(dut)\n    tlog.info(\"Found a total of %d things\", total)\n    assert total == pass_total\n\n\n@cocotb.test\nasync def discovery_all(dut):\n    \"\"\"Discover everything on top-level.\"\"\"\n    cocotb.log.info(\"Iterating over top-level to discover objects\")\n    for thing in dut:\n        cocotb.log.info(\"Found something: %s\", thing._path)\n\n    cocotb.log.info(\"length of dut.inst_acs is %d\", len(dut.gen_acs))\n\n\n@cocotb.test()\nasync def dual_iteration(dut):\n    \"\"\"Test iteration over top-level in two forked coroutines.\"\"\"\n\n    async def iteration_loop():\n        for thing in dut:\n            cocotb.log.info(\"Found something: %s\", thing._path)\n            await Timer(1)\n\n    loop_one = cocotb.start_soon(iteration_loop())\n    loop_two = cocotb.start_soon(iteration_loop())\n\n    await gather(loop_one, loop_two)\n"
  },
  {
    "path": "tests/test_cases/test_kill_sim/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCOCOTB_TEST_MODULES := kill_sim_tests\n\n.PHONY: tests\ntests:\n\t$(MAKE) test_kill_sim COCOTB_TEST_FILTER=test_sys_exit\n\t$(MAKE) test_kill_sim COCOTB_TEST_FILTER=test_task_sys_exit\n\t$(MAKE) test_kill_sim COCOTB_TEST_FILTER=test_trigger_sys_exit\n\t$(MAKE) test_kill_sim COCOTB_TEST_FILTER=test_keyboard_interrupt\n\t$(MAKE) test_kill_sim COCOTB_TEST_FILTER=test_task_keyboard_interrupt\n\t$(MAKE) test_kill_sim COCOTB_TEST_FILTER=test_trigger_keyboard_interrupt\n\n.PHONY: test_kill_sim\ntest_kill_sim:\n\t$(RM) -f test_failed\n\t-$(MAKE) sim\n\ttest ! -f test_failed\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_kill_sim/kill_sim_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport sys\nfrom typing import Any\n\nimport cocotb\nfrom cocotb.regression import SimFailure\nfrom cocotb.triggers import Timer\n\n\ndef make_failure_file() -> None:\n    open(\"test_failed\", \"w\").close()\n\n\n@cocotb.test(expect_error=SystemExit)\nasync def test_sys_exit(_: Any) -> None:\n    sys.exit(1)\n    make_failure_file()\n\n\n@cocotb.test(expect_error=SimFailure)\nasync def test_sys_exit_sim_continued(_: Any) -> None:\n    make_failure_file()\n\n\n@cocotb.test(expect_error=SystemExit)\nasync def test_task_sys_exit(_: Any) -> None:\n    async def coro() -> None:\n        sys.exit(1)\n\n    cocotb.start_soon(coro())\n    await Timer(1)\n    make_failure_file()\n\n\n@cocotb.test(expect_error=SimFailure)\nasync def test_task_sys_exit_sim_continued(_: Any) -> None:\n    make_failure_file()\n\n\n@cocotb.test(expect_error=SystemExit)\nasync def test_trigger_sys_exit(_: Any) -> None:\n    await Timer(1)\n    sys.exit(1)\n    make_failure_file()\n\n\n@cocotb.test(expect_error=SimFailure)\nasync def test_trigger_sys_exit_sim_continued(_: Any) -> None:\n    make_failure_file()\n\n\n@cocotb.test(expect_error=KeyboardInterrupt)\nasync def test_keyboard_interrupt(_: Any) -> None:\n    raise KeyboardInterrupt  # Analogous to Ctrl-C\n    make_failure_file()\n\n\n@cocotb.test(expect_error=SimFailure)\nasync def test_keyboard_interrupt_sim_continued(_: Any) -> None:\n    make_failure_file()\n\n\n@cocotb.test(expect_error=KeyboardInterrupt)\nasync def test_task_keyboard_interrupt(_: Any) -> None:\n    async def coro() -> None:\n        raise KeyboardInterrupt  # Analogous to Ctrl-C\n\n    cocotb.start_soon(coro())\n    await Timer(1)\n    make_failure_file()\n\n\n@cocotb.test(expect_error=SimFailure)\nasync def test_task_keyboard_interrupt_sim_continued(_: Any) -> None:\n    make_failure_file()\n\n\n@cocotb.test(expect_error=KeyboardInterrupt)\nasync def test_trigger_keyboard_interrupt(_: Any) -> None:\n    await Timer(1)\n    raise KeyboardInterrupt  # Analogous to Ctrl-C\n    make_failure_file()\n\n\n@cocotb.test(expect_error=SimFailure)\nasync def test_trigger_keyboard_interrupt_sim_continued(_: Any) -> None:\n    make_failure_file()\n"
  },
  {
    "path": "tests/test_cases/test_listing/.gitignore",
    "content": "sim.log\n"
  },
  {
    "path": "tests/test_cases/test_listing/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCOCOTB_TEST_MODULES := test_listing_1,test_listing_2\nexport COCOTB_LIST_TESTS := 1\n\nifneq ($(filter riviera questa,$(SIM)),)\n\nall:\n\t@echo \"Riviera and Questa are not supported on this test, skipping.\"\n\nelse\n\n.PHONY: override\noverride:\n\trm -f sim.log\n\t-$(MAKE) all 2>/dev/null | tee sim.log\n\tpython check_results.py sim.log\n\ninclude ../../designs/sample_module/Makefile\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_listing/check_results.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"\nThis file exists because Mac's grep (BSD) does not support either the -P or -z flags,\nwhich are required to check the test listing result because it must match multiple lines.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport re\nimport sys\n\nwith open(sys.argv[1]) as f:\n    log = f.read()\n    found = re.search(\n        r\"test_listing_1\\.test_a\\n.*test_listing_1\\.test_b\\n.*test_listing_2\\.test_a\\n.*test_listing_2\\.test_b\",\n        log,\n        re.MULTILINE,\n    )\n    if not found:\n        print(\"Did not find expected test listing in sim.log\")\n        sys.exit(1)\n"
  },
  {
    "path": "tests/test_cases/test_listing/test_listing_1.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test\nasync def test_a(_):\n    pass\n\n\n@cocotb.test\nasync def test_b(_):\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_listing/test_listing_2.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test\nasync def test_a(_):\n    pass\n\n\n@cocotb.test\nasync def test_b(_):\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_log_prefix/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n.PHONY: all\nall:\n\tpytest -s\n"
  },
  {
    "path": "tests/test_cases/test_log_prefix/log_prefix_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport contextlib\nimport logging\nfrom collections.abc import Generator\n\nimport cocotb\nfrom cocotb.logging import ANSI\n\n\nclass LogCaptureData:\n    def __init__(self) -> None:\n        self.records: list[logging.LogRecord] = []\n        self.msgs: list[str] = []\n\n\n@contextlib.contextmanager\ndef capture_logs(handler: logging.Handler) -> Generator[LogCaptureData, None, None]:\n    data = LogCaptureData()\n\n    old_emit = handler.emit\n\n    def emit(record: logging.LogRecord) -> None:\n        data.records.append(record)\n        data.msgs.append(handler.format(record))\n        old_emit(record)\n\n    handler.emit = emit  # type: ignore[method-assign]\n    try:\n        yield data\n    finally:\n        handler.emit = old_emit  # type: ignore[method-assign]\n\n\n@cocotb.test\nasync def test_log_prefix_custom(_: object) -> None:\n    logger = logging.getLogger(\"example\")\n    logger.setLevel(logging.INFO)\n    with capture_logs(logging.getLogger().handlers[0]) as logs:\n        logger.info(\"Test log message\")\n        logger.info(\"Test log message\\nwith multiple lines\")\n        cocotb.logging.strip_ansi = True\n        logger.info(\"Test log message\\nwith multiple lines\")\n    assert (\n        logs.msgs[0]\n        == f\"{ANSI.YELLOW_FG}abc{ANSI.DEFAULT_FG} INFO 0       exam Test log message{ANSI.DEFAULT}\"\n    )\n    assert (\n        logs.msgs[1]\n        == f\"{ANSI.YELLOW_FG}abc{ANSI.DEFAULT_FG} INFO 0       exam Test log message\\n                      with multiple lines{ANSI.DEFAULT}\"\n    )\n    assert (\n        logs.msgs[2]\n        == \"abc INFO 0       exam Test log message\\n                      with multiple lines\"\n    )\n\n\n@cocotb.test\nasync def test_log_prefix_default(_: object) -> None:\n    logger = logging.getLogger(\"example\")\n    logger.setLevel(logging.INFO)\n    with capture_logs(logging.getLogger().handlers[0]) as logs:\n        cocotb.logging.strip_ansi = False\n        logger.warning(\"First line\\nsecond line\")\n        cocotb.logging.strip_ansi = True\n        logger.warning(\"First line\\nsecond line\")\n\n    lines_colored = logs.msgs[0].splitlines()\n    assert len(lines_colored) == 2\n    assert lines_colored[0].endswith(\"First line\")\n    assert lines_colored[1].endswith(f\"second line{ANSI.DEFAULT}\")\n\n    lines_stripped = logs.msgs[1].splitlines()\n    assert len(lines_stripped) == 2\n    assert lines_stripped[0].endswith(\"First line\")\n    assert lines_stripped[1].endswith(\"second line\")\n\n    assert lines_stripped[0].find(\"First line\") == lines_stripped[1].find(\"second line\")\n    assert lines_colored[1].find(\"second line\") == lines_stripped[1].find(\"second line\")\n"
  },
  {
    "path": "tests/test_cases/test_log_prefix/test_log_prefix.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nfrom pathlib import Path\n\nimport pytest\n\nfrom cocotb_tools.runner import get_runner\n\nLANG = os.getenv(\"TOPLEVEL_LANG\", \"verilog\")\n\n\n@pytest.mark.skipif(LANG != \"verilog\", reason=\"This test only supports Verilog\")\ndef test_log_prefix() -> None:\n    sim = os.getenv(\"SIM\", \"icarus\")\n    runner = get_runner(sim)\n\n    pwd = Path(__file__).parent.absolute()\n\n    build_dir = runner.build_dir\n    runner.build(\n        sources=[pwd / \"top.sv\"],\n        hdl_toplevel=\"top\",\n        build_dir=build_dir / \"custom_prefix\",\n    )\n    runner.test(\n        test_module=\"log_prefix_tests\",\n        hdl_toplevel=\"top\",\n        hdl_toplevel_lang=LANG,\n        test_filter=\"test_log_prefix_custom\",\n        extra_env={\n            \"COCOTB_LOG_PREFIX\": \"{ANSI.YELLOW_FG}abc{ANSI.DEFAULT_FG} {record.levelname} {record.created_sim_time} {record.name[:4]:>10} \",\n            \"COCOTB_ANSI_OUTPUT\": \"1\",\n        },\n    )\n\n    runner.build(\n        sources=[pwd / \"top.sv\"],\n        hdl_toplevel=\"top\",\n        build_dir=build_dir / \"reduced_prefix\",\n    )\n    runner.test(\n        test_module=\"log_prefix_tests\",\n        hdl_toplevel=\"top\",\n        hdl_toplevel_lang=LANG,\n        test_filter=\"test_log_prefix_default\",\n    )\n\n    runner.build(\n        sources=[pwd / \"top.sv\"],\n        hdl_toplevel=\"top\",\n        build_dir=build_dir / \"full_prefix\",\n    )\n    runner.test(\n        test_module=\"log_prefix_tests\",\n        hdl_toplevel=\"top\",\n        hdl_toplevel_lang=LANG,\n        test_filter=\"test_log_prefix_default\",\n        extra_env={\"COCOTB_REDUCED_LOG_FMT\": \"0\"},\n    )\n"
  },
  {
    "path": "tests/test_cases/test_log_prefix/top.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`timescale 1 ps / 1 ps\n\nmodule top (\n    input logic placeholder\n);\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_logic_array_indexing/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifeq ($(TOPLEVEL_LANG),vhdl)\n\tVHDL_SOURCES := $(PWD)/test_logic_array_indexing.vhdl\nelse ifeq ($(TOPLEVEL_LANG),verilog)\n\tVERILOG_SOURCES := $(PWD)/test_logic_array_indexing.v\nelse\n    $(error \"Unsupported TOPLEVEL_LANG=$(TOPLEVEL_LANG)\")\nendif\n\nCOCOTB_TOPLEVEL := test_logic_array_indexing\nCOCOTB_TEST_MODULES := test_logic_array_indexing\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "tests/test_cases/test_logic_array_indexing/test_logic_array_indexing.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nfrom __future__ import annotations\n\nimport os\nfrom typing import Any\n\nimport pytest\n\nimport cocotb\nfrom cocotb.handle import LogicArrayObject, LogicObject, PackedObject\nfrom cocotb.triggers import RisingEdge, Timer\n\n\ndef inspect_signal(signal: Any, signal_name: str) -> None:\n    cocotb.log.info(f\"Signal name: {signal_name} {type(signal)}\")\n\n\nTOPLEVEL_LANG = os.getenv(\"TOPLEVEL_LANG\")\nassert TOPLEVEL_LANG is not None\nTOPLEVEL_LANG = TOPLEVEL_LANG.lower()\n\nSIM = cocotb.SIM_NAME.lower()\n\n\n@cocotb.test\n@cocotb.skipif(\n    TOPLEVEL_LANG != \"verilog\", reason=\"This test is only applicable to Verilog\"\n)\nasync def test_debug_array_verilog(dut: Any) -> None:\n    inspect_signal(dut.test_a, \"dut.test_a\")\n    assert type(dut.test_a) is PackedObject\n\n    with pytest.raises(TypeError):\n        dut.test_a[0]\n\n\n@cocotb.test\n@cocotb.skipif(TOPLEVEL_LANG != \"vhdl\", reason=\"This test is only applicable to VHDL\")\n@cocotb.xfail(\n    SIM.startswith(\"ghdl\"),\n    reason=\"GHDL uses VPI, which does not support array indexing\",\n)\nasync def test_debug_array_vhdl(dut: Any) -> None:\n    await Timer(1, unit=\"ns\")\n\n    inspect_signal(dut.test_a, \"dut.test_a\")\n    assert type(dut.test_a) is LogicArrayObject\n    inspect_signal(dut.test_b, \"dut.test_b\")\n    assert type(dut.test_b) is LogicArrayObject\n\n    inspect_signal(dut.test_a[0], \"test_a[0]\")\n    assert type(dut.test_a[0]) is LogicObject\n\n    handle = dut.test_a[0]\n    cocotb.log.info(f\"dut.test_a[0] Value = {handle.value}\")\n    await RisingEdge(handle)\n"
  },
  {
    "path": "tests/test_cases/test_logic_array_indexing/test_logic_array_indexing.v",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\nmodule test_logic_array_indexing;\n\n    reg [3:0] test_a;\n\n    initial begin\n        test_a   = 4'b0000;\n    end\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_logic_array_indexing/test_logic_array_indexing.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\n--! Using 'ieee' libraries\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n\nentity test_logic_array_indexing is\n    port (\n        test_a : out std_logic_vector(3 downto 0);\n        test_b : out std_logic_vector(3 downto 0)\n    );\nend test_logic_array_indexing;\n\narchitecture rtl of test_logic_array_indexing is\nbegin\n\n    process\n    begin\n        test_a <= (others => '0');\n        test_b <= (others => '0');\n\n        wait for 10 ns;\n\n        test_a(0) <= '1';\n\n        wait;\n    end process;\n\nend rtl;\n"
  },
  {
    "path": "tests/test_cases/test_long_log_msg/.gitignore",
    "content": "errlog\n"
  },
  {
    "path": "tests/test_cases/test_long_log_msg/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifeq ($(SIM),ghdl)\n\nall:\n\t@echo Skipping test because GHDL does not support identifiers longer than 1023 characters.\n\t@echo See also https://github.com/ghdl/ghdl/issues/1930\n\nelse\n\nPROJ_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n\nTOPLEVEL_LANG ?= verilog\n\nifeq ($(TOPLEVEL_LANG),verilog)\nVERILOG_SOURCES := $(PROJ_DIR)/test.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\nVHDL_SOURCES := $(PROJ_DIR)/test.vhd\nendif\n\nifneq ($(filter $(SIM),ius xcelium),)\nCOMPILE_ARGS += -v93\nendif\n\nCOCOTB_TOPLEVEL := test\n\nexport COCOTB_TEST_MODULES := test_long_log_msg\nexport COCOTB_LOG_LEVEL := DEBUG\n\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t$(MAKE) all 2>errlog\n\t! grep &>/dev/null \"Log message construction failed\" errlog\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_long_log_msg/test.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`timescale 1us/1us\n\nmodule test (\n    input logic KPFIVTM1LHY0OFUNXF0XZO1RV535NNU4A8QWR12BLQXJ98PMM1P552QC0T089PUJPB4POUJZLBS19S8XNMPGJV2QK3AJUW98X7RU56ZV4IMFIPDJI81E5B9HNW94Q9APLMMK3VPHS1VB1QVPQDG7VOTLY2NT3F4080OUXSC68H0JZF7KQ0O6GGN3DARXC03CSZL7TE6B7R47366SB54T5Q4MOR5BT3L5S0S3NM8MALXPHZKCUA6AR5U391GGDYG5LB7JGKAHSIREODSNGW7FAYNRTTXFFCRL4U3ZQA6DH1RKCFKGDG9WMF81IX5YSAINQSP14F2FJV0GYEM3R4LUFFSWOZKK5MGKS25RLROJFEQDC8L2XY07728MM7V516ZXH1YFS0AL1GPLH03N5EL0RQVY61EVEQEJCYDT0ZBBN1ZLC5BDQU83NF8N953MU6A99SDNPCTSOD2W9WY69ZL64JHURFHA5DT7KQC7T4KASR5CAG85ONU3F2XWYA97JHDN9V9SBS39MYMYERJ338O6JQYCHX7SH8FB2VL2PI7DOQWB3NXTA8CQM7YKT34L6U3O42WWMI7NHKUIBO4U9MBP176000FU39WET32RG4PHLYYGWFMKPYPCUFE46RFSQDELLXU31ZZH0OJCGEFUDR2USDUYZ3XPBQ6RC0XARPG2Z1GHCESILHJOF7503PHKWUKDVM2V18WB16CB7AAQ8C4C6E7FXUB3E89Q0ZJSKQFYNZPSKYKGXURV3V5C0SHU9QQ2GFUTP38ORCSWN0QYIX9H0SKJEXPC5U1D3QN9PRT0QPOVM7H5EGQ4E449YTSHUMJW1TT2S6EVIPPIR9ZMFCOWPYXRSNJEQ3OCKGDUW2ZX2AS7N5GBUY7NOAR2P7BK5YPOA6APVAH12V86V2YQZ2M56HLNAD785GI4GMFSCI5P3LNFM0CLSBUEJXCVT695N5D3GC8T0HKAN0BZDV1ZMI0WZ3QUVABNYFOJHXXBUW5OK5MQ46NMK3W0FMCKWVPP6265,\n    output logic o);\n\nassign o = KPFIVTM1LHY0OFUNXF0XZO1RV535NNU4A8QWR12BLQXJ98PMM1P552QC0T089PUJPB4POUJZLBS19S8XNMPGJV2QK3AJUW98X7RU56ZV4IMFIPDJI81E5B9HNW94Q9APLMMK3VPHS1VB1QVPQDG7VOTLY2NT3F4080OUXSC68H0JZF7KQ0O6GGN3DARXC03CSZL7TE6B7R47366SB54T5Q4MOR5BT3L5S0S3NM8MALXPHZKCUA6AR5U391GGDYG5LB7JGKAHSIREODSNGW7FAYNRTTXFFCRL4U3ZQA6DH1RKCFKGDG9WMF81IX5YSAINQSP14F2FJV0GYEM3R4LUFFSWOZKK5MGKS25RLROJFEQDC8L2XY07728MM7V516ZXH1YFS0AL1GPLH03N5EL0RQVY61EVEQEJCYDT0ZBBN1ZLC5BDQU83NF8N953MU6A99SDNPCTSOD2W9WY69ZL64JHURFHA5DT7KQC7T4KASR5CAG85ONU3F2XWYA97JHDN9V9SBS39MYMYERJ338O6JQYCHX7SH8FB2VL2PI7DOQWB3NXTA8CQM7YKT34L6U3O42WWMI7NHKUIBO4U9MBP176000FU39WET32RG4PHLYYGWFMKPYPCUFE46RFSQDELLXU31ZZH0OJCGEFUDR2USDUYZ3XPBQ6RC0XARPG2Z1GHCESILHJOF7503PHKWUKDVM2V18WB16CB7AAQ8C4C6E7FXUB3E89Q0ZJSKQFYNZPSKYKGXURV3V5C0SHU9QQ2GFUTP38ORCSWN0QYIX9H0SKJEXPC5U1D3QN9PRT0QPOVM7H5EGQ4E449YTSHUMJW1TT2S6EVIPPIR9ZMFCOWPYXRSNJEQ3OCKGDUW2ZX2AS7N5GBUY7NOAR2P7BK5YPOA6APVAH12V86V2YQZ2M56HLNAD785GI4GMFSCI5P3LNFM0CLSBUEJXCVT695N5D3GC8T0HKAN0BZDV1ZMI0WZ3QUVABNYFOJHXXBUW5OK5MQ46NMK3W0FMCKWVPP6265;\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_long_log_msg/test.vhd",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nentity test is\n    port (\n        KPFIVTM1LHY0OFUNXF0XZO1RV535NNU4A8QWR12BLQXJ98PMM1P552QC0T089PUJPB4POUJZLBS19S8XNMPGJV2QK3AJUW98X7RU56ZV4IMFIPDJI81E5B9HNW94Q9APLMMK3VPHS1VB1QVPQDG7VOTLY2NT3F4080OUXSC68H0JZF7KQ0O6GGN3DARXC03CSZL7TE6B7R47366SB54T5Q4MOR5BT3L5S0S3NM8MALXPHZKCUA6AR5U391GGDYG5LB7JGKAHSIREODSNGW7FAYNRTTXFFCRL4U3ZQA6DH1RKCFKGDG9WMF81IX5YSAINQSP14F2FJV0GYEM3R4LUFFSWOZKK5MGKS25RLROJFEQDC8L2XY07728MM7V516ZXH1YFS0AL1GPLH03N5EL0RQVY61EVEQEJCYDT0ZBBN1ZLC5BDQU83NF8N953MU6A99SDNPCTSOD2W9WY69ZL64JHURFHA5DT7KQC7T4KASR5CAG85ONU3F2XWYA97JHDN9V9SBS39MYMYERJ338O6JQYCHX7SH8FB2VL2PI7DOQWB3NXTA8CQM7YKT34L6U3O42WWMI7NHKUIBO4U9MBP176000FU39WET32RG4PHLYYGWFMKPYPCUFE46RFSQDELLXU31ZZH0OJCGEFUDR2USDUYZ3XPBQ6RC0XARPG2Z1GHCESILHJOF7503PHKWUKDVM2V18WB16CB7AAQ8C4C6E7FXUB3E89Q0ZJSKQFYNZPSKYKGXURV3V5C0SHU9QQ2GFUTP38ORCSWN0QYIX9H0SKJEXPC5U1D3QN9PRT0QPOVM7H5EGQ4E449YTSHUMJW1TT2S6EVIPPIR9ZMFCOWPYXRSNJEQ3OCKGDUW2ZX2AS7N5GBUY7NOAR2P7BK5YPOA6APVAH12V86V2YQZ2M56HLNAD785GI4GMFSCI5P3LNFM0CLSBUEJXCVT695N5D3GC8T0HKAN0BZDV1ZMI0WZ3QUVABNYFOJHXXBUW5OK5MQ46NMK3W0FMCKWVPP6265 : in integer;\n        o : out integer);\nend entity test;\n\narchitecture rtl of test is\nbegin\n    o <= KPFIVTM1LHY0OFUNXF0XZO1RV535NNU4A8QWR12BLQXJ98PMM1P552QC0T089PUJPB4POUJZLBS19S8XNMPGJV2QK3AJUW98X7RU56ZV4IMFIPDJI81E5B9HNW94Q9APLMMK3VPHS1VB1QVPQDG7VOTLY2NT3F4080OUXSC68H0JZF7KQ0O6GGN3DARXC03CSZL7TE6B7R47366SB54T5Q4MOR5BT3L5S0S3NM8MALXPHZKCUA6AR5U391GGDYG5LB7JGKAHSIREODSNGW7FAYNRTTXFFCRL4U3ZQA6DH1RKCFKGDG9WMF81IX5YSAINQSP14F2FJV0GYEM3R4LUFFSWOZKK5MGKS25RLROJFEQDC8L2XY07728MM7V516ZXH1YFS0AL1GPLH03N5EL0RQVY61EVEQEJCYDT0ZBBN1ZLC5BDQU83NF8N953MU6A99SDNPCTSOD2W9WY69ZL64JHURFHA5DT7KQC7T4KASR5CAG85ONU3F2XWYA97JHDN9V9SBS39MYMYERJ338O6JQYCHX7SH8FB2VL2PI7DOQWB3NXTA8CQM7YKT34L6U3O42WWMI7NHKUIBO4U9MBP176000FU39WET32RG4PHLYYGWFMKPYPCUFE46RFSQDELLXU31ZZH0OJCGEFUDR2USDUYZ3XPBQ6RC0XARPG2Z1GHCESILHJOF7503PHKWUKDVM2V18WB16CB7AAQ8C4C6E7FXUB3E89Q0ZJSKQFYNZPSKYKGXURV3V5C0SHU9QQ2GFUTP38ORCSWN0QYIX9H0SKJEXPC5U1D3QN9PRT0QPOVM7H5EGQ4E449YTSHUMJW1TT2S6EVIPPIR9ZMFCOWPYXRSNJEQ3OCKGDUW2ZX2AS7N5GBUY7NOAR2P7BK5YPOA6APVAH12V86V2YQZ2M56HLNAD785GI4GMFSCI5P3LNFM0CLSBUEJXCVT695N5D3GC8T0HKAN0BZDV1ZMI0WZ3QUVABNYFOJHXXBUW5OK5MQ46NMK3W0FMCKWVPP6265;\nend architecture rtl;\n"
  },
  {
    "path": "tests/test_cases/test_long_log_msg/test_long_log_msg.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_access_long_name(dut):\n    dut.KPFIVTM1LHY0OFUNXF0XZO1RV535NNU4A8QWR12BLQXJ98PMM1P552QC0T089PUJPB4POUJZLBS19S8XNMPGJV2QK3AJUW98X7RU56ZV4IMFIPDJI81E5B9HNW94Q9APLMMK3VPHS1VB1QVPQDG7VOTLY2NT3F4080OUXSC68H0JZF7KQ0O6GGN3DARXC03CSZL7TE6B7R47366SB54T5Q4MOR5BT3L5S0S3NM8MALXPHZKCUA6AR5U391GGDYG5LB7JGKAHSIREODSNGW7FAYNRTTXFFCRL4U3ZQA6DH1RKCFKGDG9WMF81IX5YSAINQSP14F2FJV0GYEM3R4LUFFSWOZKK5MGKS25RLROJFEQDC8L2XY07728MM7V516ZXH1YFS0AL1GPLH03N5EL0RQVY61EVEQEJCYDT0ZBBN1ZLC5BDQU83NF8N953MU6A99SDNPCTSOD2W9WY69ZL64JHURFHA5DT7KQC7T4KASR5CAG85ONU3F2XWYA97JHDN9V9SBS39MYMYERJ338O6JQYCHX7SH8FB2VL2PI7DOQWB3NXTA8CQM7YKT34L6U3O42WWMI7NHKUIBO4U9MBP176000FU39WET32RG4PHLYYGWFMKPYPCUFE46RFSQDELLXU31ZZH0OJCGEFUDR2USDUYZ3XPBQ6RC0XARPG2Z1GHCESILHJOF7503PHKWUKDVM2V18WB16CB7AAQ8C4C6E7FXUB3E89Q0ZJSKQFYNZPSKYKGXURV3V5C0SHU9QQ2GFUTP38ORCSWN0QYIX9H0SKJEXPC5U1D3QN9PRT0QPOVM7H5EGQ4E449YTSHUMJW1TT2S6EVIPPIR9ZMFCOWPYXRSNJEQ3OCKGDUW2ZX2AS7N5GBUY7NOAR2P7BK5YPOA6APVAH12V86V2YQZ2M56HLNAD785GI4GMFSCI5P3LNFM0CLSBUEJXCVT695N5D3GC8T0HKAN0BZDV1ZMI0WZ3QUVABNYFOJHXXBUW5OK5MQ46NMK3W0FMCKWVPP6265\n"
  },
  {
    "path": "tests/test_cases/test_max_failures/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCOCOTB_TEST_MODULES := test_max_failures\n\nexport COCOTB_MAX_FAILURES := 1\n\n# ensure the test runs, squash any error code, and ensure a failing test was reported\n.PHONY: override_for_this_test\noverride_for_this_test:\n\trm -f results.xml\n\t-$(MAKE) all\n\t$(call check_for_results_file)\n\ttest $$(python -m cocotb_tools.combine_results | grep \"Failure in testsuite\" | wc -l) -eq 1 && \\\n\tpython -m cocotb_tools.combine_results | grep \"2 TestCases\" &>/dev/null && \\\n\trm -f results.xml\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_max_failures/test_max_failures.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.regression import RegressionTerminated\n\n\n@cocotb.test\nasync def test_max_failures(dut: object) -> None:\n    \"\"\"Test that the test fails after the first failure when COCOTB_MAX_FAILURES is set to 1.\"\"\"\n    assert False, \"This test should fail immediately due to max failures limit.\"\n\n\n@cocotb.test(expect_error=RegressionTerminated)\nasync def test_should_not_run(dut: object) -> None:\n    \"\"\"This test should not run because the previous test should have already caused the test suite to fail.\"\"\"\n"
  },
  {
    "path": "tests/test_cases/test_module_var_empty/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# test COCOTB_TEST_MODULES is empty\n# should cause regression initialization failure so no results.xml is written\n\nCOCOTB_TEST_MODULES := \" \"\n\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t-$(MAKE) all\n\t@test ! -f $(COCOTB_RESULTS_FILE)\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_module_var_messy/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# test COCOTB_TEST_MODULES contains leading and trailing separators\n# should cause regression initialization failure so no results.xml is written\n\nCOCOTB_TEST_MODULES=\" , test_nothing  ,\"\n\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t-$(MAKE) all\n\t@test ! -f $(COCOTB_RESULTS_FILE)\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_module_var_messy/test_nothing.py",
    "content": "\"\"\"This test module is purposefully empty\"\"\"\n"
  },
  {
    "path": "tests/test_cases/test_module_without_tests/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# test COCOTB_TEST_MODULES is set\n# should cause regression initialization failure so no results.xml is written\n\nCOCOTB_TEST_MODULES=test_nothing\n\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t-$(MAKE) all\n\t@test ! -f $(COCOTB_RESULTS_FILE)\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_module_without_tests/test_nothing.py",
    "content": "\"\"\"This test module is purposefully empty\"\"\"\n"
  },
  {
    "path": "tests/test_cases/test_multi_dimension_array/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2016, 2018 Potential Ventures Ltd\n# Copyright (c) 2016 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\nifeq ($(SIM),)\nUSING_ICARUS := 1\nendif\n\nifeq ($(shell echo $(SIM) | tr A-Z a-z),icarus)\nUSING_ICARUS := 1\nendif\n\nifneq ($(USING_ICARUS),)\nICARUS_MIN := 12.0\nICARUS_VERSION := $(shell iverilog -V 2>/dev/null | head -n1 | cut -d ' ' -f 4)\nMIN_VERSION := $(shell printf \"%s\\n%s\\n\" \"$(ICARUS_MIN)\" \"$(ICARUS_VERSION)\" | sort -g | head -1)\nifneq ($(MIN_VERSION),$(ICARUS_MIN))\nSKIP := 1\n$(info Skipping test_multi_dimension_array since icarus < v$(ICARUS_MIN) doesn't support the design syntax)\nendif\nendif\n\nifeq ($(SKIP),)\n\ninclude ../../designs/multi_dimension_array/Makefile\n\nCOCOTB_TEST_MODULES = test_cocotb_array\n\nelse\n\nall:\n\nclean::\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_multi_dimension_array/test_cocotb_array.py",
    "content": "from __future__ import annotations\n\nimport os\nfrom typing import Any\n\nimport cocotb\nfrom cocotb.handle import ArrayObject, LogicArrayObject, LogicObject\nfrom cocotb.triggers import Timer\n\nSIM_NAME = cocotb.SIM_NAME.lower()\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\nquesta_vpi_compat = (\n    LANGUAGE == \"verilog\"\n    and SIM_NAME.startswith(\"modelsim\")\n    and os.getenv(\"COCOTB__QUESTA_MODE\", \"compat\") == \"compat\"\n)\n\n\n@cocotb.test()\nasync def test_in_vect_packed(dut):\n    assert isinstance(dut.in_vect_packed, LogicArrayObject)\n    assert len(dut.in_vect_packed) == 3\n\n    test_value = 0x5\n    dut.in_vect_packed.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_vect_packed.value == test_value\n\n\n@cocotb.test()\nasync def test_in_vect_unpacked(dut):\n    assert isinstance(dut.in_vect_unpacked, ArrayObject)\n    assert len(dut.in_vect_unpacked) == 3\n\n    dut.in_vect_unpacked[0]\n    assert isinstance(dut.in_vect_unpacked[0], LogicObject)\n\n    test_value = [0x1, 0x0, 0x1]\n    dut.in_vect_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_vect_unpacked.value == test_value\n\n\n@cocotb.test()\nasync def test_in_arr(dut):\n    assert isinstance(dut.in_arr, LogicArrayObject)\n    assert len(dut.in_arr) == 3\n\n    test_value = 0x5\n    dut.in_arr.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_arr.value == test_value\n\n\n@cocotb.test()\nasync def test_in_2d_vect_packed_packed(dut):\n    assert isinstance(dut.in_2d_vect_packed_packed, LogicArrayObject)\n    assert len(dut.in_2d_vect_packed_packed) == 9\n\n    test_value = (0x5 << 6) | (0x5 << 3) | 0x5\n    dut.in_2d_vect_packed_packed.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_2d_vect_packed_packed.value == test_value\n\n\n@cocotb.test()\nasync def test_in_2d_vect_packed_unpacked(dut):\n    assert isinstance(dut.in_2d_vect_packed_unpacked, ArrayObject)\n    assert len(dut.in_2d_vect_packed_unpacked) == 3\n\n    dut.in_2d_vect_packed_unpacked[0]\n    assert isinstance(dut.in_2d_vect_packed_unpacked[0], LogicArrayObject)\n    assert len(dut.in_2d_vect_packed_unpacked[0]) == 3\n\n    test_value = [0x5, 0x5, 0x5]\n    dut.in_2d_vect_packed_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_2d_vect_packed_unpacked.value == test_value\n\n\n# Verilator doesn't support multi-dimensional unpacked arrays (gh-3611)\n# Icarus flattens multi-dimensional unpacked arrays (gh-2595)\n@cocotb.test(\n    expect_fail=SIM_NAME.startswith(\"icarus\"),\n)\nasync def test_in_2d_vect_unpacked_unpacked(dut):\n    assert isinstance(dut.in_2d_vect_unpacked_unpacked, ArrayObject)\n    assert len(dut.in_2d_vect_unpacked_unpacked) == 3\n\n    dut.in_2d_vect_unpacked_unpacked[0]\n    assert isinstance(dut.in_2d_vect_unpacked_unpacked[0], ArrayObject)\n    assert len(dut.in_2d_vect_unpacked_unpacked[0]) == 3\n\n    dut.in_2d_vect_unpacked_unpacked[0][0]\n    assert isinstance(dut.in_2d_vect_unpacked_unpacked[0][0], LogicObject)\n\n    test_value = 3 * [[0x1, 0x0, 0x1]]\n    dut.in_2d_vect_unpacked_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_2d_vect_unpacked_unpacked.value == test_value\n\n\n@cocotb.test()\nasync def test_in_arr_packed(dut):\n    assert isinstance(dut.in_arr_packed, LogicArrayObject)\n    assert len(dut.in_arr_packed) == 9\n\n    test_value = 365\n    dut.in_arr_packed.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_arr_packed.value == test_value\n\n\n@cocotb.test()\nasync def test_in_arr_unpacked(dut):\n    assert isinstance(dut.in_arr_unpacked, ArrayObject)\n    assert len(dut.in_arr_unpacked) == 3\n\n    dut.in_arr_unpacked[0]\n    assert isinstance(dut.in_arr_unpacked[0], LogicArrayObject)\n    assert len(dut.in_arr_unpacked[0]) == 3\n\n    test_value = [0x5, 0x5, 0x5]\n    dut.in_arr_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_arr_unpacked.value == test_value\n\n\n@cocotb.test()\nasync def test_in_2d_arr(dut):\n    assert isinstance(dut.in_2d_arr, LogicArrayObject)\n    assert len(dut.in_2d_arr) == 9\n\n    test_value = 365\n    dut.in_2d_arr.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_2d_arr.value == test_value\n\n\n@cocotb.test()\nasync def test_in_vect_packed_packed_packed(dut):\n    assert isinstance(dut.in_vect_packed_packed_packed, LogicArrayObject)\n    assert len(dut.in_vect_packed_packed_packed) == 27\n\n    test_value = 95869805\n    dut.in_vect_packed_packed_packed.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_vect_packed_packed_packed.value == test_value\n\n\n# Questa (VPI/compat mode) is unable to access elements of a logic array if the last dimension is unpacked (gh-2605)\n# Verilator doesn't support multi-dimensional unpacked arrays (gh-3611)\n@cocotb.test(expect_error=IndexError if questa_vpi_compat else ())\nasync def test_in_vect_packed_packed_unpacked(dut):\n    assert isinstance(dut.in_vect_packed_packed_unpacked, ArrayObject)\n    assert len(dut.in_vect_packed_packed_unpacked) == 3\n\n    dut.in_vect_packed_packed_unpacked[0]\n    assert isinstance(dut.in_vect_packed_packed_unpacked[0], LogicArrayObject)\n    assert len(dut.in_vect_packed_packed_unpacked[0]) == 9\n\n    test_value = [365, 365, 365]\n    dut.in_vect_packed_packed_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_vect_packed_packed_unpacked.value == test_value\n\n\n# Icarus flattens multi-dimensional unpacked arrays (gh-2595)\n@cocotb.test(\n    expect_fail=SIM_NAME.startswith(\"icarus\"),\n)\nasync def test_in_vect_packed_unpacked_unpacked(dut):\n    assert isinstance(dut.in_vect_packed_unpacked_unpacked, ArrayObject)\n    assert len(dut.in_vect_packed_unpacked_unpacked) == 3\n\n    dut.in_vect_packed_unpacked_unpacked[0]\n    assert isinstance(dut.in_vect_packed_unpacked_unpacked[0], ArrayObject)\n    assert len(dut.in_vect_packed_unpacked_unpacked[0]) == 3\n\n    dut.in_vect_packed_unpacked_unpacked[0][0]\n    assert isinstance(dut.in_vect_packed_unpacked_unpacked[0][0], LogicArrayObject)\n    assert len(dut.in_vect_packed_unpacked_unpacked[0][0]) == 3\n\n    test_value = 3 * [3 * [5]]\n    dut.in_vect_packed_unpacked_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_vect_packed_unpacked_unpacked.value == test_value\n\n\n# Icarus flattens multi-dimensional unpacked arrays (gh-2595)\n@cocotb.test(\n    expect_fail=SIM_NAME.startswith(\"icarus\"),\n)\nasync def test_in_vect_unpacked_unpacked_unpacked(dut):\n    assert isinstance(dut.in_vect_unpacked_unpacked_unpacked, ArrayObject)\n    assert len(dut.in_vect_unpacked_unpacked_unpacked) == 3\n\n    dut.in_vect_unpacked_unpacked_unpacked[0]\n    assert isinstance(dut.in_vect_unpacked_unpacked_unpacked[0], ArrayObject)\n    assert len(dut.in_vect_unpacked_unpacked_unpacked[0]) == 3\n\n    dut.in_vect_unpacked_unpacked_unpacked[0][0]\n    assert isinstance(dut.in_vect_unpacked_unpacked_unpacked[0][0], ArrayObject)\n    assert len(dut.in_vect_unpacked_unpacked_unpacked[0][0]) == 3\n\n    dut.in_vect_unpacked_unpacked_unpacked[0][0][0]\n    assert isinstance(dut.in_vect_unpacked_unpacked_unpacked[0][0][0], LogicObject)\n\n    test_value = 3 * [3 * [[1, 0, 1]]]\n    dut.in_vect_unpacked_unpacked_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_vect_unpacked_unpacked_unpacked.value == test_value\n\n\n@cocotb.test()\nasync def test_in_arr_packed_packed(dut):\n    assert isinstance(dut.in_arr_packed_packed, LogicArrayObject)\n    assert len(dut.in_arr_packed_packed) == 27\n\n    test_value = (365 << 18) | (365 << 9) | (365)\n    dut.in_arr_packed_packed.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_arr_packed_packed.value == test_value\n\n\n# Questa (VPI/compat mode) is unable to access elements of a logic array if the last dimension is unpacked (gh-2605)\n@cocotb.test(expect_error=IndexError if questa_vpi_compat else ())\nasync def test_in_arr_packed_unpacked(dut):\n    assert isinstance(dut.in_arr_packed_unpacked, ArrayObject)\n    assert len(dut.in_arr_packed_unpacked) == 3\n\n    dut.in_arr_packed_unpacked[0]\n    assert isinstance(dut.in_arr_packed_unpacked[0], LogicArrayObject)\n    assert len(dut.in_arr_packed_unpacked[0]) == 9\n\n    test_value = [365, 365, 365]\n    dut.in_arr_packed_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_arr_packed_unpacked.value == test_value\n\n\n# Icarus flattens multi-dimensional unpacked arrays (gh-2595)\n@cocotb.test(\n    expect_fail=SIM_NAME.startswith(\"icarus\"),\n)\nasync def test_in_arr_unpacked_unpacked(dut):\n    assert isinstance(dut.in_arr_unpacked_unpacked, ArrayObject)\n    assert len(dut.in_arr_unpacked_unpacked) == 3\n\n    dut.in_arr_unpacked_unpacked[0]\n    assert isinstance(dut.in_arr_unpacked_unpacked[0], ArrayObject)\n    assert len(dut.in_arr_unpacked_unpacked[0]) == 3\n\n    dut.in_arr_unpacked_unpacked[0][0]\n    assert isinstance(dut.in_arr_unpacked_unpacked[0][0], LogicArrayObject)\n    assert len(dut.in_arr_unpacked_unpacked[0][0]) == 3\n\n    test_value = 3 * [3 * [5]]\n    dut.in_arr_unpacked_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_arr_unpacked_unpacked.value == test_value\n\n\n@cocotb.test()\nasync def test_in_2d_arr_packed(dut):\n    assert isinstance(dut.in_2d_arr_packed, LogicArrayObject)\n    assert len(dut.in_2d_arr_packed) == 27\n\n    test_value = (365 << 18) | (365 << 9) | (365)\n    dut.in_2d_arr_packed.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_2d_arr_packed.value == test_value\n\n\n# Questa (VPI/compat mode) is unable to access elements of a logic array if the last dimension is unpacked (gh-2605)\n@cocotb.test(expect_error=IndexError if questa_vpi_compat else ())\nasync def test_in_2d_arr_unpacked(dut):\n    assert isinstance(dut.in_2d_arr_unpacked, ArrayObject)\n    assert len(dut.in_2d_arr_unpacked) == 3\n\n    dut.in_2d_arr_unpacked[0]\n    assert isinstance(dut.in_2d_arr_unpacked[0], LogicArrayObject)\n    assert len(dut.in_2d_arr_unpacked[0]) == 9\n\n    test_value = [365, 365, 365]\n    dut.in_2d_arr_unpacked.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_2d_arr_unpacked.value == test_value\n\n\n@cocotb.test()\nasync def test_in_3d_arr(dut):\n    assert isinstance(dut.in_3d_arr, LogicArrayObject)\n    assert len(dut.in_3d_arr) == 27\n\n    test_value = (365 << 18) | (365 << 9) | (365)\n    dut.in_3d_arr.value = test_value\n    await Timer(1, \"ns\")\n    assert dut.out_3d_arr.value == test_value\n\n\n# Riviera fails when trying to access packed structs (gh-4753)\n@cocotb.test(skip=cocotb.SIM_NAME.lower().startswith(\"riviera\"))\nasync def test_struct(dut: Any) -> None:\n    assert isinstance(dut.in_struct_packed, LogicArrayObject)\n    assert len(dut.in_struct_packed) == 24\n\n    dut.in_struct_packed.value = 123\n    await Timer(1)\n    assert dut.out_struct_packed.value == 123\n\n\n# Riviera crashes when trying to access packed structs (gh-4753)\n@cocotb.test(skip=cocotb.SIM_NAME.lower().startswith(\"riviera\"))\nasync def test_struct_1d_arr_packed(dut: Any) -> None:\n    assert isinstance(dut.in_struct_packed_array_packed, LogicArrayObject)\n    assert len(dut.in_struct_packed_array_packed) == 72\n\n    dut.in_struct_packed_array_packed.value = 123456\n    await Timer(1)\n    assert dut.out_struct_packed_array_packed.value == 123456\n\n\n# Riviera crashes when trying to access packed structs (gh-4753)\n@cocotb.test(skip=cocotb.SIM_NAME.lower().startswith(\"riviera\"))\nasync def test_struct_1d_arr_unpacked(dut: Any) -> None:\n    assert isinstance(dut.in_struct_packed_array_unpacked, ArrayObject)\n    assert len(dut.in_struct_packed_array_unpacked) == 3\n\n    assert isinstance(dut.in_struct_packed_array_unpacked[0], LogicArrayObject)\n    assert len(dut.in_struct_packed_array_unpacked[0]) == 24\n\n    dut.in_struct_packed_array_unpacked.value = [6798, 2000, 3000]\n    await Timer(1)\n    assert dut.out_struct_packed_array_unpacked.value == [6798, 2000, 3000]\n    assert dut.out_struct_packed_array_unpacked[2].value == 6798\n\n\n# Riviera crashes when trying to access packed structs (gh-4753)\n@cocotb.test(skip=cocotb.SIM_NAME.lower().startswith(\"riviera\"))\nasync def test_struct_2d_arr_packed_packed(dut: Any) -> None:\n    assert isinstance(dut.in_struct_packed_arr_packed_packed, LogicArrayObject)\n    assert len(dut.in_struct_packed_arr_packed_packed) == 216\n\n    dut.in_struct_packed_arr_packed_packed.value = 123458123456123\n    await Timer(1)\n    assert dut.in_struct_packed_arr_packed_packed.value == 123458123456123\n\n\n# Riviera crashes when trying to access packed structs (gh-4753)\n@cocotb.test(skip=cocotb.SIM_NAME.lower().startswith(\"riviera\"))\nasync def test_struct_2d_arr_packed_unpacked(dut: Any) -> None:\n    assert isinstance(dut.in_struct_packed_arr_packed_unpacked, ArrayObject)\n    assert len(dut.in_struct_packed_arr_packed_unpacked) == 3\n    assert isinstance(dut.in_struct_packed_arr_packed_unpacked[0], LogicArrayObject)\n    assert len(dut.in_struct_packed_arr_packed_unpacked[0]) == 72\n\n\n# Icarus flattens multi-dimensional unpacked arrays (gh-2595)\n# Riviera crashes when trying to access packed structs (gh-4753)\n@cocotb.test(\n    expect_fail=cocotb.SIM_NAME.lower().startswith(\"icarus\"),\n    skip=cocotb.SIM_NAME.lower().startswith(\"riviera\"),\n)\nasync def test_struct_2d_arr_unpacked_unpacked(dut: Any) -> None:\n    assert isinstance(dut.in_struct_packed_arr_unpacked_unpacked, ArrayObject)\n    assert len(dut.in_struct_packed_arr_unpacked_unpacked) == 3\n    assert isinstance(dut.in_struct_packed_arr_unpacked_unpacked[0], ArrayObject)\n    assert len(dut.in_struct_packed_arr_unpacked_unpacked[0]) == 3\n    assert isinstance(\n        dut.in_struct_packed_arr_unpacked_unpacked[0][2], LogicArrayObject\n    )\n    assert len(dut.in_struct_packed_arr_unpacked_unpacked[0][2]) == 24\n"
  },
  {
    "path": "tests/test_cases/test_multi_level_module_path/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# test COCOTB_TEST_MODULES contains a multi-level Python module path, separated by period\n\nCOCOTB_TEST_MODULES = test_package.test_module_path\n\nexport PYTHONPATH := .\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_multi_level_module_path/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_cases/test_multi_level_module_path/test_package/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_cases/test_multi_level_module_path/test_package/test_module_path.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"Test for multi-level module path in MODULE\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_pass(_):\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_null_ranges/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifeq ($(TOPLEVEL_LANG),vhdl)\n\nifneq ($(filter $(SIM),ius xcelium),)\n    COMPILE_ARGS += -v93\nendif\n\nCOCOTB_TOPLEVEL := null_ranges_top\nCOCOTB_TEST_MODULES := test_null_ranges\nVHDL_SOURCES := null_ranges_pkg.vhdl null_ranges.vhdl\n\n# cocotb inclusions\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nelse\nall:\n\t$(info Skipping simulation as only TOPLEVEL_LANG=vhdl is supported)\n\nclean::\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_null_ranges/null_ranges.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n\nuse work.null_ranges_pkg.unsignedArrayType;\n\nentity null_ranges_top is\n  port(\n    null_vector_port_to     : in std_logic_vector(10 to 4);\n    null_vector_port_downto : in std_logic_vector(-1 downto 0);\n    null_array_port_to      : in unsignedArrayType(0 to -1);\n    null_array_port_downto  : in unsignedArrayType(-7 downto 0);\n    null_string_port_to     : in string(3 to -2);\n    null_string_port_downto : in string(0 downto 7)\n  );\nend entity null_ranges_top;\n\narchitecture rtl of null_ranges_top is\n  signal null_vector_signal_to     : std_logic_vector(10 to 4);\n  signal null_vector_signal_downto : std_logic_vector(-1 downto 0);\n  signal null_array_signal_to      : unsignedArrayType(0 to -1);\n  signal null_array_signal_downto  : unsignedArrayType(-7 downto 0);\n  signal null_string_signal_to     : string(3 to -2);\n  signal null_string_signal_downto : string(0 downto 7);\nbegin\nend architecture rtl;\n"
  },
  {
    "path": "tests/test_cases/test_null_ranges/null_ranges_pkg.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\n\nlibrary ieee;\n\nuse ieee.numeric_std.all;\n\npackage null_ranges_pkg is\n\n    type unsignedArrayType is array (natural range <>) of unsigned(7 downto 0);\n\nend package null_ranges_pkg;\n\npackage body null_ranges_pkg is\nend package body null_ranges_pkg;\n"
  },
  {
    "path": "tests/test_cases/test_null_ranges/test_null_ranges.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\nfrom typing import Any\n\nimport pytest\n\nimport cocotb\nfrom cocotb.types import LogicArray, Range\n\nis_questa_vhpi = (\n    cocotb.SIM_NAME.lower().startswith(\"modelsim\")\n    and os.environ[\"VHDL_GPI_INTERFACE\"] == \"vhpi\"\n)\nis_xcelium = cocotb.SIM_NAME.lower().startswith(\"xmsim\")\nis_riviera = cocotb.SIM_NAME.lower().startswith(\"riviera\")\nis_ghdl = cocotb.SIM_NAME.lower().startswith(\"ghdl\")\n\n\n@cocotb.parametrize(\n    (\n        (\"signal_name\", \"high\", \"direction\", \"low\"),\n        (\n            (\"null_vector_port_to\", 10, \"to\", 4),\n            (\"null_vector_port_downto\", -1, \"downto\", 0),\n            (\"null_vector_signal_to\", 10, \"to\", 4),\n            (\"null_vector_signal_downto\", -1, \"downto\", 0),\n        ),\n    )\n)\n@cocotb.xfail(\n    is_questa_vhpi,\n    reason=\"Questa does not return correct direction for ranges (gh-4236)\",\n)\n@cocotb.xfail(\n    is_ghdl,\n    raises=Exception,\n    reason=\"GHDL cannot find null-ranged vectors (gh-5458)\",\n)\n@cocotb.test\nasync def test_null_vector(\n    dut: Any,\n    signal_name: str,\n    high: int,\n    direction: str,\n    low: int,\n) -> None:\n    handle = getattr(dut, signal_name)\n    assert handle.range == Range(high, direction, low)\n    assert len(handle) == 0\n    assert handle.value == LogicArray([])\n    assert handle.value.range == Range(high, direction, low)\n    with pytest.raises(ValueError):\n        handle.value = 0x1\n\n\n@cocotb.parametrize(\n    (\n        (\"signal_name\", \"high\", \"direction\", \"low\"),\n        (\n            (\"null_array_port_to\", 0, \"to\", -1),\n            (\"null_array_port_downto\", -7, \"downto\", 0),\n            (\"null_array_signal_to\", 0, \"to\", -1),\n            (\"null_array_signal_downto\", -7, \"downto\", 0),\n        ),\n    )\n)\n@cocotb.xfail(\n    is_questa_vhpi,\n    reason=\"Questa does not return correct direction for ranges (gh-4236)\",\n)\n@cocotb.xfail(\n    is_ghdl,\n    reason=\"GHDL uses VPI and cannot represent null-ranged objects, the ranges will mismatch\",\n)\n@cocotb.test\nasync def test_null_array(\n    dut: Any,\n    signal_name: str,\n    high: int,\n    direction: str,\n    low: int,\n) -> None:\n    handle = getattr(dut, signal_name)\n    assert handle.range == Range(high, direction, low)\n    assert len(handle) == 0\n    assert handle.value == []\n    assert len(handle.value) == 0\n    assert handle.value.range == Range(high, direction, low)\n    with pytest.raises(ValueError):\n        handle.value = [1, 2, 3, 4]\n\n\n@cocotb.parametrize(\n    (\n        (\"signal_name\", \"high\", \"direction\", \"low\"),\n        (\n            (\"null_string_port_to\", 3, \"to\", -2),\n            (\"null_string_port_downto\", 0, \"downto\", 7),\n            (\"null_string_signal_to\", 3, \"to\", -2),\n            (\"null_string_signal_downto\", 0, \"downto\", 7),\n        ),\n    )\n)\n@cocotb.xfail(\n    is_questa_vhpi,\n    raises=AttributeError,\n    reason=\"Questa discovers null-ranged strings as vhpiSigDeclK and vhpiPortDeclK (gh-5461)\",\n)\n@cocotb.xfail(\n    is_xcelium,\n    raises=AttributeError,\n    reason=\"Xcelium discovers null-ranged strings as vhpiSigDeclK and vhpiPortDeclK (gh-5460)\",\n)\n@cocotb.skipif(\n    is_riviera,\n    reason=\"Riviera crashes when accessing null-ranged string objects (gh-5459)\",\n)\n@cocotb.xfail(\n    is_ghdl,\n    reason=\"GHDL uses VPI and cannot represent null-ranged objects, the ranges will mismatch\",\n)\n@cocotb.test\nasync def test_null_string(\n    dut: Any,\n    signal_name: str,\n    high: int,\n    direction: str,\n    low: int,\n) -> None:\n    handle = getattr(dut, signal_name)\n    assert handle.range == Range(high, direction, low)\n    assert len(handle) == 0\n    assert handle.value == b\"\"\n"
  },
  {
    "path": "tests/test_cases/test_one_empty_test/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES = test_one_empty_test\n"
  },
  {
    "path": "tests/test_cases/test_one_empty_test/test_one_empty_test.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test\nasync def test(_):\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_package/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifeq ($(SIM),)\nUSING_ICARUS := 1\nendif\n\nifeq ($(shell echo $(SIM) | tr A-Z a-z),icarus)\nUSING_ICARUS := 1\nendif\n\nifneq ($(USING_ICARUS),)\nICARUS_MIN := 12.0\nICARUS_VERSION := $(shell iverilog -V 2>/dev/null | head -n1 | cut -d ' ' -f 4)\nMIN_VERSION := $(shell printf \"%s\\n%s\\n\" \"$(ICARUS_MIN)\" \"$(ICARUS_VERSION)\" | sort -g | head -1)\nifneq ($(MIN_VERSION),$(ICARUS_MIN))\nSKIP := 1\n$(info \"Skipping test_defaultless_parameter since icarus < v12.0 doesn't support vpiInstance iteration\")\nendif\nendif\n\nTOPLEVEL_LANG ?= verilog\nifneq ($(TOPLEVEL_LANG),verilog)\nSKIP := 1\n$(info \"Skipping . . . Verilog only\")\nendif\n\nifeq ($(SKIP),)\n\nVERILOG_SOURCES = $(PWD)/cocotb_package_pkg.sv \\\n                  $(PWD)/cocotb_package.sv\nCOCOTB_TOPLEVEL := cocotb_package\nCOCOTB_TEST_MODULES = test_package\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nelse\n\nall:\n\t@echo \"Skipping test_package\"\n\nclean::\n# nothing to clean, just define target in this branch\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_package/cocotb_package.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\nmodule cocotb_package;\n    // Necessary for Xcelium and Riviera in order for compiled packages to be visible\n    import cocotb_package_pkg_1::*;\n    import cocotb_package_pkg_2::*;\n\n    parameter int seven_int = 7;\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_package/cocotb_package_pkg.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\npackage cocotb_package_pkg_1;\n    parameter int five_int = 5;\n    parameter logic [31:0] eight_logic = 8;\n\n    parameter bit [0:0]     bit_1_param     = 1;\n    parameter bit [1:0]     bit_2_param     = 3;\n    parameter bit [599:0]   bit_600_param   = 600'ha364c9849f8298c66d659;\n    parameter byte          byte_param      = 100;\n    parameter shortint      shortint_param  = 63000;\n    parameter int           int_param       = 50;\n    parameter longint       longint_param   = 64'h11c98c031cb;\n\n    parameter integer       integer_param   = 125000;\n    parameter logic [129:0] logic_130_param = 130'h8c523ec7dc553a2b;\n    parameter reg   [7:0]   reg_8_param     = 200;\n    parameter time          time_param      = 64'h2540be400;\nendpackage\n\npackage cocotb_package_pkg_2;\n    parameter int eleven_int = 11;\nendpackage\n\nparameter int unit_four_int = 4;\n"
  },
  {
    "path": "tests/test_cases/test_package/test_package.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"\nA set of tests that demonstrate package access\n\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.handle import HierarchyObject, LogicArrayObject\n\n\n# Riviera-PRO 2019.10 does not detect packages over GPI:\n#   AttributeError: 'types.SimpleNamespace' object has no attribute\n#   'cocotb_package_pkg_1'\n@cocotb.test(\n    expect_error=(\n        AttributeError\n        if (\n            cocotb.SIM_NAME.lower().startswith(\"riviera\")\n            and cocotb.SIM_VERSION.startswith(\"2019.10\")\n        )\n        else ()\n    )\n)\nasync def test_package_access(_) -> None:\n    \"\"\"Test package parameter access\"\"\"\n\n    pkg1 = cocotb.packages.cocotb_package_pkg_1\n    assert isinstance(pkg1, HierarchyObject)\n    assert pkg1._path.startswith(\"cocotb_package_pkg_1\")\n\n    assert isinstance(pkg1.five_int, LogicArrayObject)\n    assert pkg1.five_int._path == \"cocotb_package_pkg_1::five_int\"\n    assert pkg1.five_int.value == 5\n\n    assert isinstance(pkg1.eight_logic, LogicArrayObject)\n    assert pkg1.eight_logic._path == \"cocotb_package_pkg_1::eight_logic\"\n    assert pkg1.eight_logic.value == 8\n\n    assert isinstance(pkg1.bit_1_param, LogicArrayObject)\n    assert pkg1.bit_1_param._path == \"cocotb_package_pkg_1::bit_1_param\"\n    assert pkg1.bit_1_param.value == 1\n\n    assert isinstance(pkg1.bit_2_param, LogicArrayObject)\n    assert pkg1.bit_2_param._path == \"cocotb_package_pkg_1::bit_2_param\"\n    assert pkg1.bit_2_param.value == 3\n\n    assert isinstance(pkg1.bit_600_param, LogicArrayObject)\n    assert pkg1.bit_600_param._path == \"cocotb_package_pkg_1::bit_600_param\"\n    assert pkg1.bit_600_param.value == 12345678912345678912345689\n\n    assert isinstance(pkg1.byte_param, LogicArrayObject)\n    assert pkg1.byte_param._path == \"cocotb_package_pkg_1::byte_param\"\n    assert pkg1.byte_param.value == 100\n\n    assert isinstance(pkg1.shortint_param, LogicArrayObject)\n    assert pkg1.shortint_param._path == \"cocotb_package_pkg_1::shortint_param\"\n    assert pkg1.shortint_param.value == 63000\n\n    assert isinstance(pkg1.int_param, LogicArrayObject)\n    assert pkg1.int_param._path == \"cocotb_package_pkg_1::int_param\"\n    assert pkg1.int_param.value == 50\n\n    assert isinstance(pkg1.longint_param, LogicArrayObject)\n    assert pkg1.longint_param._path == \"cocotb_package_pkg_1::longint_param\"\n    assert pkg1.longint_param.value == 0x11C98C031CB\n\n    assert isinstance(pkg1.integer_param, LogicArrayObject)\n    assert pkg1.integer_param._path == \"cocotb_package_pkg_1::integer_param\"\n    assert pkg1.integer_param.value == 125000\n\n    assert isinstance(pkg1.logic_130_param, LogicArrayObject)\n    assert pkg1.logic_130_param._path == \"cocotb_package_pkg_1::logic_130_param\"\n    assert pkg1.logic_130_param.value == 0x8C523EC7DC553A2B\n\n    assert isinstance(pkg1.reg_8_param, LogicArrayObject)\n    assert pkg1.reg_8_param._path == \"cocotb_package_pkg_1::reg_8_param\"\n    assert pkg1.reg_8_param.value == 200\n\n    assert isinstance(pkg1.time_param, LogicArrayObject)\n    assert pkg1.time_param._path == \"cocotb_package_pkg_1::time_param\"\n    assert pkg1.time_param.value == 0x2540BE400\n\n    pkg2 = cocotb.packages.cocotb_package_pkg_2\n    assert isinstance(pkg2, HierarchyObject)\n    assert pkg2._path.startswith(\"cocotb_package_pkg_2\")\n\n    assert isinstance(pkg2.eleven_int, LogicArrayObject)\n    assert pkg2.eleven_int._path == \"cocotb_package_pkg_2::eleven_int\"\n    assert pkg2.eleven_int.value == 11\n\n\n@cocotb.test(skip=cocotb.SIM_NAME.lower().startswith(\"riviera\"))\nasync def test_dollar_unit(dut):\n    \"\"\"Test $unit scope\"\"\"\n\n    # Is $unit even a package?  Xcelium says yes and 37.10 detail 5 would also suggest yes\n    pkgs = vars(cocotb.packages).keys()\n    f = filter(lambda x: \"unit\" in x, pkgs)\n    unit = next(iter(f))\n    cocotb.log.info(f\"Found $unit as {unit}\")\n    unit_pkg = getattr(cocotb.packages, unit)\n    assert unit_pkg.unit_four_int.value == 4\n"
  },
  {
    "path": "tests/test_cases/test_packed_union/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nifneq ($(TOPLEVEL_LANG),verilog)\n\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being verilog\"\nclean::\n\nelse\n\nVERILOG_SOURCES = $(PWD)/test_packed_union.sv\nCOCOTB_TOPLEVEL = test_packed_union\nCOCOTB_TEST_MODULES = test_packed_union\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_packed_union/test_packed_union.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport os\n\nimport cocotb\nfrom cocotb_tools.sim_versions import RivieraVersion\n\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\n\n# Riviera-PRO 2022.10-2023.10 (VPI) do not discover dut.t correctly (gh-3587)\n@cocotb.test(\n    expect_error=Exception\n    if cocotb.SIM_NAME.lower().startswith((\"verilator\", \"icarus\", \"ghdl\"))\n    or (\n        cocotb.SIM_NAME.lower().startswith(\"riviera\")\n        and RivieraVersion(cocotb.SIM_VERSION) >= RivieraVersion(\"2022.10\")\n        and RivieraVersion(cocotb.SIM_VERSION) < RivieraVersion(\"2024.04\")\n        and LANGUAGE == \"verilog\"\n    )\n    else (AttributeError)\n)\nasync def test_packed_union(dut):\n    pbs = dut.t\n    pbs.a.value = 0\n"
  },
  {
    "path": "tests/test_cases/test_packed_union/test_packed_union.sv",
    "content": "/**\n * Copyright cocotb contributors\n * Licensed under the Revised BSD License, see LICENSE for details.\n * SPDX-License-Identifier: BSD-3-Clause\n*/\n\nmodule test_packed_union\n    (input union packed {\n           logic [3:0] a;\n           logic [1:0][1:0] b;\n     } t);\nendmodule : test_packed_union\n"
  },
  {
    "path": "tests/test_cases/test_plusargs/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/plusargs_module/Makefile\n\nCOCOTB_PLUSARGS=+foo=bar +test1 +test2 +options=fubar +lol=wow=4\n\nCOCOTB_TEST_MODULES = plusargs\n"
  },
  {
    "path": "tests/test_cases/test_plusargs/plusargs.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2013 Potential Ventures Ltd\n# Copyright (c) 2013 SolarFlare Communications Inc\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\"\"\"\nplusarg testing\n\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def plusargs_test(dut):\n    \"\"\"Demonstrate plusarg access from Python test\"\"\"\n\n    for name in cocotb.plusargs:\n        print(\"COCOTB:\", name, cocotb.plusargs[name])\n\n    assert \"test1\" in cocotb.plusargs\n    assert cocotb.plusargs[\"foo\"] == \"bar\"\n    assert cocotb.plusargs[\"lol\"] == \"wow=4\"\n"
  },
  {
    "path": "tests/test_cases/test_random_test_order/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCOCOTB_TEST_MODULES = test_random_test_order\n\n# This particular seed value provides a nice spread of how random the test order can be.\n#\n# Specifically, it demonstrates that:\n#\t- Tests within a stage are shuffled.\n#\t- The ordering of stages is upheld.\n# \t- Parametrized tests are shuffled among the stage.\nexport COCOTB_RANDOM_SEED := 1233\n\n# Set COCOTB_RANDOM_TEST_ORDER to randomize tests within stages.\nexport COCOTB_RANDOM_TEST_ORDER := 1\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_random_test_order/test_random_test_order.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n# Track which test gets ran during the simulation.\ncount = 0\n\n\n# Try this a parametrized version of a test.\n@cocotb.test(stage=0)\n@cocotb.parametrize(index=[0, 1, 2])\nasync def test_a0(dut: object, index: int) -> None:\n    \"\"\"Run a test.\"\"\"\n    global count\n    count += 1\n    if index == 0:\n        assert count == 3\n    elif index == 1:\n        assert count == 2\n    elif index == 2:\n        assert count == 5\n\n\n@cocotb.test(stage=0)\nasync def test_b0(dut: object) -> None:\n    \"\"\"Run a test.\"\"\"\n    global count\n    count += 1\n    assert count == 1\n\n\n@cocotb.test(stage=0)\nasync def test_c0(dut: object) -> None:\n    \"\"\"Run a test.\"\"\"\n    global count\n    count += 1\n    assert count == 4\n\n\n# Try with a test in a different stage.\n@cocotb.test(stage=1)\nasync def test_a1(dut: object) -> None:\n    \"\"\"Run a test.\"\"\"\n    global count\n    count += 1\n    # Verify this test is always last.\n    assert count == 6\n"
  },
  {
    "path": "tests/test_cases/test_seed/.gitignore",
    "content": "number\n"
  },
  {
    "path": "tests/test_cases/test_seed/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nrun:\n\t$(RM) number\n\t$(MAKE) sim COCOTB_TEST_MODULES=test_other,test_seed COCOTB_RANDOM_SEED=1234\n\t$(MAKE) sim COCOTB_TEST_MODULES=test_seed COCOTB_TEST_FILTER=test_reproducibility COCOTB_RANDOM_SEED=1234\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_seed/test_other.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_pass(_):\n    # exists solely so there is another test in another module\n    # before the other module is run\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_seed/test_seed.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport random\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_first(dut):\n    # move generator to test that it doesn't affect the next test\n    for _ in range(100):\n        random.getrandbits(64)\n\n\n@cocotb.test()\nasync def test_reproducibility(_):\n    try:\n        with open(\"number\") as file:\n            a = int(file.read())\n        assert a == random.getrandbits(32)\n    except FileNotFoundError:\n        with open(\"number\", \"w\") as file:\n            number = random.getrandbits(32)\n            file.write(str(number))\n"
  },
  {
    "path": "tests/test_cases/test_select_testcase/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# select only y_tests from all MODULEs\n\nCOCOTB_TEST_MODULES := x_tests,y_tests,y_tests_again\nCOCOTB_TESTCASE := y_test\n\n# override PYTHONWARNINGS to prevent DeprecationWarning causing an error with use of COCOTB_TESTCASE\nifdef PYTHONWARNINGS\noverride PYTHONWARNINGS := $(PYTHONWARNINGS),ignore::DeprecationWarning:cocotb.regression\nendif\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_select_testcase/x_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def x_test(dut):\n    assert False\n"
  },
  {
    "path": "tests/test_cases/test_select_testcase/y_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def y_test(dut):\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_select_testcase/y_tests_again.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def y_test(dut):\n    pass\n\n\n@cocotb.test()\nasync def y_test_with_additional(_):\n    assert False, \"COCOTB_TESTCASE shouldn't match this test\"\n"
  },
  {
    "path": "tests/test_cases/test_select_testcase_error/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# This module exists, but...\nCOCOTB_TEST_MODULES := x_tests\n# ...this test does not exist\nTESTCASE := y_test\n\n# TESTCASE filtering out all tests results in a warning\n\n# override PYTHONWARNINGS to prevent DeprecationWarning causing an error with use of COCOTB_TESTCASE\nifdef PYTHONWARNINGS\noverride PYTHONWARNINGS := $(PYTHONWARNINGS),ignore::DeprecationWarning:cocotb.regression\nendif\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_select_testcase_error/x_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def x_test(dut):\n    cocotb.log.info(\"x_test\")\n"
  },
  {
    "path": "tests/test_cases/test_similar_scope_name/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nPROJ_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n\nTOPLEVEL_LANG ?= verilog\n\nifeq ($(TOPLEVEL_LANG),verilog)\nVERILOG_SOURCES := $(PROJ_DIR)/test.sv\nelse ifeq ($(TOPLEVEL_LANG),vhdl)\nVHDL_SOURCES := $(PROJ_DIR)/test.vhd\nendif\n\nCOCOTB_TOPLEVEL := test\n\nifneq ($(filter $(SIM),ius xcelium),)\nCOMPILE_ARGS += -v93\nendif\n\nexport COCOTB_TEST_MODULES := test_similar_scope_name\nexport COCOTB_LOG_LEVEL := DEBUG\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n"
  },
  {
    "path": "tests/test_cases/test_similar_scope_name/test.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`timescale 1us/1us\n\nmodule test (output [15:0] o);\n\n  genvar idx1;\n  generate for (idx1 = 0; idx1 < 10; idx1 = idx1 + 1)\n    begin: foobar\n      assign o[idx1] = 1;\n    end\n  endgenerate\n\n  genvar idx2;\n  generate for (idx2 = 10; idx2 < 16; idx2 = idx2 + 1)\n    begin: foo   // Should not be confused with \"foobar\" which shares the same prefix\n      assign o[idx2] = 1;\n    end\n  endgenerate\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_similar_scope_name/test.vhd",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nentity test is\n    port ( o : out bit_vector(15 downto 0) );\nend entity test;\n\narchitecture rtl of test is\nbegin\n\n    foobar: for i in 0 to 9 generate\n    begin\n        o(i) <= '1';\n    end generate;\n\n    -- Should not be confused with \"foobar\" which shares the same prefix\n    foo: for i in 10 to 15 generate\n    begin\n        o(i) <= '1';\n    end generate;\n\nend architecture rtl;\n"
  },
  {
    "path": "tests/test_cases/test_similar_scope_name/test_similar_scope_name.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\"\"\"Test for issue #2255: a scope whose name starts another scope is returned instead.\"\"\"\n\nfrom __future__ import annotations\n\nimport cocotb\n\n\n# GHDL is unable to access signals in generate loops (gh-2594)\n# Verilator doesn't support vpiGenScope or vpiGenScopeArray (gh-1884)\n# VCS is unable to access signals in generate loops\n@cocotb.test(\n    expect_error=AssertionError\n    if cocotb.SIM_NAME.lower().startswith(\"ghdl\")\n    else AttributeError\n    if cocotb.SIM_NAME.lower().startswith(\"verilator\")\n    else AttributeError\n    if \"vcs\" in cocotb.SIM_NAME.lower()\n    else ()\n)\nasync def test_distinct_generates(dut):\n    assert len(dut.foobar) == 10\n    assert len(dut.foo) == 6\n"
  },
  {
    "path": "tests/test_cases/test_skip/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCOCOTB_TEST_MODULES := test_skip\n\n# Ensure we had the correct number of skips\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t$(MAKE) all\n\ttest $$(grep '<skipped />' $(COCOTB_RESULTS_FILE) | wc -l) -eq 4\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_skip/test_skip.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport pytest\n\nimport cocotb\nfrom cocotb.triggers import Timer\n\n\n@cocotb.test\nasync def test_skip(_: object) -> None:\n    pytest.skip(\"This test is skipped\")\n    assert False  # This should not be reached\n\n\n@cocotb.test\nasync def test_skip_in_task(_: object) -> None:\n    async def skipit() -> None:\n        pytest.skip(\"This test is skipped\")\n        assert False  # This should not be reached\n\n    task = cocotb.start_soon(skipit())\n    await Timer(1)\n    await task\n    assert False  # This should not be reached\n\n\n@cocotb.test\n@cocotb.skipif(True, reason=\"This test is skipped\")\nasync def test_skipif_deco(_: object) -> None:\n    assert False  # This test should not be run\n\n\n@cocotb.test(skip=True)\nasync def test_skip_arg(_: object) -> None:\n    assert False  # This test should not be run\n"
  },
  {
    "path": "tests/test_cases/test_skipped_explicitly_run/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/sample_module/Makefile\n\nSKIPPED_TEST_FILE = ran_skipped_test~\n\nclean::\n\t$(RM) -r ${SKIPPED_TEST_FILE}\n\n# Override the default target. We need to run clean (to remove the cached test file)\n# and then test to make sure it is recreated.\n.DEFAULT_GOAL := override\n.PHONY: override\noverride: clean all\n\t@test -f $(SKIPPED_TEST_FILE) || (echo \"ERROR: skip=True test was not ran!\" >&2 && exit 1)\n\n# Set COCOTB_TEST_FILTER; run test_skipped even though skip=True is set.\nCOCOTB_TEST_FILTER = test_skipped\n\nCOCOTB_TEST_MODULES = test_skipped_explicitly_run\n"
  },
  {
    "path": "tests/test_cases/test_skipped_explicitly_run/test_skipped_explicitly_run.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport pathlib\n\nimport cocotb\n\nskipped_file_name = \"ran_skipped_test~\"\n\n\n@cocotb.test(skip=True)\nasync def test_skipped(dut: object) -> None:\n    \"\"\"Touch a file so we can check that this test has run.\"\"\"\n    pathlib.Path(skipped_file_name).touch()\n"
  },
  {
    "path": "tests/test_cases/test_struct/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n\nTOPLEVEL_LANG ?= verilog\n\nifneq ($(TOPLEVEL_LANG),verilog)\n\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being verilog\"\nclean::\n\nelse\n\ninclude ../../designs/sample_module/Makefile\nCOCOTB_TEST_MODULES:=test_struct\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_struct/test_struct.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport logging\nimport os\nimport re\n\nimport cocotb\nfrom cocotb.triggers import Timer\nfrom cocotb_tools.sim_versions import RivieraVersion\n\nSIM_NAME = cocotb.SIM_NAME.lower()\nLANGUAGE = os.environ[\"TOPLEVEL_LANG\"].lower().strip()\n\n\n@cocotb.test(\n    expect_error=(\n        AttributeError if SIM_NAME.startswith((\"icarus\", \"ghdl\", \"nvc\")) else ()\n    ),\n)\nasync def test_packed_struct_format(dut):\n    \"\"\"Test that the correct objects are returned for a struct\"\"\"\n    assert repr(dut.my_struct) in (\n        \"LogicArrayObject(sample_module.my_struct)\",\n        \"PackedObject(sample_module.my_struct)\",\n    )\n\n    # Riviera-PRO initializes the struct with X, Verilator with 0, and others\n    # with Z. Since we don't want to explicitly set dut.my_struct (write tests\n    # are below) we accept any initialization the simulator might choose.\n    assert re.fullmatch(\n        r\"LogicArray\\('[0XZ]{3}', Range\\(2, 'downto', 0\\)\\)\", repr(dut.my_struct.value)\n    )\n\n\n# Riviera-PRO 2024.04 crashes on this testcase (gh-3936)\nsim_ver = RivieraVersion(cocotb.SIM_VERSION)\nis_riviera_2024_04 = (\n    sim_ver >= \"2024.04\" and sim_ver < \"2024.05\"\n    if SIM_NAME.startswith(\"riviera\")\n    else None\n)\n\n\n# Riviera-PRO 2022.10 - 2023.10 ignores writes to the packed struct.\n# Riviera-PRO 2024.04 crashes.\n@cocotb.test(\n    expect_error=(\n        AttributeError if SIM_NAME.startswith((\"icarus\", \"ghdl\", \"nvc\")) else ()\n    ),\n    expect_fail=(\n        SIM_NAME.startswith(\"riviera\")\n        and RivieraVersion(cocotb.SIM_VERSION) >= \"2022.10\"\n        and RivieraVersion(cocotb.SIM_VERSION) < \"2024.10\"\n    ),\n    skip=(SIM_NAME.startswith(\"riviera\") and is_riviera_2024_04),\n)\nasync def test_packed_struct_setting(dut):\n    \"\"\"Test setting the value of an entire struct\"\"\"\n\n    # test struct write -> individual signals\n    dut.my_struct.value = 0\n    await Timer(1000, \"ns\")\n\n    assert str(dut.my_struct.value) == \"000\"\n\n\n# GHDL unable to access record signals (gh-2591)\n# Icarus doesn't support structs (gh-2592)\n# Verilator doesn't support structs (gh-1275)\n# Riviera-PRO does not discover inout_if correctly over VPI (gh-3587, gh-3933)\n@cocotb.test(\n    expect_error=(\n        AttributeError\n        if SIM_NAME.startswith((\"icarus\", \"ghdl\", \"verilator\"))\n        or (SIM_NAME.startswith(\"riviera\") and LANGUAGE == \"verilog\")\n        else ()\n    )\n)\nasync def test_struct_format(dut):\n    \"\"\"\n    Access a structure\n    \"\"\"\n\n    tlog = logging.getLogger(\"cocotb.test\")\n\n    structure = dut.inout_if\n\n    tlog.info(\n        f\"Value of inout_if => a_in = {structure.a_in.value} ; b_out = {structure.b_out.value}\"\n    )\n"
  },
  {
    "path": "tests/test_cases/test_sv_interface/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\nVERILOG_SOURCES = $(shell pwd)/top.sv\nCOCOTB_TEST_MODULES = test_sv_if\nCOCOTB_TOPLEVEL = top\n\n# Simulator behavior:\n# Icarus Verilog sees SV interfaces as vpiModule but doesn't discover signals inside them\n# Verilator sees SV interfaces as vpiModule and discovers signals inside them\n# Commercial simulators all see SV interfaces as vpiInterface and discover signals inside them\n\n\nifneq ($(TOPLEVEL_LANG),verilog)\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being verilog\"\nclean::\nelse\nifeq ($(filter questa xcelium ius vcs riviera activehdl verilator,$(shell echo $(SIM) | tr A-Z a-z)),)\nall::\n\t@echo \"Skipping simulator $(SIM) because it might not support SV interfaces\"\nclean::\nelse\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\nendif\nendif\n"
  },
  {
    "path": "tests/test_cases/test_sv_interface/test_sv_if.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.handle import ArrayObject, HierarchyArrayObject\nfrom cocotb_tools.sim_versions import VerilatorVersion\n\n\n@cocotb.test()\nasync def test_sv_if(dut):\n    \"\"\"Test that signals in an interface are discovered\"\"\"\n\n    dut.sv_if_i._discover_all()\n    assert hasattr(dut.sv_if_i, \"a\")\n    assert hasattr(dut.sv_if_i, \"b\")\n    assert hasattr(dut.sv_if_i, \"c\")\n\n\nSIM_NAME = cocotb.SIM_NAME.lower()\nverilator_less_than_5024 = SIM_NAME.startswith(\"verilator\") and VerilatorVersion(\n    cocotb.SIM_VERSION\n) < VerilatorVersion(\"5.024\")\n\n\n# Verilator before 5.024 doesn't support interface arrays (gh-3824)\n@cocotb.test(\n    expect_error=AttributeError\n    if verilator_less_than_5024\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else ()\n)\nasync def test_sv_intf_arr_type(dut):\n    \"\"\"Test that interface arrays are the correct type\"\"\"\n\n    print(dut.sv_if_arr)\n\n    if cocotb.SIM_NAME.lower().startswith((\"xmsim\", \"modelsim\", \"riviera\")):\n        assert isinstance(dut.sv_if_arr, ArrayObject)\n    else:\n        # This is correct\n        assert isinstance(dut.sv_if_arr, HierarchyArrayObject)\n\n\n# Verilator before 5.024 doesn't support interface arrays (gh-3824)\n@cocotb.test(\n    expect_fail=cocotb.SIM_NAME.lower().startswith(\"riviera\"),\n    expect_error=AttributeError\n    if verilator_less_than_5024\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else (),\n)\nasync def test_sv_intf_arr_len(dut):\n    \"\"\"Test that interface array length is correct\"\"\"\n    assert len(dut.sv_if_arr) == 3\n\n\n# Verilator before 5.024 doesn't support interface arrays (gh-3824)\n@cocotb.test(\n    expect_error=IndexError\n    if cocotb.SIM_NAME.lower().startswith(\"riviera\")\n    else AttributeError\n    if verilator_less_than_5024\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else ()\n)\nasync def test_sv_intf_arr_access(dut):\n    \"\"\"Test that interface array objects can be accessed\"\"\"\n    for i in range(3):\n        assert hasattr(dut.sv_if_arr[i], \"a\")\n        assert hasattr(dut.sv_if_arr[i], \"b\")\n        assert hasattr(dut.sv_if_arr[i], \"c\")\n\n\n# Verilator before 5.024 doesn't support interface arrays (gh-3824)\n@cocotb.test(\n    expect_fail=cocotb.SIM_NAME.lower().startswith(\"riviera\"),\n    expect_error=AttributeError\n    if verilator_less_than_5024\n    else AttributeError\n    if \"vcs\" in SIM_NAME\n    else (),\n)\nasync def test_sv_intf_arr_iteration(dut):\n    \"\"\"Test that interface arrays can be iterated\"\"\"\n    count = 0\n    for intf in dut.sv_if_arr:\n        assert hasattr(intf, \"a\")\n        assert hasattr(intf, \"b\")\n        assert hasattr(intf, \"c\")\n        count += 1\n\n    assert count == 3\n"
  },
  {
    "path": "tests/test_cases/test_sv_interface/top.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n\n`timescale 1us/1us\n\ninterface sv_if();\n  logic a;\n  reg b;\n  wire c;\nendinterface\n\nmodule top ();\n\nsv_if sv_if_i();\n\nsv_if sv_if_arr[3]();\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_test_filter/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n# select only y_tests from all MODULEs\n\ninclude ../../designs/sample_module/Makefile\n\nCOCOTB_TEST_MODULES := x_tests\nexport COCOTB_TEST_FILTER := y_test\n"
  },
  {
    "path": "tests/test_cases/test_test_filter/x_tests.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test\nasync def x_test(_):\n    assert False, \"Should not match this test\"\n\n\ny_test_with_suffix_ran = False\n\n\n@cocotb.test\nasync def y_test_with_suffix(_):\n    global y_test_with_suffix_ran\n    y_test_with_suffix_ran = True\n\n\n@cocotb.test\nasync def y_test(_):\n    assert y_test_with_suffix_ran\n"
  },
  {
    "path": "tests/test_cases/test_toplevel_architecture_same_as_entity/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= vhdl\nCOCOTB_TOPLEVEL := test\nVHDL_SOURCES := test.vhdl\nCOCOTB_TEST_MODULES := test_toplevel_architecture_same_as_entity\n\nifneq ($(filter $(SIM),ius xcelium),)\nCOMPILE_ARGS += -v93\nendif\n\nifneq ($(shell echo $(TOPLEVEL_LANG) | tr A-Z a-z),vhdl)\nall:\n\t@echo \"Skipping test since only VHDL is supported\"\nclean::\nelse\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\nendif\n"
  },
  {
    "path": "tests/test_cases/test_toplevel_architecture_same_as_entity/test.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nentity test is\n    port ( x : in boolean );\nend entity test;\n\narchitecture test of test is\nbegin\n    -- This architecture has the same name as the entity, which is\n    -- what this testcase is testing.\nend architecture test;\n"
  },
  {
    "path": "tests/test_cases/test_toplevel_architecture_same_as_entity/test_toplevel_architecture_same_as_entity.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_architecture_name(dut):\n    # This test does not need to do anything to hit this issue.\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_toplevel_library/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifeq ($(SIM)_$(TOPLEVEL_LANG),questa_vhdl)\n\nPROJ_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n\nVHDL_SOURCES := $(PROJ_DIR)/mylib.vhd\nCOCOTB_TOPLEVEL := myentity\nTOPLEVEL_LIBRARY := mylib\n\nCOCOTB_TEST_MODULES := test_myentity\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nelse\n\nall:\n\t@echo \"Skipping test because TOPLEVEL_LIBRARY is only supported in Questa in VHDL regressions.\"\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_toplevel_library/mylib.vhd",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nlibrary ieee;\n    use ieee.std_logic_1164.all;\n\nentity myentity is\n    port (\n        clk     : in    std_logic;\n        a_data  : in    std_logic_vector(31 downto 0);\n        b_data  :   out std_logic_vector(31 downto 0));\nend entity myentity;\n\narchitecture rtl of myentity is\nbegin\n\n    process (clk) is\n    begin\n        if (rising_edge(clk)) then\n            b_data <= a_data;\n        end if;\n    end process;\n\nend architecture rtl;\n"
  },
  {
    "path": "tests/test_cases/test_toplevel_library/test_myentity.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test_myentity(dut):\n    # if we got here, the test worked\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_verilator_timing_a/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nCOCOTB_TEST_MODULES := test_verilator_timing_a\n\ninclude ../../designs/verilator_timing/Makefile\n\nifneq ($(shell echo $(TOPLEVEL_LANG) | tr A-Z a-z),verilog)\nall:\n\t@echo \"Skipping test since only Verilog is supported\"\nelse ifeq ($(filter verilator,$(shell echo $(SIM) | tr A-Z a-z)),)\nall:\n\t@echo \"Skipping test since only Verilator is supported\"\nelse\n\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t# We cannot normally rely on the simulator return code, but this test is specific to Verilator\n\tif $(MAKE) all; then echo \"Expected test to fail without --timing flag\"; false; else echo \"Failed as expected\"; fi\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\nendif\n"
  },
  {
    "path": "tests/test_cases/test_verilator_timing_a/test_verilator_timing_a.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport random\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import RisingEdge\n\n\n@cocotb.test()\nasync def clk_in_coroutine(dut):\n    dut.d.value = 0\n    clock = Clock(dut.clk, 10, unit=\"us\")\n    cocotb.start_soon(clock.start(start_high=False))\n    await RisingEdge(dut.clk)\n    for _ in range(3):\n        val = random.randint(0, 1)\n        dut.d.value = val\n        await RisingEdge(dut.clk)\n\n\n@cocotb.test()\nasync def clk_in_hdl(dut):\n    dut.d.value = 0\n    await RisingEdge(dut.clk)\n    for _ in range(3):\n        val = random.randint(0, 1)\n        dut.d.value = val\n        await RisingEdge(dut.clk)\n"
  },
  {
    "path": "tests/test_cases/test_verilator_timing_b/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nCOCOTB_TEST_MODULES := test_verilator_timing_b\nEXTRA_ARGS := \"+define+TEST_CLK_EXTERNAL=1\"\n\ninclude ../../designs/verilator_timing/Makefile\n\nifneq ($(shell echo $(TOPLEVEL_LANG) | tr A-Z a-z),verilog)\nall:\n\t@echo \"Skipping test since only Verilog is supported\"\nelse ifeq ($(filter verilator,$(shell echo $(SIM) | tr A-Z a-z)),)\nall:\n\t@echo \"Skipping test since only Verilator is supported\"\nelse\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\nendif\n"
  },
  {
    "path": "tests/test_cases/test_verilator_timing_b/test_verilator_timing_b.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport random\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.regression import SimFailure\nfrom cocotb.triggers import RisingEdge\n\n\n@cocotb.test()\nasync def clk_in_coroutine(dut):\n    dut.d.value = 0\n    clock = Clock(dut.clk, 10, unit=\"us\")\n    cocotb.start_soon(clock.start(start_high=False))\n    await RisingEdge(dut.clk)\n    for _ in range(3):\n        val = random.randint(0, 1)\n        dut.d.value = val\n        await RisingEdge(dut.clk)\n\n\n@cocotb.test(expect_error=SimFailure)\nasync def clk_in_hdl(dut):\n    dut.d.value = 0\n    await RisingEdge(dut.clk)\n    for _ in range(3):\n        val = random.randint(0, 1)\n        dut.d.value = val\n        await RisingEdge(dut.clk)\n"
  },
  {
    "path": "tests/test_cases/test_verilator_timing_c/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCOCOTB_TEST_MODULES := test_verilator_timing_c\nEXTRA_ARGS := \"--timing\"\n\ninclude ../../designs/verilator_timing/Makefile\n\nifneq ($(shell ./check_version 2>/dev/null 1>&2; echo $$?),0)\nall:\n\t@echo \"Skipping test since it requires newer version of cocotb\"\nelse ifneq ($(shell echo $(TOPLEVEL_LANG) | tr A-Z a-z),verilog)\nall:\n\t@echo \"Skipping test since only Verilog is supported\"\nelse ifeq ($(filter verilator,$(shell echo $(SIM) | tr A-Z a-z)),)\nall:\n\t@echo \"Skipping test since only Verilator is supported\"\nelse\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\nendif\n"
  },
  {
    "path": "tests/test_cases/test_verilator_timing_c/check_version",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\n#!/bin/bash\n\nVERSION=`cocotb-config --version`\nMIN_VERSION=\"1.8.0\"\necho \"----------------------------------------\"\necho \"cocotb-config       : $VERSION\"\necho \"Minimum requirement : $MIN_VERSION\"\necho \"----------------------------------------\"\n\n# If set {MIN_VERSION, VERSION} is sorted in ascending order, then returns 0\nprintf '%s\\n' \"$MIN_VERSION\" \"$VERSION\" | sort --version-sort --check=silent\nRES=$?\nif [ $RES -eq 0 ]; then\n    echo \"Minimum requirement is met\"\n    echo \"----------------------------------------\"\n    exit 0\nelse\n    echo \"Minimum requirement not met\"\n    echo \"----------------------------------------\"\n    exit 1\nfi\n"
  },
  {
    "path": "tests/test_cases/test_verilator_timing_c/test_verilator_timing_c.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport random\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.triggers import RisingEdge\n\n\n@cocotb.test()\nasync def clk_in_coroutine(dut):\n    dut.d.value = 0\n    clock = Clock(dut.clk, 10, unit=\"us\")\n    cocotb.start_soon(clock.start(start_high=False))\n    await RisingEdge(dut.clk)\n    for _ in range(3):\n        val = random.randint(0, 1)\n        dut.d.value = val\n        await RisingEdge(dut.clk)\n\n\n@cocotb.test()\nasync def clk_in_hdl(dut):\n    dut.d.value = 0\n    await RisingEdge(dut.clk)\n    for _ in range(3):\n        val = random.randint(0, 1)\n        dut.d.value = val\n        await RisingEdge(dut.clk)\n"
  },
  {
    "path": "tests/test_cases/test_verilator_timing_d/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nCOCOTB_TEST_MODULES := test_verilator_timing_d\nEXTRA_ARGS=\"+define+TEST_CLK_EXTERNAL=1 --timing\"\n\ninclude ../../designs/verilator_timing/Makefile\n\nifneq ($(shell echo $(TOPLEVEL_LANG) | tr A-Z a-z),verilog)\nall:\n\t@echo \"Skipping test since only Verilog is supported\"\nelse ifeq ($(filter verilator,$(shell echo $(SIM) | tr A-Z a-z)),)\nall:\n\t@echo \"Skipping test since only Verilator is supported\"\nelse\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\nendif\n"
  },
  {
    "path": "tests/test_cases/test_verilator_timing_d/test_verilator_timing_d.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport random\n\nimport cocotb\nfrom cocotb.clock import Clock\nfrom cocotb.regression import SimFailure\nfrom cocotb.triggers import RisingEdge\n\n\n@cocotb.test()\nasync def clk_in_coroutine(dut):\n    dut.d.value = 0\n    clock = Clock(dut.clk, 10, unit=\"us\")\n    cocotb.start_soon(clock.start(start_high=False))\n    await RisingEdge(dut.clk)\n    for _ in range(3):\n        val = random.randint(0, 1)\n        dut.d.value = val\n        await RisingEdge(dut.clk)\n\n\n@cocotb.test(expect_error=SimFailure)\nasync def clk_in_hdl(dut):\n    dut.d.value = 0\n    await RisingEdge(dut.clk)\n    for _ in range(3):\n        val = random.randint(0, 1)\n        dut.d.value = val\n        await RisingEdge(dut.clk)\n"
  },
  {
    "path": "tests/test_cases/test_verilog_access/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/uart2bus/Makefile\nCOCOTB_TEST_MODULES = test_verilog_access\n"
  },
  {
    "path": "tests/test_cases/test_verilog_access/test_verilog_access.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.handle import HierarchyObject, LogicArrayObject, LogicObject\n\n\n@cocotb.test()\nasync def port_not_hierarchy(dut):\n    \"\"\"\n    Test for issue raised by Luke - iteration causes a toplevel port type to\n    change from LogicObject to HierarchyObject\n    \"\"\"\n\n    assert isinstance(dut.clk, LogicObject)\n    assert isinstance(dut.i_verilog, HierarchyObject)\n    assert isinstance(dut.i_verilog.clock, LogicObject)\n    assert isinstance(dut.i_verilog.tx_data, LogicArrayObject)\n\n    for _ in dut:\n        pass\n\n    for _ in dut.i_verilog:\n        pass\n\n    assert isinstance(dut.clk, LogicObject)\n    assert isinstance(dut.i_verilog, HierarchyObject)\n    assert isinstance(dut.i_verilog.clock, LogicObject)\n    assert isinstance(dut.i_verilog.tx_data, LogicArrayObject)\n"
  },
  {
    "path": "tests/test_cases/test_verilog_include_dirs/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nTOPLEVEL_LANG ?= verilog\n\nifneq ($(TOPLEVEL_LANG),verilog)\n\nall:\n\t@echo \"Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being verilog\"\nclean::\n\nelse\n\nVERILOG_INCLUDE_DIRS = \\\n\t$(PWD)/common \\\n\t$(PWD)/const_stream\nVERILOG_SOURCES = $(PWD)/simple_and.sv\nCOCOTB_TOPLEVEL = simple_and\nCOCOTB_TEST_MODULES = test_verilog_include_dirs\n\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_verilog_include_dirs/common/a.vh",
    "content": "`define DATA_BYTES 8\n"
  },
  {
    "path": "tests/test_cases/test_verilog_include_dirs/common/b.vh",
    "content": "`define DATA_WIDTH 5\n"
  },
  {
    "path": "tests/test_cases/test_verilog_include_dirs/const_stream/c.vh",
    "content": "`define DATA_LAST 3\n"
  },
  {
    "path": "tests/test_cases/test_verilog_include_dirs/simple_and.sv",
    "content": "// Copyright cocotb contributors\n// Licensed under the Revised BSD License, see LICENSE for details.\n// SPDX-License-Identifier: BSD-3-Clause\n`include \"a.vh\"\n`include \"b.vh\"\n`include \"c.vh\"\n\nmodule simple_and (\n    input [`DATA_BYTES-1:0]               a,\n    input [`DATA_WIDTH+2:0]               b,\n    output [`DATA_LAST+4:0]               c\n);\n\nassign c = a & b;\n\nendmodule\n"
  },
  {
    "path": "tests/test_cases/test_verilog_include_dirs/test_verilog_include_dirs.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n# The purpose of this test is just to complete an elaboration cycle up to time 0, before simulation\n# If it fails to get to this point then the addition of the include dirs failed!\n@cocotb.test()\nasync def test_noop(_):\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_access/Makefile",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\ninclude ../../designs/viterbi_decoder_axi4s/Makefile\nCOCOTB_TEST_MODULES = test_vhdl_access\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_access/test_vhdl_access.py",
    "content": "# Copyright cocotb contributors\n# Copyright (c) 2015 Potential Ventures Ltd\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport logging\n\nimport pytest\n\nimport cocotb\nfrom cocotb.handle import (\n    EnumObject,\n    HierarchyObject,\n    IntegerObject,\n    LogicArrayObject,\n    LogicObject,\n)\n\n\n# GHDL discovers enum as `vpiNet` (gh-2600)\n@cocotb.test(expect_fail=cocotb.SIM_NAME.lower().startswith(\"ghdl\"))\nasync def check_enum_object(dut):\n    \"\"\"\n    Enumerations currently behave as normal signals\n\n    TODO: Implement an EnumObject class and detect valid string mappings\n    \"\"\"\n    assert isinstance(dut.inst_ram_ctrl.write_ram_fsm, EnumObject)\n\n\n# GHDL unable to access signals in generate loops (gh-2594)\n@cocotb.test(\n    expect_error=IndexError if cocotb.SIM_NAME.lower().startswith(\"ghdl\") else ()\n)\nasync def check_objects(dut):\n    \"\"\"\n    Check the types of objects that are returned\n    \"\"\"\n    tlog = logging.getLogger(\"cocotb.test\")\n\n    def check_instance(obj, objtype):\n        assert isinstance(obj, objtype), (\n            f\"Expected {obj._path} to be of type {objtype.__name__} but got {type(obj).__name__}\"\n        )\n        tlog.info(f\"{obj._path} is {type(obj).__name__}\")\n\n    # Hierarchy checks\n    check_instance(dut.inst_axi4s_buffer, HierarchyObject)\n    check_instance(dut.gen_branch_distance[0], HierarchyObject)\n    check_instance(dut.gen_branch_distance[0].inst_branch_distance, HierarchyObject)\n    check_instance(dut.gen_acs[0].inbranch_tdata_low, LogicArrayObject)\n    check_instance(dut.aclk, LogicObject)\n    check_instance(dut.s_axis_input_tdata, LogicArrayObject)\n    check_instance(dut.current_active, IntegerObject)\n    check_instance(dut.inst_axi4s_buffer.DATA_WIDTH, IntegerObject)\n    check_instance(dut.inst_ram_ctrl, HierarchyObject)\n\n    assert dut.inst_axi4s_buffer.DATA_WIDTH.value == 32, (\n        f\"Expected dut.inst_axi4s_buffer.DATA_WIDTH to be 32 but got {dut.inst_axi4s_buffer.DATA_WIDTH.value}\"\n    )\n\n    with pytest.raises(TypeError):\n        dut.inst_axi4s_buffer.DATA_WIDTH.value = 42\n\n\n@cocotb.test()\nasync def port_not_hierarchy(dut):\n    \"\"\"\n    Test for issue raised by Luke - iteration causes a toplevel port type to\n    change from LogicObject to HierarchyObject\n    \"\"\"\n    assert isinstance(dut.aclk, LogicObject), (\n        f\"dut.aclk should be LogicObject but got {type(dut.aclk).__name__}\"\n    )\n\n    for _ in dut:\n        pass\n\n    assert isinstance(dut.aclk, LogicObject), (\n        f\"dut.aclk should be LogicObject but got {type(dut.aclk).__name__}\"\n    )\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_integer/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nifeq ($(TOPLEVEL_LANG),vhdl)\n\nifneq ($(filter $(SIM),ius xcelium),)\n    COMPILE_ARGS += -v93\nendif\n\nCOCOTB_TOPLEVEL := vhdl_integer\nCOCOTB_TEST_MODULES := test_vhdl_integer\nVHDL_SOURCES := vhdl_integer.vhdl\n\n# cocotb inclusions\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\n\nelse\nall:\n\t$(info Skipping simulation as only TOPLEVEL_LANG=vhdl is supported)\n\nclean::\n\nendif\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_integer/test_vhdl_integer.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\nfrom cocotb.triggers import gather\nfrom cocotb_tools.sim_versions import NvcVersion\n\nSIM_NAME = cocotb.SIM_NAME.lower()\n\n\nasync def wait_value_change(signal, expected_value) -> None:\n    await signal.value_change\n    current_value = signal.value\n    assert current_value == expected_value, (\n        f\"Signal {signal} current value {current_value} didn't match expected value {expected_value}\"\n    )\n\n\n@cocotb.test(timeout_time=15, timeout_unit=\"ns\")\nasync def vhdl_integer_valuechange(dut) -> None:\n    dut.i_int.value = 0\n\n    await gather(\n        wait_value_change(dut.o_int, 0),\n        wait_value_change(dut.s_int, 1),\n    )\n\n\n@cocotb.xfail(\n    SIM_NAME.startswith(\"ghdl\"),\n    raises=AttributeError,\n    reason=\"GHDL is unable to access record signals (gh-2591)\",\n)\n@cocotb.xfail(\n    SIM_NAME.startswith(\"nvc\") and NvcVersion(cocotb.SIM_VERSION) < NvcVersion(\"1.15\"),\n    raises=RuntimeError,\n    reason=\"NVC versions prior to 1.15 have issues setting up value change triggers on fields of records (gh-5130)\",\n)\n@cocotb.test(timeout_time=15, timeout_unit=\"ns\")\nasync def vhdl_record_integer_valuechange(dut) -> None:\n    a_val = dut.s_ints.a.value\n    b_val = dut.s_ints.b.value\n\n    await gather(\n        wait_value_change(dut.s_ints.a, a_val + 1),\n        wait_value_change(dut.s_ints.b, b_val + 1),\n    )\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_integer/vhdl_integer.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\n\nlibrary ieee;\nuse ieee.std_logic_1164.all;\n\nentity vhdl_integer is\n  port(\n    i_int : in  integer;\n    o_int : out integer\n  );\nend entity vhdl_integer;\n\narchitecture RTL of vhdl_integer is\n  signal s_int : integer := 0;\n\n  type ints is record\n    a : integer;\n    b : integer;\n  end record ints;\n\n  signal s_ints : ints := (1, 2);\nbegin\n\n  process\n  begin\n    wait for 10 ns;\n    s_int <= s_int + 1;\n    s_ints.a <= s_ints.a + 1;\n    s_ints.b <= s_ints.b + 1;\n\n  end process;\n\n  o_int <= transport i_int after 10 ns;\n\nend architecture RTL;\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nSIM ?= ghdl\nTOPLEVEL_LANG ?= vhdl\nVHDL_SOURCES_blib := b.vhdl\nVHDL_SOURCES := a.vhdl\nCOCOTB_TOPLEVEL := a\nCOCOTB_TEST_MODULES := test_ab\n\nifneq ($(filter $(SIM),xcelium),)\n    COMPILE_ARGS += -v93\nendif\n\nifneq ($(filter nvc questa-compat questa-qisqrun modelsim xcelium ius riviera,$(shell echo $(SIM) | tr A-Z a-z)),)\n    VHDL_LIB_ORDER := blib\nendif\n\nifneq ($(shell echo $(TOPLEVEL_LANG) | tr A-Z a-z),vhdl)\nall:\n\t@echo \"Skipping test since only VHDL is supported\"\nclean::\nelse ifeq ($(filter ghdl nvc questa-compat questa-qisqrun modelsim xcelium ius riviera,$(shell echo $(SIM) | tr A-Z a-z)),)\nall:\n\t@echo \"Skipping test since only GHDL, NVC, Questa/ModelSim, Xcelium, Incisive and Riviera-PRO are supported\"\nclean::\nelse\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\nendif\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries/a.vhdl",
    "content": "library blib;\n\nentity a is\n  port ( x : in boolean );\nend;\n\narchitecture structural of a is\nbegin\n  b : entity blib.b port map (x);\nend;\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries/b.vhdl",
    "content": "entity b is\n  port ( x : in boolean );\nend;\n\n\narchitecture structural of b is\nbegin\n  process(x) begin\n    report b'instance_name;\n  end process;\nend;\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries/test_ab.py",
    "content": "from __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test(dut):\n    # Toggling an input should trigger the simulator to print a message\n    # similar to:\n    #\n    #   b.vhdl:9:5:@0ms:(report note): :a(structural):b@b(structural):\n    #\n    dut.x.value = False\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries_multiple/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nSIM ?= ghdl\nTOPLEVEL_LANG ?= vhdl\n\nVHDL_SOURCES_blib := b.vhdl\nVHDL_SOURCES_clib := c.vhdl\nVHDL_SOURCES_dlib := d.vhdl\nVHDL_SOURCES_elib := e.vhdl\n\nVHDL_SOURCES := a.vhdl\nCOCOTB_TOPLEVEL := a\nCOCOTB_TEST_MODULES := test_abcde\n\nifneq ($(filter $(SIM),xcelium),)\n    COMPILE_ARGS += -v93\nendif\n\nifneq ($(filter nvc questa-compat questa-qisqrun modelsim xcelium riviera,$(shell echo $(SIM) | tr A-Z a-z)),)\n    VHDL_LIB_ORDER := elib dlib clib blib\nendif\n\nifneq ($(shell echo $(TOPLEVEL_LANG) | tr A-Z a-z),vhdl)\nall:\n\t@echo \"Skipping test since only VHDL is supported\"\nclean::\nelse ifeq ($(filter ghdl nvc questa-compat questa-qisqrun modelsim xcelium riviera,$(shell echo $(SIM) | tr A-Z a-z)),)\nall:\n\t@echo \"Skipping test since only GHDL, NVC, Questa/ModelSim, Xcelium and Riviera-PRO are supported\"\nclean::\nelse\ninclude $(shell cocotb-config --makefiles)/Makefile.sim\nendif\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries_multiple/a.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\nlibrary blib;\n\nentity a is\n  port ( x : in boolean );\nend;\n\narchitecture structural of a is\nbegin\n  b : entity blib.b port map (x);\nend;\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries_multiple/b.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\nlibrary clib;\n\nentity b is\n  port ( x : in boolean );\nend;\n\narchitecture structural of b is\nbegin\n  c : entity clib.c port map (x);\nend;\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries_multiple/c.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\nlibrary dlib;\n\nentity c is\n  port ( x : in boolean );\nend;\n\narchitecture structural of c is\nbegin\n  d : entity dlib.d port map (x);\nend;\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries_multiple/d.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\nlibrary elib;\n\nentity d is\n  port ( x : in boolean );\nend;\n\narchitecture structural of d is\nbegin\n  e : entity elib.e port map (x);\nend;\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries_multiple/e.vhdl",
    "content": "-- Copyright cocotb contributors\n-- Licensed under the Revised BSD License, see LICENSE for details.\n-- SPDX-License-Identifier: BSD-3-Clause\nentity e is\n  port ( x : in boolean );\nend;\n\n\narchitecture structural of e is\nbegin\n  process(x) begin\n    report e'instance_name;\n  end process;\nend;\n"
  },
  {
    "path": "tests/test_cases/test_vhdl_libraries_multiple/test_abcde.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport cocotb\n\n\n@cocotb.test()\nasync def test(dut):\n    pass\n"
  },
  {
    "path": "tests/test_cases/test_xfail/Makefile",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\n\nCOCOTB_TEST_MODULES := test_xfail\n\n# Ensure the correct number of tests ran.\n# Maybe one day we can explicitly check for XFAIL.\n.PHONY: override_for_this_test\noverride_for_this_test:\n\t$(MAKE) all\n\tpython -m cocotb_tools.combine_results | grep -q \"Ran a total .* 11 TestCases\"\n\ninclude ../../designs/sample_module/Makefile\n"
  },
  {
    "path": "tests/test_cases/test_xfail/test_xfail.py",
    "content": "# Copyright cocotb contributors\n# Licensed under the Revised BSD License, see LICENSE for details.\n# SPDX-License-Identifier: BSD-3-Clause\nfrom __future__ import annotations\n\nimport sys\n\nimport pytest\n\nimport cocotb\n\nif sys.version_info < (3, 11):\n    from exceptiongroup import ExceptionGroup\n\n\n@cocotb.test\nasync def test_xfail(_: object) -> None:\n    pytest.xfail(\"This test is expected to fail\")\n\n\nclass MyException(Exception):\n    pass\n\n\n@cocotb.test(expect_fail=True)\nasync def test_expect_arg_assert(_: object) -> None:\n    assert False\n\n\n@cocotb.test(expect_fail=True)\nasync def test_expect_arg_raises(_: object) -> None:\n    with pytest.raises(ValueError):\n        pass\n\n\n@cocotb.test(expect_fail=True)\nasync def test_expect_arg_warns(_: object) -> None:\n    with pytest.warns(DeprecationWarning):\n        pass\n\n\n@cocotb.test(expect_error=MyException)\nasync def test_expect_arg_exception(_: object) -> None:\n    raise MyException()\n\n\n@cocotb.test\n@cocotb.xfail(reason=\"This test is expected to fail\")\nasync def test_xfail_assert(_: object) -> None:\n    assert False\n\n\n@cocotb.test\n@cocotb.xfail(reason=\"This test is expected to fail\")\nasync def test_xfail_raises(_: object) -> None:\n    with pytest.raises(ValueError):\n        pass\n\n\n@cocotb.test\n@cocotb.xfail(reason=\"This test is expected to fail\")\nasync def test_xfail_warns(_: object) -> None:\n    with pytest.warns(DeprecationWarning):\n        pass\n\n\n@cocotb.test\n@cocotb.xfail(raises=MyException, reason=\"This test is expected to fail\")\nasync def test_xfail_exception(_: object) -> None:\n    raise MyException()\n\n\n@cocotb.test\n@cocotb.xfail(\n    raises=pytest.RaisesGroup(\n        ValueError,\n        ValueError,\n        pytest.RaisesExc(TypeError, match=\"^expected int$\"),\n        match=\"^my group$\",\n    )\n)\nasync def test_xfail_with_raises_group(dut: object) -> None:\n    raise ExceptionGroup(\n        \"my group\",\n        [\n            ValueError(),\n            TypeError(\"expected int\"),\n            ValueError(),\n        ],\n    )\n\n\n@cocotb.test\n@cocotb.xfail(raises=pytest.RaisesGroup(pytest.RaisesGroup(ValueError)))\nasync def test_xfail_with_raises_group_nested(dut: object) -> None:\n    raise ExceptionGroup(\"\", (ExceptionGroup(\"\", (ValueError(),)),))\n"
  }
]