UVVM Assertions

A simple and powerful way to integrate assertions into your UVVM testbenches.

In the newest UVVM release, we now offer UVVM Assertions as a powerful way to add concurrent verification next to the sequencer in your testbenches, still within the familiar UVVM syntax.

UVVM already provides a wide range of checks, BFMs, and VIPs to verify your design. Until now, if you wanted to assert a given signal property, you would have to: Write a native VHDL assertion; Use UVVM utility library, and write your own processes; or use other assertion tools such as OVL, PSL, SVA, or others.

There might be several reasons to use assertions to check a signal property or a bus behavior in your design, be it:

  •  a value that the signal should never be
  • some condition that should always occur
  • some sequence that should always occur when a given signal goes high.

 

Running a concurrent assertion allows you to verify that this holds during all the other checks the sequencer performs.  

One downside of using native VHDL assertions, or other assertion libraries, is that they will not easily show up in the UVVM alert and logging verbosity system, allowing you to get a clear overview of any assertions that failed, both while simulating and in the final summary of all alerts at the end of the sequencer:

The other added benefit of the new UVVM Assertions is the option to use more advanced assertions without learning a new assertion syntax/language, as well as not limiting usage to a given simulator due to licensing. The most basic assertions will work the same as a native VHDL assertion, and you may build a complex assertion around that one. You are also presented with some assertions that we think would cover the most useful cases.

The code outlined below is the code producing the log example above. As can be seen, although both the native VHDL assertion and the UVVM Assertion cover the same signal property, we will get a cleaner log of the UVVM Assertions within the UVVM framework. The UVVM Assertions available can be used for several different assertion cases with minor modifications, as seen here with an intermediate signal.

 

				
					architecture demo_arch of demo_tb is
    ...
    -- DUT signals
    signal count          : std_logic_vector(7 downto 0);
    -- assertion signal to hold the result of the comparison
    signal count_is_13    : boolean;
begin
    -- Instantiate DUT which should always skip number 13
    i_dut_1 : entity work.dummy_counter
        port map(
        clk       => clk,
        rst       => '0',
        count     => count
        );

    -- UVVM assertion: count should never be 13
    count_is_13 <= (count = std_logic_vector(to_unsigned(13, 8)));
    assert_value(clk, assert_value_ena, count_is_13, false, "Count should never be 13");

    -- Native VHDL assertion variant of the same assertion:
    assert count /= std_logic_vector(to_unsigned(13, 8)) report "Count should never be 13" severity Error;

    p_main : process
    begin
        ...
    end process;
end architecture demo_arch;

				
			

Figure 1: A basic assertion of count /= 13 both in native VHDL and using UVVM Assertions

Let’s look at the more complex case  of asserting an AXI stream master module. In this scenario, you want to make sure the data transmitted is always between 8 and 32 bytes, and so you specify that `tlast` should always come between 8-32 cycles after `tvalid` goes high.

Using one of the more advanced UVVM window assertions, we can check this property using the `assert_change_to_value_from_min_to_max_cycles_after_trigger` assertion. This window assertion allows us to put in a concurrent check that `tlast` will always come 8 to 32 clock cycles (data bytes) after `tvalid` goes high (using rising edge as a trigger). The code for this will look like (placed in a bare bones example testbench):

				
					architecture demo_arch of demo_axi_stream_tb is
    signal tvalid_rise : std_logic := '0';
begin
    -- DUT
    i_axistream_master_DUT : entity work.axistream_master
        port map(
        clk              => clk,
        axistream_if     => axistream_if_m
        );

    -----------------------------
    -- vvc/executors
    -----------------------------
    -- slave vvc that receive from FIFO
    i_axistream_vvc_slave_FIFO2VVC : entity bitvis_vip_axistream.axistream_vvc
        generic map(
        GC_VVC_IS_MASTER => false,
        ....
        )
        port map(
        clk              => clk,
        axistream_vvc_if => axistream_if_s
        );

    -- to only start the assertion check when tvalid goes high, we add a rising edge detection
    p_tvalid_rise : process(clk)
        variable vr_tvalid_d1 : std_logic := '0';
    begin
        if rising_edge(clk) then
            tvalid_rise  <= axistream_if_m.tvalid and not vr_tvalid_d1;
            vr_tvalid_d1 := axistream_if_m.tvalid;
        end if;
    end process p_tvalid_rise;

    assert_change_to_value_from_min_to_max_cycles_after_trigger(
        clk            => clk,
        ena            => assertion_ena,
        tracked_value  => axistream_if_m.tlast,
        exp_value      => '1',
        trigger        => tvalid_rise,
        min_cycles     => 8,
        max_cycles     => 32,
        msg            => "tlast did not go high within 8-32 cycles after tvalid went high",
        severity       => ERROR
    )

    p_main : process
    begin
        -- Testbench sequencer
    end process;
end architecture demo_arch;

				
			

Figure 2: A more advance usage of UVVM Assertions, verifying that tlast comes 8-32 cycles after tvalid goes high.

As you can see in the example code, the UVVM Assertion keeps the abstraction  of the assertion high, while still giving us room to control enabling/disabling of the configuration, as is common in a process containing native VHDL assertions. We have chosen longer descriptive names for the more complex assertions, since they would commonly only be instantiated once, as opposed to UVVM utility checkers, which will often be called many times in the sequencer.

We hope that by using UVVM, you will make your verification more readable, easier to maintain, and easier to modify when needed. The goal of introducing UVVM Assertions as part of UVVM was to add one-line assertions that can be run concurrently while you execute a normal sequential verification. We have opted to be inspired by Accelleras’ OVL list of assertions, and if you are already using OVL, the UVVM Assertions wiki includes comparative assertions that cover the same properties. We hope you will find the use for and try out UVVM Assertions in your next verification setup! Don’t hesitate to reach out to us if you have any issues or need guidance on using UVVM.

More FPGA Posts