Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial programming >> VHDL

VUnit 101: A Practical Guide to Automated VHDL Verification

VUnit is a leading open‑source VHDL verification framework that couples a Python test‑suite runner with a dedicated VHDL library. Together they automate testbench compilation, execution, and result reporting, enabling engineers to follow a test‑driven development cycle.

In this tutorial, Ahmadmunthar Zaklouta, the author behind VHDLwhiz, walks you through the entire VUnit workflow—from installation and configuration to creating a testbench, writing test cases, and running them in ModelSim. A ready‑to‑run example project is available for download.

Overview

Use the sidebar or the mobile navigation button to jump between sections. The tutorial includes screenshots for visual reference.

Requirements

Basic VHDL and ModelSim proficiency is assumed.

Installing VUnit

Clone the repository with submodules:

git clone --recurse-submodules https://github.com/VUnit/vunit.git

Or download the ZIP, extract it to C:\vunit, then install via:

cd C:\vunit
python setup.py install

Configure environment variables:

Example screenshot:

VUnit 101: A Practical Guide to Automated VHDL Verification

Download the Example Project

Extract the ZIP to C:\vunit_tutorial and run the included scripts.

Introduction to VUnit

VUnit simplifies HDL verification by providing:

The VHDL side includes six libraries; this tutorial focuses on the logging and check libraries.

VUnit 101: A Practical Guide to Automated VHDL Verification

Design Under Test (DUT)

The example DUT, motor_start, drives three LEDs (RED, YELLOW, GREEN) to represent a motor’s startup sequence. Its interface uses record types for inputs and outputs.

VUnit 101: A Practical Guide to Automated VHDL Verification

The startup process has three steps:

  1. Loading configuration (RED LED)
  2. Calibration (YELLOW LED)
  3. Rotation (GREEN LED)

Startup Sequence

Testbench Development

  1. Configure the Python run.py script.
  2. Build the VUnit skeleton.
  3. Instantiate the DUT and drive signals.

Python Run Script

The run.py script defines paths, creates a VUnit instance, and adds design and testbench libraries:

# ROOT directory
ROOT = Path(__file__).resolve().parent
# Source paths
DUT_PATH = ROOT / "design"
TEST_PATH = ROOT / "testbench"

# VUnit instance
VU = VUnit.from_argv()
VU.enable_location_preprocessing()

# Libraries
design_lib = VU.add_library("design_lib")
design_lib.add_source_files([DUT_PATH / "*.vhdl"])

tb_lib = VU.add_library("tb_lib")
tb_lib.add_source_files([TEST_PATH / "*.vhdl"])

VUnit Skeleton

In the testbench entity, add the VUnit context and a mandatory generic:

LIBRARY VUNIT_LIB;
CONTEXT VUNIT_LIB.VUNIT_CONTEXT;

ENTITY motor_start_tb IS
  GENERIC(runner_cfg : string := runner_cfg_default);
END ENTITY motor_start_tb;

The architecture hosts the test runner process:

ARCHITECTURE tb OF motor_start_tb IS
  test_runner : PROCESS
  BEGIN
    test_runner_setup(runner, runner_cfg);
    WHILE test_suite LOOP
      -- test cases
    END LOOP;
    test_runner_cleanup(runner);
  END PROCESS;
END ARCHITECTURE;

Individual test cases are defined with IF run("case_name") THEN blocks.

Signal Declarations & DUT Instantiation

Define clocks, resets, and interface records:

CONSTANT C_CLK_PERIOD : time := 10 ns;
SIGNAL clk, reset : STD_LOGIC := '0';
SIGNAL motor_start_in  : MOTOR_START_IN_RECORD_TYPE := (switch_1 => '0', switch_2 => '0', switch_3 => '0');
SIGNAL motor_start_out : MOTOR_START_OUT_RECORD_TYPE;

Instantiate the DUT:

motor_start_tb_inst : ENTITY DESIGN_LIB.motor_start(rtl)
  PORT MAP(
    clk            => clk,
    reset          => reset,
    motor_start_in => motor_start_in,
    motor_start_out => motor_start_out
  );

Drive clock and reset:

clk   <= NOT clk after C_CLK_PERIOD / 2;
reset <= '0' after 5 * (C_CLK_PERIOD / 2);

Test Case Development

We explore three verification styles: inline driver & checker, controlled checker, and self‑checking checker.

Inline Driver & Checker

A simple test case that drives switch_1 and checks LED states using VUnit’s check family:

IF run("switch_1_on_output_check") THEN
  WAIT UNTIL reset = '0';
  WAIT UNTIL falling_edge(clk);
  motor_start_in.switch_1 <= '1';
  FOR i IN 0 TO 4 LOOP
    WAIT UNTIL rising_edge(clk);
    check(motor_start_out.red_led = '1', "Red LED should be on");
    check_false(motor_start_out.yellow_led, "Yellow LED should be off");
    check_equal(motor_start_out.green_led, '0', "Green LED should be off");
  END LOOP;
END IF;

Controlled Checker

Here the driver remains in the test case while the checker runs in a separate process, controlled by start/end events. For example, verifying the YELLOW LED after switch_2 is enabled:

check_stable(clock       => clk,
             en          => enable,
             start_event => yellow_low_start_event,
             end_event   => yellow_low_end_event,
             expr        => motor_start_out.yellow_led,
             msg         => "YELLOW LED low before switch_2");

Self‑Checking Checker

Encapsulate verification logic in a dedicated process that uses check or check_stable internally. A driver procedure simplifies stimulus:

PROCEDURE switch_driver(
  SIGNAL switches     : OUT MOTOR_START_IN_RECORD_TYPE;
  CONSTANT clk_period : IN TIME;
  CONSTANT sw1_delay  : IN INTEGER;
  CONSTANT sw2_delay  : IN INTEGER;
  CONSTANT sw3_delay  : IN INTEGER) IS
BEGIN
  IF sw1_delay >= 0 THEN
    WAIT FOR clk_period * sw1_delay;
    switches.switch_1 <= '1';
  END IF;
  IF sw2_delay >= 0 THEN
    WAIT FOR clk_period * sw2_delay;
    switches.switch_2 <= '1';
  END IF;
  IF sw3_delay >= 0 THEN
    WAIT FOR clk_period * sw3_delay;
    switches.switch_3 <= '1';
  END IF;
END PROCEDURE;

Running Tests

From the terminal:

python .\run.py *switch_1_on_output_check

VUnit compiles the design, discovers testbenches, and executes the specified case. Output is logged to C:\vunit_tutorial\vunit_out\test_output.

Use -v for verbose logs, -l to list all cases, --clean to purge previous results, or -g to launch ModelSim with a waveform window (requires a wave.do file).

Summary

VUnit offers a robust, lightweight framework that accelerates both design and verification teams. Its Python‑driven test harness, rich VHDL libraries, and flexible checker API make it a valuable addition to any HDL workflow.

Next Steps

Download the full example project via the form below.

VHDL

  1. Connext DDS 101: A Beginner’s Guide to Getting Started
  2. A Practical Guide to Ceramic 3D Printing: Techniques, Materials, and Design Tips
  3. Getting Started with TJBot: Build, Configure, and Voice‑Control Your Own AI Robot
  4. AI in Insurance: A Practical Starter Guide for Real-World Implementation
  5. Master Permanent Mold Casting: A Beginner's Guide to Durable, High-Volume Metal Parts
  6. Touch Switch Circuits: A Beginner’s Guide to Simple Tactile Sensors
  7. Optimize Cat® Machinery: The Ultimate My.Cat.com Guide
  8. Deploying Node-RED on PLCnext with Docker: A Step‑by‑Step Guide
  9. Build Your First Go Application on PLCnext: A Beginner’s Guide
  10. How to Convert Your Tormach CNC into a 2D Scanner: A Beginner's Guide