Assertions

This is not a complete guide!
This is just here to give some glimpses at some of the capabilities of assertions, particularly for verification of designs in SystemVerilog.

Assertions are run-time checks for errors which appear in many variations in different language environments. In one way assertions can be coded with existing tools but nowadays there is sometimes better support within the language environment.

As a rough classification, consider a software example where an index might put an array reference outside the array.

Assertions should be able to raise the confidence that code works without needing to impact the final performance.


Verilog & SystemVerilog

In hardware terms we are primarily concerned with verification – finding faults before implementing and deploying the device. This is where assertions can provide a significant confidence boost.

This is an overview of the SystemVerilog facilities. It is here to give a starting point; refer ro something more definitive for fuller details.
(The description in the standard is 118 pp.)

Some associated keywords are:

There are two types of SystemVerilog assertions: Immediate Assertions and Concurrent Assertions.


Immediate assertions

Immediate assertions are fairly straightforward: they are ‘immediate’ in the sense that they are not dependent on time. They can be used for things like checking values or signal combinations.

In Verilog

always @ (aa, bb)
  if (aa && bb)           // Nothing
    $display("Signals aa and bb clashed");

With SystemVerilog assertion

always @ (aa, bb)
  assert (!(aa && bb))
    else $error("Signals aa and bb clashed");

If the else is omitted the tool will call $error by default, although with less information.

Note that the assert can have an action before the else which is executed each time the assertion is satisfied. An example function would be counting the number of times this has happened.
It's also possible (and sensible!) to give the assertion a name so it can be identified in a wave trace.

Example


always @ (aa, bb)
ab_check: assert ((aa && bb) != 1) ab_pass++;    // Count sucesses
else begin
     ab_fail++;                                  // Count failures
     $warning("ab fail at %t.", $time);
     end

always @ (*)
cc_moved: assert (cc == 0) else $info("cc went high!");

Traces illustrating
          immediate assertions

(Click to enlarge figure.)

 

    Log report

    …
    ab fail at           120000.
    ab fail at           140000.
    cc went high!
    …

The system tasks $info, $warning, $error and $fatal are all ‘print’ outputs, intended for increasing severities of concern.

An assert is a statement, like any other, and needs to be told when to execute: the example above is sensitive to changes in aa and bb so it will be active throughout a simulation run. However a simulation may be halted on the occurence of a failed exception of sufficient ‘severity’ such as an $error but not a $warning.

assume is similar to assert in simulation but has added properties for formal verification.


Concurrent assertions

Immediate assertions happen when they are triggered by an event, such as a signal change. Concurrent assertions check behaviour repetitively, across time, using sampled values. As such they require some sort of timing reference – i.e. a clock. This will often be a/the system clock (but need not be) but should provide some sort of countable cycles.

As might be expected, there is considerable associated syntax which can provide an extensive range of facilities. Let's start with a simple, illustrative example, requiring only a few new functions.


example: assert property(@ (posedge clk)
  disable iff (reset)
    req |-> ##1 ack)
    else $error("Check failed");

(There is an alternative syntax because – being Verilog – of course there is!)

This therefore asserts that, as long as we are not being reset, if req is active at one clock edge ack is expected to active at the next. This is illustrated in the trace below.

Traces illustrating
		concurrent assertions

Some more syntax

There is a plethora of accompanying ‘new’ syntax: here are some more salient items.

The |-> implication starts timing (counting) in the cycle(s) the implication is true. There is also a |=> implication which starts one cycle later.   “|=> ##n“ ≡ “|-> ##(n+1)

The delay operator (“##n“) can also specify time ranges: “##[m:n]“.

You can have sequences on either side of implication operator, thus:
req ##1 grant |-> ack ##1 !ack

System tasks “$stable()“, “$rose()“ and “$fell()“ allow changes in signal states to be detected whilst a concurrent assertion is active. BEWARE! Such changes are detected by comparing samples at the chosen sample clock: they are not specified to spot a short glitch if it occurs entirely between two samples.
The system task “$past()“, allows expression from previous samples.

What else is worth including here?
(Work in progress!)


Back to general SystemVerilog

Up to Verilog index