Module 79 min

Assertions

Rules the design must never break, checked automatically

An assertion is a rule you write down that must always hold true. The simulator watches it every cycle and complains the instant it is violated - even if your testbench was looking somewhere else. Assertions are like tripwires placed throughout the design.

Two kinds

TypeWhen checkedExample rule
ImmediateRight now, inside procedural code"At this point, count must not be zero"
ConcurrentContinuously, against the clock"Whenever request rises, grant must follow within 3 cycles"

An immediate assertion

systemverilog
// Check a condition at this moment
assert (fifo_count <= FIFO_DEPTH)
  else $error("FIFO overflow: count = %0d", fifo_count);

A concurrent assertion - rules over time

This is the powerful one. It expresses behavior across clock cycles in a compact line. Read the example as a sentence.

systemverilog
// "Every time req goes high, ack must be high
//  within the next 1 to 3 clock cycles."
property req_gets_ack;
  @(posedge clk) req |-> ##[1:3] ack;
endproperty

assert property (req_gets_ack)
  else $error("req was not acknowledged in time");
  • @(posedge clk) - check on each clock edge.
  • req |-> ... - "if req is true, then the rest must follow."
  • ##[1:3] ack - ack must be true somewhere 1 to 3 cycles later.
Pro tip

Assertions are documentation that checks itself. Writing "req must be acked within 3 cycles" as an assertion captures a spec rule AND enforces it on every test, forever. They often catch the bug at the exact cycle and signal where it happened, instead of as a wrong value a thousand cycles downstream.

Watch out

Keep assertions in their own place (bound to the design or in the interface), not scattered through RTL. And assert the intent from the specification, not a restatement of the code - an assertion that just repeats the implementation only tells you the code equals itself, which proves nothing.