The UVVM demo projects
UVVM is a verification library for VHDL. It comes with demo testbenches for its own example designs and verification components: a UART, an interrupt controller, a scoreboard, Ethernet and more. They are a good way to see a real verification environment run. This tutorial runs all eight of them with JanusHDL.
1. Get UVVM
JanusHDL does not include UVVM; you get it from its own project, so you always have the version you choose. With git:
git clone https://github.com/UVVM/UVVM.git
cd UVVM
Or download the zip from the project page on GitHub and unpack it. The file lists below were tested with the UVVM release of April 2026 (commit 90d56e9). A later release may add or move files; if a file is missing, the error names it.
2. Get the file lists
A JanusHDL file list names the source files of a design, each under its library, in the order they are analyzed. Download the one for the demo you want, or all eight, into the UVVM folder, the one that holds uvvm_util. The paths inside are relative to that folder.
| Demo | What it shows | File list | Top |
|---|---|---|---|
| IRQC | An interrupt controller, tested with plain UVVM utility calls: no verification components. | uvvm_irqc_demo.f | bitvis_irqc.irqc_demo_tb |
| UART | A UART, driven by verification components (VVCs) for its bus and its serial lines. | uvvm_uart_demo.f | bitvis_uart.uart_vvc_demo_tb |
| Error injection | Faults injected into a signal between two components, on purpose. | uvvm_ei_demo.f | bitvis_vip_error_injection.ei_demo_tb |
| Scoreboard | A scoreboard comparing what the UART sends with what was expected. | uvvm_sb_demo.f | bitvis_vip_scoreboard.sb_uart_sbi_demo_tb |
| UART VIP | The UART verification component on its own, with its monitor. | uvvm_vip_uart_demo.f | bitvis_vip_uart.uvvm_demo_tb |
| Assertions | UVVM's assertion checks on a running design. | uvvm_assertions_demo.f | uvvm_assertions.uvvm_assertions_demo_tb |
| Coverage | Constrained random stimulus and functional coverage on the UART. | uvvm_cr_fc_demo.f | bitvis_uart.cr_fc_demo_tb |
| Ethernet | Ethernet frames over a GMII interface, checked by a scoreboard. The longest run. | uvvm_ethernet_demo.f | bitvis_vip_ethernet.ethernet_sbi_gmii_demo_tb |
Open one in a text editor: it is plain text, a library line followed by that library's files, then the next library. You can write your own the same way.
3. Run a demo
From the UVVM folder:
jhdl --compat -f uvvm_uart_demo.f --top bitvis_uart.uart_vvc_demo_tb
The top is given as library.entity, because the testbench is not in the library work. JanusHDL analyzes the files, elaborates the testbench and runs it, all in one command. --compat turns on compatibility mode, which UVVM needs.
Why --compat
Since VHDL-2002, the standard allows a shared variable only of a protected type, so that two processes cannot update it at the same time. UVVM keeps a few settings in plain shared variables. JanusHDL reports what the standard forbids as an error, so without --compat the analysis stops, and the first error says why and what to do:
error[unprotected-shared-variable]: a shared variable must be of a protected type, not T_LOG_DESTINATION
--> uvvm_util/src/string_methods_pkg.vhd:31:3
|
31 | shared variable shared_default_log_destination : t_log_destination := C_DEFAULT_LOG_DESTINATION;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: wrap the value in a protected type, or analyze the file as VHDL-93 (--std 93); or run with --compat, which accepts it and simulates it as written
= LRM 6.4.2.4
The packages that declare such variables then fail to analyze, and every unit that uses them says so, so the output goes on for a while and ends with analysis failed; the first error is the one to read. (On Windows, paths show with \.)
With --compat, each of them is a warning instead, 42 for the UART demo, and UVVM runs as written:
warning[unprotected-shared-variable]: a shared variable must be of a protected type, not T_LOG_DESTINATION
--> uvvm_util/src/string_methods_pkg.vhd:31:3
|
31 | shared variable shared_default_log_destination : t_log_destination := C_DEFAULT_LOG_DESTINATION;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: accepted in compatibility mode (--compat) and simulated as written; to make it legal: wrap the value in a protected type, or analyze the file as VHDL-93 (--std 93)
= LRM 6.4.2.4
The warnings do not affect the run. To leave them out as well:
jhdl --compat -f uvvm_uart_demo.f --top bitvis_uart.uart_vvc_demo_tb --allow unprotected-shared-variable
In the window, tick Compatibility mode in the Run dialog (Simulate → Run simulation…); it is remembered for the file list.
The run
Then the testbench prints UVVM's log as it goes: each check, each transaction of the verification components, each alert. At the end, UVVM prints its summary of alerts, and the last lines look like this:
UVVM: >> Simulation SUCCESS: No mismatch between counted and expected serious alerts
...
UVVM: ID_LOG_HDR 370673.5 ns TB seq. SIMULATION COMPLETED
...
simulation of bitvis_uart.uart_vvc_demo_tb ended at 370.6735 µs (stopped); analysis … ms, elaboration … ms, run … ms
The first line is UVVM's verdict. The last is JanusHDL's: where the simulation stopped (stopped: the testbench ended it), and how long analysis, elaboration and the run took on your machine. UVVM also writes its log to UVVM_Log.txt and its alerts to UVVM_Alert.txt in the current folder.
One demo, the UART VIP, sends bytes with parity and stop-bit errors on purpose. The UART design reports each with an assertion of severity error, so that run ends with exit code 1 although UVVM says SUCCESS: it expected those errors. The other seven end with exit code 0.
4. Faster the second time
Each run starts by analyzing the UVVM sources. Keep the analysis in a cache:
jhdl --compat -f uvvm_uart_demo.f --top bitvis_uart.uart_vvc_demo_tb --cache uvvm.cache
The next run with the same cache reads the analyzed libraries back instead of analyzing them again, as long as no source file changed and the options that affect analysis (here --compat) are the same; that takes a small fraction of the time analysis takes. The warnings are kept with it and shown again. Give each demo its own cache file: a cache holds the analysis of one list of files.
Native code is on by default: what qualifies is compiled to machine code while the simulation runs, and the rest runs in the interpreter, with the same results. --jit off runs everything in the interpreter.
5. Look at the waveforms
jhdl --compat -f uvvm_uart_demo.f --top bitvis_uart.uart_vvc_demo_tb --wave uart.jhw
jhdlw uart.jhw
In the viewer, open the hierarchy down to the UART and pick the signals of its bus and serial lines.
6. All eight at once
On Windows, a small batch file in the UVVM folder runs every demo, each in its own folder so their logs stay apart:
@echo off
for %%d in (irqc:bitvis_irqc.irqc_demo_tb
uart:bitvis_uart.uart_vvc_demo_tb
ei:bitvis_vip_error_injection.ei_demo_tb
sb:bitvis_vip_scoreboard.sb_uart_sbi_demo_tb
vip_uart:bitvis_vip_uart.uvvm_demo_tb
assertions:uvvm_assertions.uvvm_assertions_demo_tb
cr_fc:bitvis_uart.cr_fc_demo_tb
ethernet:bitvis_vip_ethernet.ethernet_sbi_gmii_demo_tb) do call :run %%d
goto :eof
:run
for /f "tokens=1,2 delims=:" %%a in ("%1") do (
mkdir runs\%%a 2>nul
pushd runs\%%a
jhdl --compat -f ..\..\uvvm_%%a_demo.f --top %%b --cache uvvm.cache --allow unprotected-shared-variable > out.txt 2>&1
findstr /c:"Simulation SUCCESS" out.txt >nul && echo %%a: SUCCESS || echo %%a: FAILED, see runs\%%a\out.txt
popd
)
On Linux, the same in a shell loop:
for d in irqc:bitvis_irqc.irqc_demo_tb uart:bitvis_uart.uart_vvc_demo_tb \
ei:bitvis_vip_error_injection.ei_demo_tb sb:bitvis_vip_scoreboard.sb_uart_sbi_demo_tb \
vip_uart:bitvis_vip_uart.uvvm_demo_tb assertions:uvvm_assertions.uvvm_assertions_demo_tb \
cr_fc:bitvis_uart.cr_fc_demo_tb ethernet:bitvis_vip_ethernet.ethernet_sbi_gmii_demo_tb; do
name=${d%%:*}; top=${d#*:}
mkdir -p runs/$name
(cd runs/$name && jhdl --compat -f ../../uvvm_${name}_demo.f --top $top --cache uvvm.cache \
--allow unprotected-shared-variable > out.txt 2>&1)
grep -q "Simulation SUCCESS" runs/$name/out.txt && echo "$name: SUCCESS" || echo "$name: FAILED"
done
Next
Use one of these file lists as the start of your own: keep the UVVM libraries, and add your design and testbench at the end, under their own library, and run it with --compat. In the window, File → Import a file list (.f) as a project… makes a project of it; turn on Compatibility mode in its settings. If a construct in your code is not supported yet, the error says which one.