Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7c6271c
Add run_script_path to runner_cfg and result accessors to check_pkg
ru551n Sep 13, 2026
bf15053
Add a VHDL to Python interface: python_pkg on a native bridge
ru551n Sep 13, 2026
b55dbf4
Add the embedded Python example
ru551n Sep 13, 2026
af66484
Document the VHDL to Python interface
ru551n Sep 13, 2026
cda4e4e
Add CI for the VHDL to Python interface
ru551n Sep 13, 2026
24035be
Announce the VHDL to Python interface as a feature
ru551n Sep 14, 2026
b9430da
Use join() for the paths in the embedded Python example
ru551n Sep 14, 2026
d7a4009
Name the typed subprograms and types std_ulogic
ru551n Sep 14, 2026
4ce146e
Resolve a relative exec_file name from the testbench directory
ru551n Sep 14, 2026
6644db1
Keep all argument constructors in one place
ru551n Sep 14, 2026
59860e3
Drop the unused operation parameter of p_arg_value
ru551n Sep 14, 2026
bbb1847
Use is_x to find the metavalues of an argument value
ru551n Sep 14, 2026
4d5c399
Remove the string argument forms of to_call_str and call
ru551n Sep 14, 2026
d33a067
Make a call with an argument that failed fail in Python
ru551n Sep 14, 2026
e4ffa82
Let positional arguments form groups too
ru551n Sep 14, 2026
9e0cdfd
Say why null_arg is the identity of an argument group
ru551n Sep 14, 2026
91ff756
Make a Python session a VUnit object
ru551n Sep 14, 2026
6f34c38
Give every session its own logger and follow the object conventions
ru551n Sep 14, 2026
4a3e31b
Simplify the Python bridge without changing its behaviour
ru551n Sep 14, 2026
e56c08d
Name the news fragments after their pull request
ru551n Sep 15, 2026
c73f4f6
Take the run script from the file Python was started with
ru551n Sep 15, 2026
50a9d66
Raise instead of exiting when add_python() cannot set up the package
ru551n Sep 15, 2026
9a7db2d
Remove the input stimuli files of the embedded Python example
ru551n Sep 15, 2026
6c70078
Move the C sources of the VHPI application next to the bridge
ru551n Sep 15, 2026
ac6350b
Describe the C sources of the VHPI application in their first comment…
ru551n Sep 15, 2026
2efe5af
Fall back to gcc on PATH for the Windows bridge builds
ru551n Sep 17, 2026
25693bb
Require a 64-bit simulator for VHDL Python support on Windows
ru551n Sep 17, 2026
128da0a
Test the gcc build of the bridge on Windows CI
ru551n Sep 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@ jobs:
- name: '🚧 Run job'
run: tox -e py${{ matrix.task }} -- --color=yes

#
# Prebuilt Windows DLLs of the VHDL Python bridge, included in releases
#

python-bridge-dlls:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
uses: ./.github/workflows/python_bridge_dlls.yml

#
# Deploy to PyPI
#
Expand All @@ -177,6 +185,7 @@ jobs:
- ghdl
- nvc
- win
- python-bridge-dlls
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
name: '🚀 Deploy'
steps:
Expand All @@ -186,6 +195,12 @@ jobs:
with:
submodules: recursive

- name: '📥 Download Python bridge DLLs'
uses: actions/download-artifact@v4
with:
name: python-bridge-dlls
path: vunit/python_bridge/bin

- name: '🐍 Setup Python'
uses: actions/setup-python@v6
with:
Expand Down
235 changes: 235 additions & 0 deletions .github/workflows/python_bridge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
name: 'python bridge'

# Tests of the VHDL Python integration, add_python(), in the environments
# push.yml does not provide: CPython from python.org, on Linux
# (bridge compiled on first use) and Windows (prebuilt MSVC DLLs), and the
# content of the package.

on:
push:
pull_request:
workflow_dispatch:

defaults:
run:
shell: bash

jobs:

#
# Linux and macOS, bridge compiled on first use
#

posix:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# The oldest and newest supported CPython; every GHDL backend, since
# the bridge library is loaded differently by the ones that link ahead
# of time (llvm, gcc), on the latest release; the NVC release VUnit is
# developed against.
#
# Canaries (allowed to fail): the GHDL nightly builds and NVC built
# from its master branch, with Python 3.14, where simulator changes
# show up first.
include:
- { os: ubuntu-24.04, py: '3.10', sim: nvc, nvc: '1.22.1' }
- { os: ubuntu-24.04, py: '3.14', sim: nvc, nvc: '1.22.1' }
- { os: ubuntu-24.04, py: '3.14', sim: nvc, nvc: master, canary: true }
- { os: ubuntu-24.04, py: '3.10', sim: ghdl, backend: mcode, ghdl: latest }
- { os: ubuntu-24.04, py: '3.14', sim: ghdl, backend: mcode, ghdl: nightly, canary: true }
- { os: ubuntu-24.04, py: '3.14', sim: ghdl, backend: llvm-jit, ghdl: latest }
- { os: ubuntu-24.04, py: '3.14', sim: ghdl, backend: llvm-jit, ghdl: nightly, canary: true }
- { os: ubuntu-24.04, py: '3.14', sim: ghdl, backend: llvm, ghdl: latest }
- { os: ubuntu-24.04, py: '3.14', sim: ghdl, backend: llvm, ghdl: nightly, canary: true }
- { os: ubuntu-24.04, py: '3.14', sim: ghdl, backend: gcc, ghdl: latest }
- { os: ubuntu-24.04, py: '3.14', sim: ghdl, backend: gcc, ghdl: nightly, canary: true }
- { os: macos-15, py: '3.14', sim: nvc, nvc: brew }
# macos-15: setup-ghdl has no build for newer macOS versions yet, and only the llvm backend
- { os: macos-15, py: '3.14', sim: ghdl, backend: llvm, ghdl: latest }
name: '${{ matrix.os }} · Python ${{ matrix.py }} · ${{ matrix.sim }} ${{ matrix.backend }}${{ matrix.ghdl }}${{ matrix.nvc }}'
continue-on-error: ${{ matrix.canary || false }}
env:
VUNIT_SIMULATOR: ${{ matrix.sim }}
steps:

- name: '🧰 Checkout'
uses: actions/checkout@v4
with:
submodules: recursive

- name: '🐍 Setup Python'
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.py }}

- name: '⚙️ Setup NVC'
if: matrix.sim == 'nvc' && matrix.nvc != 'brew' && matrix.nvc != 'master'
run: |
curl -fsSL -o nvc.deb "https://github.com/nickg/nvc/releases/download/r${{ matrix.nvc }}/nvc_${{ matrix.nvc }}-1_amd64_ubuntu-24.04.deb"
sudo apt-get install -y ./nvc.deb

# As in NVC's README
- name: '⚙️ Build NVC from its master branch'
if: matrix.nvc == 'master'
run: |
sudo apt-get install -y -qq build-essential automake autoconf flex check llvm-dev pkg-config zlib1g-dev libdw-dev libffi-dev libzstd-dev
git clone --depth 1 https://github.com/nickg/nvc.git "$RUNNER_TEMP/nvc"
cd "$RUNNER_TEMP/nvc" && ./autogen.sh && mkdir build && cd build && ../configure && make -j"$(nproc)" && sudo make install
nvc --version

- name: '⚙️ Setup NVC with Homebrew'
if: matrix.nvc == 'brew'
run: brew install nvc

- name: '⚙️ Setup GHDL'
if: matrix.sim == 'ghdl'
uses: ghdl/setup-ghdl@main
with:
version: ${{ matrix.ghdl }}
backend: ${{ matrix.backend }}

# The environment and the output go to the runner's temporary directory,
# outside the checkout, so nothing built can end up in the tree. The space
# in the path is deliberate: the bridge builds command lines and simulator
# options from these paths.
- name: '🐍 Install VUnit in a virtual environment'
run: |
python -m venv "$RUNNER_TEMP/venv with space"
echo "$RUNNER_TEMP/venv with space/bin" >> "$GITHUB_PATH"
"$RUNNER_TEMP/venv with space/bin/pip" install -e . --progress-bar off

- name: '🚧 Feature tests'
run: python vunit/vhdl/python/run.py -p 4 -o "$RUNNER_TEMP/out dir"

- name: '🚧 Example'
run: python examples/vhdl/embedded_python/run.py -p 4 --without-attributes .optional_deps --without-attributes .expected_failure

#
# Windows, prebuilt MSVC DLLs
#

dlls:
uses: ./.github/workflows/python_bridge_dlls.yml

windows:
needs: dlls
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
py: ['3.10', '3.12', '3.14']
sim: [nvc, ghdl]
bridge: [dll]
# No prebuilt DLLs: the library is built with the MinGW gcc of the runner image, the
# build Questa/ModelSim always uses on Windows, which has no runner
include:
- {py: '3.13', sim: nvc, bridge: gcc}
name: '🟦 Windows · Python ${{ matrix.py }} · ${{ matrix.sim }} · ${{ matrix.bridge }}'
env:
VUNIT_SIMULATOR: ${{ matrix.sim }}
steps:

- name: '🧰 Checkout'
uses: actions/checkout@v4
with:
submodules: recursive

- name: '📥 Download bridge DLLs'
if: matrix.bridge == 'dll'
uses: actions/download-artifact@v4
with:
name: python-bridge-dlls
path: vunit/python_bridge/bin

- name: '⚙️ Put MinGW gcc on PATH'
if: matrix.bridge == 'gcc'
run: echo "C:/mingw64/bin" >> "$GITHUB_PATH"

- name: '🐍 Setup Python'
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.py }}
architecture: x64

- name: '⚙️ Setup NVC'
if: matrix.sim == 'nvc'
shell: pwsh
run: |
Invoke-WebRequest -Uri https://github.com/nickg/nvc/releases/download/r1.22.1/nvc-1.22.1.msi -OutFile nvc.msi
Start-Process msiexec.exe -Wait -ArgumentList '/i', 'nvc.msi', '/qn', '/norestart'
$bin = Get-ChildItem -Path 'C:\Program Files*' -Recurse -Filter nvc.exe -ErrorAction SilentlyContinue | Select-Object -First 1
$bin.DirectoryName | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

- name: '⚙️ Setup GHDL'
if: matrix.sim == 'ghdl'
uses: ghdl/setup-ghdl@main
with:
backend: mcode

# Same as on Linux: outside the checkout, with a space in the path
- name: '🐍 Install VUnit in a virtual environment'
run: |
python -m venv "$RUNNER_TEMP/venv with space"
echo "$RUNNER_TEMP/venv with space/Scripts" >> "$GITHUB_PATH"
"$RUNNER_TEMP/venv with space/Scripts/pip" install -e . --progress-bar off

# The simulator is accepted as x64, and a 32-bit executable of Windows itself is detected
- name: '🔍 64-bit check'
run: |
python -c "import shutil; from vunit.python_bridge.native_library import pe_machine; \
assert pe_machine(shutil.which('${{ matrix.sim }}')) == 0x8664; \
assert pe_machine(r'C:\Windows\SysWOW64\cmd.exe') == 0x14C"

# dll: no MSVC on PATH, the prebuilt DLLs must be used. gcc: the library must be built with gcc.
- name: '🚧 Feature tests'
run: |
! command -v cl
if [ '${{ matrix.bridge }}' = gcc ]; then command -v gcc; fi
python vunit/vhdl/python/run.py -p 4 -o "$RUNNER_TEMP/out dir"
if [ '${{ matrix.bridge }}' = gcc ]; then
find "$RUNNER_TEMP/out dir" -path '*-win_amd64-gcc-*' -name vunit_python_bridge.dll | grep .
fi

- name: '🚧 Example'
run: python examples/vhdl/embedded_python/run.py -p 4 --without-attributes .optional_deps --without-attributes .expected_failure

#
# Packaging, sources and DLLs included, no Linux binaries
#

packaging:
needs: dlls
runs-on: ubuntu-latest
name: '📦 Packaging'
steps:

- name: '🧰 Checkout'
uses: actions/checkout@v4
with:
submodules: recursive

- name: '📥 Download bridge DLLs'
uses: actions/download-artifact@v4
with:
name: python-bridge-dlls
path: vunit/python_bridge/bin

- name: '🐍 Setup Python'
uses: actions/setup-python@v6
with:
python-version: '3.13'

- name: '📦 Build sdist'
run: |
pip install -U setuptools wheel --progress-bar off
python setup.py sdist

# The C sources, the five DLLs, no Linux binary
- name: '🔍 Check sdist content'
run: |
tar tzf dist/*.tar.gz > content.txt
grep -q 'vunit/python_bridge/native/bridge.h$' content.txt
test "$(grep -c 'vunit/python_bridge/bin/vunit_python_bridge-cp3[0-9]*-win_amd64.dll$' content.txt)" = 5
! grep -q '\.so$' content.txt
63 changes: 63 additions & 0 deletions .github/workflows/python_bridge_dlls.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: 'python bridge dlls'

# Builds the prebuilt Windows DLLs of the VHDL Python bridge with MSVC, one per
# CPython version. Called by python_bridge.yml and by push.yml for releases.

on:
workflow_call:

jobs:

build:
runs-on: windows-latest
strategy:
matrix:
py: ['3.10', '3.11', '3.12', '3.13', '3.14']
name: '🟦 MSVC · bridge DLL · Python ${{ matrix.py }}'
steps:

- name: '🧰 Checkout'
uses: actions/checkout@v4

- name: '🐍 Setup Python'
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.py }}
architecture: x64

- name: '⚙️ Setup MSVC'
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64

- name: '🔨 Build DLL'
run: python tools/build_python_bridge.py --output-dir dlls

- name: '📤 Upload DLL'
uses: actions/upload-artifact@v4
with:
name: python-bridge-dll-${{ matrix.py }}
path: dlls/*.dll
if-no-files-found: error

collect:
needs: build
runs-on: ubuntu-latest
name: '📦 Collect bridge DLLs'
steps:

- name: '📥 Download DLLs'
uses: actions/download-artifact@v4
with:
pattern: python-bridge-dll-*
merge-multiple: true
path: dlls

- name: '🔍 Check DLLs'
run: test "$(ls dlls/*.dll | wc -l)" = 5

- name: '📤 Upload DLLs'
uses: actions/upload-artifact@v4
with:
name: python-bridge-dlls
path: dlls/*.dll
5 changes: 5 additions & 0 deletions docs/hdl_libraries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ VUnit includes several optional libraries in a group named *VHDL builtins* (see
Most of the utilities are based on some internal data types providing dynamic arrays and queues (FIFOs).
See :ref:`data_types_library`.

With :meth:`add_python() <vunit.ui.VUnit.add_python>`, testbenches can also execute Python code and call Python
functions through :vunit_file:`python <vunit/vhdl/python>` (``context vunit_lib.python_context;``). NVC, GHDL and
Questa/ModelSim are served by the VUnit Python bridge, Riviera-PRO/Active-HDL by a VHPI application.
See :ref:`python_bridge`.

Communication
-------------

Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ often"* approach through automation. :ref:`Read more <about>`
com/user_guide
verification_components/user_guide
data_types/user_guide
python_bridge/user_guide

.. toctree::
:caption: Reference
Expand Down
9 changes: 9 additions & 0 deletions docs/news.d/1220.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
VHDL testbenches can now execute Python code and call Python functions
directly from the simulator: NumPy reference models, checkers, file access and
anything else the Python ecosystem offers. The VHDL API is ``python_pkg`` and
it is enabled with ``add_python()`` after ``add_vhdl_builtins()``. Values of
all the common VHDL types cross the boundary in both directions, as arguments
and as results. The API is available on NVC, GHDL and Questa/ModelSim through
the VUnit Python bridge, and on Riviera-PRO/Active-HDL through a VHPI
application, both of which ``add_python()`` builds under the output path. See
:ref:`python_bridge`.
3 changes: 3 additions & 0 deletions docs/news.d/1221.feature.1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added accessor functions to ``check_pkg`` for inspecting a ``check_result_t``:
``is_pass``, ``get_checker``, ``get_msg``, ``get_log_level``, ``get_line_num`` and
``get_file_name``.
2 changes: 2 additions & 0 deletions docs/news.d/1221.feature.2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Added ``run_script_path(runner_cfg)`` to ``run_pkg``, returning the path of the
VUnit run script that started the simulation.
Loading
Loading