Generate UVM Test Bench from Simulink

This example shows how you can develop a design and test bench in Simulink and generate an equivalent simulation for a Universal Verification Methodology (UVM) environment using uvmbuild. It shows how you can substitute pieces of the generated UVM environment with an RTL design under test (DUT) using AXI protocol interfaces and hand-written driver and monitor components.

Introduction

This example walks you through a top-down design development process of an HDL implementation. In such a workflow, you design a behavioral algorithm in Simulink and test it using surrounding blocks for stimulus generation and results checking. Once the simulation confirms that the design meets its requirements, you deliver any collateral needed to the downstream HDL implementation team. You need to re-verify the HDL implementation meets the requirements as simulated in Simulink as well as any other unique aspects of the design such as protocol interfaces that were not modeled in Simulink.

Ordinarily the hand-off process can be tedious and the source of many errors. The HDL implementation and HDL Design Verification (DV) engineers must:

  • Translate written specifications to HDL and testing environments.

  • Understand the run-time behavior of the Simulink simulation environment such as how the stimulus is created, processed, and checked.

  • Translate the run-time behaviors to SystemVerilog implementations.

  • Integrate the stimulus, design, and response checking into a runnable SystemVerilog to confirm that the translated behaviors behave the same as the original Simulink simulation.

  • Integrate these main SystemVerilog components into a UVM context in order to allow extending the Simulink testing with DV-authored verification. This extended testing might include randomized testing, SystemVerilog assertions, functional coverage, and code coverage.

Using the HDL Verifier UVM generation capabilities, this hand-off process is automated. The DV engineer gets a verified UVM test environment that matches the testing performed in Simulink and can easily update that environment to meet their downstream verification needs.

Setup

Copy the example files to a writeable working directory. With no argument it will create a directory in the system temporary directory. Specify any relative or absolute path. A directory will be created if the specified directory doesn't exist.

hdlv_copyfiles('hdlv_uvmtb', 'workingDir', '.')
Copied example files for 'hdlv_uvmtb' to '.'.

Design and Test in Simulink

Write your algorithm and add a test bench to it. The model consists of typical subsystems for a test bench such as stimulus generation, the design under test (DUT), and response checking.

In this design, the source subsystem creates a random pulse of 64 samples of information embedded at a random location in a 5000 sample frame of noise. It also generates a set of 64 optimal matched filter coefficients for detection of the pulse. The inputs are fed to both the design and the response checker. The response checker verifies that the pulse is detected at the right location in the noisy waveform. Proper operation is confirmed through console output. If the expected power of the detected signal is not within certain limits, an assertion is fired.

model = 'hdlv_uvmtb';
open_system(model);

Simulating the model provides confirmation that in five generated pulses, five are detected. A three paneled figure shows a Tx Signal (the original pulse), an Rx Signal (the pulse embedded in noise), and the filtered output of a reference implementation that shows where a peak is detected. The output signal is delayed by one frame.

sim(model);
[time=1.000000] Peak location=4404.000000, mag-squared=0.059 using global max
[time=1.000000] Peak detected from impl=4412 error(abs)=8
[time=1.000000] Peak mag-squared from impl=0.059, error(abs)=0.000 error(pct)=0.002

[time=2.000000] Peak location=1377.000000, mag-squared=0.042 using global max
[time=2.000000] Peak detected from impl=1385 error(abs)=8
[time=2.000000] Peak mag-squared from impl=0.042, error(abs)=0.000 error(pct)=0.002

[time=3.000000] Peak location=1010.000000, mag-squared=0.060 using global max
[time=3.000000] Peak detected from impl=1018 error(abs)=8
[time=3.000000] Peak mag-squared from impl=0.060, error(abs)=0.000 error(pct)=0.002

[time=4.000000] Peak location=2832.000000, mag-squared=0.071 using global max
[time=4.000000] Peak detected from impl=2840 error(abs)=8
[time=4.000000] Peak mag-squared from impl=0.070, error(abs)=0.000 error(pct)=0.001

[time=5.000000] Peak location=3538.000000, mag-squared=0.052 using global max
[time=5.000000] Peak detected from impl=3546 error(abs)=8
[time=5.000000] Peak mag-squared from impl=0.051, error(abs)=0.000 error(pct)=0.002

Generate an Executable UVM Test Bench

Use the uvmbuild function to export your design to a UVM environment. The UVM test bench provides structure to the HDL verification process and allows for all of the Simulink test bench components and test cases to be reused by the implementation verification team. Standard component definitions separate the pieces of the environment by their role in the simulation. For this example:

  • PulseDetector is mapped to the DUT SystemVerilog module

  • GenPulse subsystem is mapped to the sequence_item creation for the Sequencer UVM component

  • CheckDetection subsystem is mapped to the Scoreboard UVM component.

The generated UVM test bench is shown below:

design     = 'hdlv_uvmtb/PulseDetector';
sequence   = 'hdlv_uvmtb/GenPulse';
scoreboard = 'hdlv_uvmtb/CheckDetection';
uvmbuild(design, sequence, scoreboard);

Each of the highlighted pieces of the UVM test bench are implemented by wrapping generated C-code from the Simulink subsystem and calling its entry points using DPI. The following image shows a couple of the function declarations for the PulseDetector subsystem.

The SystemVerilog/UVM code determines the timing of the DPI calls. For example, in the PulseDetector SystemVerilog module:

  • The "initialize" DPI call is triggered by an "initial" code block.

  • The "terminate" DPI call is triggered by a "final" code block.

  • The "reset" DPI call is triggered by an active reset signal.

  • The "output" and "update" DPI calls are triggered by a rising clock edge where reset is not active and the clock enable is active.

Run the UVM Test Bench

The uvmbuild process also generates a script to run a simulation of the UVM test. Scripts are generated for the following simulators:

  • Mentor Graphics® Modelsim® and Questa®: run_tb_mq.do

  • Cadence® Xcelium™: run_tb_incisive.sh

  • Synopsys® VCS®: run_tb_vcs.sh

The generated script for ModelSim is shown.

Execute the generated script to verify the UVM execution matches the Simulink execution. For example, in a system shell:

cd hdlv_uvmtb_uvmbuild/uvm_testbench/top
vsim -do run_tb_mq.do
cd ../../..

The simulation log shows the same diagnostic messages:

And the waveform shows the timing of the DUT interface signals. The cursor is placed at a frame boundary and shows the instantaneous update of the matched filter coefficients.

Integrate an AXI-Based RTL Design

The DUT in Simulink represents the functional behavior of the pulse detector and does not use any hardware protocol interfaces that are typical of HDL IP cores. The UVM test bench uses the Simulink design as a stand-in for the actual HDL implementation. The next step in the verification workflow integrates an actual HDL implementation that uses AXI-based protocols into the same generated UVM test bench.

To use an RTL DUT you must substitute pieces of the UVM test bench, as shown in blue:

For this RTL DUT, the coeff port is mapped to a processor interface, AXI4-Lite, the data_in port is mapped to an AXI4-Stream slave interface, and the data_out port is mapped to an AXI4-Stream master interface as shown below.

You can manually write this RTL or use HDL Coder's IP core generation workflow to create it.

An example AXI-based RTL implementation is located in top_AXIDUT/AXIIPSource.

The UVM files to replace the original DUT are located in top_AXIDUT. There is no need to modify any of the generated files from the uvmbuild invocation.

Execute the script for the new UVM environment in a system shell, for example for Questasim:

cd top_AXIDUT
vsim -do run_tb_mq.do

The simulation log and a waveform snippet are shown below. Notice the log shows the same results as before, 5 detected pulses. However, also notice the waveforms show different timing for exercising the design. Instead of a steady stream of always valid data, for each frame of 5000 signal samples, the 64 coefficients are first programmed via the processor interface, then the 5000 samples are streamed.

Conclusion and Next Steps

This example has shown how a design and test bench developed in Simulink can be used to generate a fully executable UVM test bench. The uvmbuild command automates the generation, compilation, and integration of key components into the UVM framework.

HDL verification engineers can confirm overall coverage from Simulink and augment the coverage with their own library of native UVM sequences.

They can also substitute a behavioral design from Simulink with an RTL design that is wrapped in hardware protocols such as AXI4 with no changes to the original sequence generator and response checkers.