This is a bridge between VUnit’s external VHDL API and C, through GHDL’s VHPIDIRECT features (see Interfacing to other languages). A Python class (named VHPIDIRECT) provides helper functions to (re)use a C API (vhpidirect_user.h, grt.ver and/or stubs.c) with VUnit’s add_builtins and set_sim_option("ghdl.elab_flags", ...). Examples of how to use this bridge are shown in VHPIDIRECT.


In the latest stable release of GHDL (v0.36), mcode backend does not support VHPIDIRECT. Moreover, using LLVM or GCC backends is suggested, as these generate executable files and are supported in a wider range of platforms.


For GHDL to generate PIE executable files, it needs to be configured with option --default-pic. Moreover, loading ELF binaries dynamically is a hackish procedure that takes advantage of PIE ELF binaries and shared libraries having a common structure on GNU/Linux. However, this does not work on Windows (see ghdl/ghdl#803). As a result:

  • GHDL needs to be enhanced to allow building designs as shared libraries instead of executable binaries (see ghdl/ghdl#800).

  • or, build features in VUnit need to be extended to use ghdl --bind, ghdl --list-link and gcc/clang in order to generate a *.dll on Windows.

  • or, a helper method need to be added to this class to use gcc/clang.

Implementation details

vhpidirect_user.h is the C implementation of the interface. It uses an array of pointers (uint8_t *D[256];) to keep a reference to all the buffers that are shared between C and VHDL.


Users that need to share more than 256 pointers, can and should include their own copy of this header file. Actually, in example Copy the provided header file is not used. Instead, functions are implemented in main.c.

stubs.c is to be used when multiple tests are handled in a single run.py file (i.e. by the same VUnit object), but some of them do NOT use external modes. Since builtins are compiled once only, every test (binary) needs to have placeholders for the C functions that VHDL expects to use. stubs.c provides dummy definitions of the C API. Note that these will produce errors if executed at runtime.

grt.ver is to be used when the ELF file built with GHDL is to be loaded dynamically. By default, GHDL hides most of the global symbols. Providing this file as an elaboration option ensures that the functions of the C API are visible. Script corun.py in example Buffer shows how to dynamically load and execute the simulation from Python.

extfnc mode

As explained in External VHDL API, mode extfnc is expected to be used when data is not available in the same memory space as the VHDL simulation. For example, when libraries such as gRPC, ZeroMQ or netpp are used to co-execute simulations in remote targets. Hence, write_*/read_* function bodies provided in vhpidirect_user.h are for testing purposes. In practice, developers willing to use this mode are expected to provide their own custom header file.

Note that this is the difference between extfnc and extacc: with extacc, there is no explicit callback when VHDL modifies a value in a shared buffer. Conversely, with extfnc, VHDL cannot modify a value without a callback.

Python interface

class cosim.vhpidirect.VHPIDIRECT

VHPIDIRECT VUnit co-simulation bridge class


srcs – optional alternative location of the sources


Get lists of files to register the bridge with vu.add_builtins


features – struct,``{‘string’: <VAL>, ‘integer’: <VAL> }``, to provide bridges for the external VHDL API. Accepted values are True, False, None or ['path/to/custom/file'].

property include

Get path to include directories containing C sources/headers

static post_func(results)

Optional post-func to copy runtime args for each test/executable to output subdir ‘cosim’


Get argument to add a custom version-script file to GHDL


file – provide a custom file instead of the one provided with the bridge