Default timescale
Although Verilog modules are expected to have a timescale defined before the module, simulators may insert a default timescale. The actual timescale that gets applied at any scope in a Verilog elaborated hierarchy can be printed using the system task $printtimescale
which accepts the scope as an argument.
module tb;
initial begin
// Print timescale of this module
$printtimescale(tb);
// $printtimescale($root);
end
endmodule
Verilog delay statements can have delays specified either on the left hand side or the right hand side of the assignment operator.
Inter-assignment Delays
// Delay is specified on the left side
#<delay> <LHS> = <RHS>
An inter-assignment delay statement has delay value on the LHS of the assignment operator. This indicates that the statement itself is executed after the delay expires, and is the most commonly using form of delay control.
Until now in previous articles, simple boolean expressions were checked on every clock edge. But sequential checks take several clock cycles to complete and the time delay is specified by ##
sign.
## Operator
If a is not high on any given clock cycle, the sequence starts and fails on the same cycle. However, if a is high on any clock, the assertion starts and succeeds if b is high 2 clocks later. It fails if b is low 2 clocks later.
A sequence
is a simple building block in SystemVerilog assertions that can represent certain expressions to aid in creating more complex properties.
Simple Sequence
module tb;
bit a;
bit clk;
// This sequence states that a should be high on every posedge clk
sequence s_a;
@(posedge clk) a;
endsequence
// When the above sequence is asserted, the assertion fails if 'a'
// is found to be not high on any posedge clk
assert property(s_a);
always #10 clk = ~clk;
initial begin
for (int i = 0; i < 10; i++) begin
a = $random;
@(posedge clk);
// Assertion is evaluated in the preponed region and
// use $display to see the value of 'a' in that region
$display("[%0t] a=%0d", $time, a);
end
#20 $finish;
end
endmodule

Time (ns) | a | Result |
---|---|---|
10 | 0 | FAIL |
30 | 1 | PASS |
50 | 1 | PASS |
70 | 1 | PASS |
90 | 1 | PASS |
110 | 1 | PASS |
130 | 1 | PASS |
150 | 0 | FAIL |
170 | 1 | PASS |
190 | 1 | PASS |
Compiler version P-2019.06-1; Runtime version P-2019.06-1; Jan 14 06:32 2020 [10] a=0 "testbench.sv", 12: tb.unnamed$$_0: started at 10ns failed at 10ns Offending 'a' [30] a=1 [50] a=1 [70] a=1 [90] a=1 [110] a=1 [130] a=1 [150] a=0 "testbench.sv", 12: tb.unnamed$$_0: started at 150ns failed at 150ns Offending 'a' [170] a=1 [190] a=1 $finish called from file "testbench.sv", line 27. $finish at simulation time 210 V C S S i m u l a t i o n R e p o r t Time: 210 ns
$rose
The system task $rose
is used to detect a positive edge of the given signal. In this case $rose
of a indicates that a posedge of a is expected to be seen on every posedge of clk . Because SystemVerilog assertions evaluate in the preponed region, it can only detect value of the given signal in the preponed region. When value of the signal is 0 in the first edge and then 1 on the next edge, a positive edge is assumed to have happened. So, this requires 2 clocks to be identified.
module tb;
bit a;
bit clk;
// This sequence states that 'a' should rise on every posedge clk
sequence s_a;
@(posedge clk) $rose(a);
endsequence
// When the above sequence is asserted, the assertion fails if
// posedge 'a' is not found on every posedge clk
assert property(s_a);
// Rest of the testbench stimulus
endmodule
See that a positive edge was detected and the assertion passed at 30ns in the image shown below. This is because value of a is 0 at 10ns and 1 at 30ns upon which the assertion completes and is proven to be successful.

Time (ns) | a | Transition | Result |
---|---|---|---|
10 | 0 | FAIL | |
30 | 1 | 0->1 | PASS |
50 | 1 | FAIL | |
70 | 1 | FAIL | |
90 | 1 | FAIL | |
110 | 1 | FAIL | |
130 | 1 | FAIL | |
150 | 0 | 1->0 | FAIL |
170 | 1 | 0->1 | PASS |
190 | 1 | FAIL |
The behavior is visible in the simulation log where assertion failed at all times other than 30ns and 170ns.
Compiler version P-2019.06-1; Runtime version P-2019.06-1; Jan 14 06:58 2020 [10] a=0 "testbench.sv", 12: tb.unnamed$$_0: started at 10ns failed at 10ns Offending '$rose(a)' [30] a=1 [50] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 50ns failed at 50ns Offending '$rose(a)' [70] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 70ns failed at 70ns Offending '$rose(a)' [90] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 90ns failed at 90ns Offending '$rose(a)' [110] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 110ns failed at 110ns Offending '$rose(a)' [130] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 130ns failed at 130ns Offending '$rose(a)' [150] a=0 "testbench.sv", 12: tb.unnamed$$_0: started at 150ns failed at 150ns Offending '$rose(a)' [170] a=1 [190] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 190ns failed at 190ns Offending '$rose(a)' $finish called from file "testbench.sv", line 27. $finish at simulation time 210 V C S S i m u l a t i o n R e p o r t Time: 210 ns
$fell
The system task $fell
is used to detect negative edge of the given signal. In this case $fell
of a indicates that a negedge of a is expected to be seen on every posedge of clk . Because SystemVerilog assertions evaluate in the preponed region, it can only detect value of the given signal in the preponed region. When value of the signal is 1 on the first edge and then 0 on the next edge, a negative edge is assumed to have happened. So, this requires 2 clocks to be identified.
module tb;
bit a;
bit clk;
// This sequence states that 'a' should fall on every posedge clk
sequence s_a;
@(posedge clk) $fell(a);
endsequence
// When the above sequence is asserted, the assertion fails if
// negedge 'a' is not found on every posedge clk
assert property(s_a);
// Rest of the testbench stimulus
endmodule
See that a negative edge was detected and the assertion passed at 1500ns in the image shown below. This is because value of a is 1 at 130ns and 0 at 150ns upon which the assertion completes and is proven to be successful.

Time (ns) | a | Transition | Result |
---|---|---|---|
10 | 0 | FAIL | |
30 | 1 | 0->1 | FAIL |
50 | 1 | FAIL | |
70 | 1 | FAIL | |
90 | 1 | FAIL | |
110 | 1 | FAIL | |
130 | 1 | FAIL | |
150 | 0 | 1->0 | PASS |
170 | 1 | 0->1 | FAIL |
190 | 1 | FAIL |
Compiler version P-2019.06-1; Runtime version P-2019.06-1; Jan 14 07:09 2020 [10] a=0 "testbench.sv", 12: tb.unnamed$$_0: started at 10ns failed at 10ns Offending '$fell(a)' [30] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 30ns failed at 30ns Offending '$fell(a)' [50] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 50ns failed at 50ns Offending '$fell(a)' [70] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 70ns failed at 70ns Offending '$fell(a)' [90] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 90ns failed at 90ns Offending '$fell(a)' [110] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 110ns failed at 110ns Offending '$fell(a)' [130] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 130ns failed at 130ns Offending '$fell(a)' [150] a=0 [170] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 170ns failed at 170ns Offending '$fell(a)' [190] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 190ns failed at 190ns Offending '$fell(a)' $finish called from file "testbench.sv", line 27. $finish at simulation time 210 V C S S i m u l a t i o n R e p o r t Time: 210 ns
$stable
module tb;
bit a;
bit clk;
// This sequence states that 'a' should be stable on every clock
// and should not have posedge/negedge at any posedge clk
sequence s_a;
@(posedge clk) $stable(a);
endsequence
// When the above sequence is asserted, the assertion fails if
// 'a' toggles at any posedge clk
assert property(s_a);
// Rest of the testbench stimulus
endmodule

Time (ns) | a | Transition | Result |
---|---|---|---|
10 | 0 | FAIL | |
30 | 1 | 0->1 | FAIL |
50 | 1 | PASS | |
70 | 1 | PASS | |
90 | 1 | PASS | |
110 | 1 | PASS | |
130 | 1 | PASS | |
150 | 0 | 1->0 | FAIL |
170 | 1 | 0->1 | FAIL |
190 | 1 | PASS |
Compiler version P-2019.06-1; Runtime version P-2019.06-1; Jan 14 07:12 2020 [10] a=0 [30] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 30ns failed at 30ns Offending '$stable(a)' [50] a=1 [70] a=1 [90] a=1 [110] a=1 [130] a=1 [150] a=0 "testbench.sv", 12: tb.unnamed$$_0: started at 150ns failed at 150ns Offending '$stable(a)' [170] a=1 "testbench.sv", 12: tb.unnamed$$_0: started at 170ns failed at 170ns Offending '$stable(a)' [190] a=1 $finish called from file "testbench.sv", line 27. $finish at simulation time 210 V C S S i m u l a t i o n R e p o r t Time: 210 ns
The behavior of a system can be written as an assertion that should be true at all times. Hence assertions are used to validate the behavior of a system defined as properties, and can also be used in functional coverage.
What are properties of a design ?
If a property of the design that is being checked for by an assertion does not behave in the expected way, the assertion fails. For example, assume the design requests for grant and expects to receive an ack within the next four cycles. But if the design gets an ack on the fifth cycle, the property that an ack should be returned within 4 clocks is violated and the assertion fails.
If a property of the design that is being checked for by an assertion is forbidden from happening, the assertion fails. For example, assume a small processor decodes instructions read from memory, encounters an unknown instruction and results in a fatal error. If such a scenario is never expected from the design, the property of the design that only valid instructions can be read from memory is violated and the assertion fails.
As evident from the two examples above, properties of a given design is checked for by writing SystemVerilog assertions.
Why do we need assertions ?
An assertion is nothing but a more concise representation of a functional checker. The functionality represented by an assertion can also be written as a SystemVerilog task or checker that involves more line of code. Some disadvantages of doing so are listed below:
- SystemVerilog is verbose and difficult to maintain and scale code with the number of properties
- Being a procedural language, it is difficult to write checkers that involve many parallel events in the same period of time
// A property written in Verilog/SystemVerilog
always @ (posedge clk) begin
if (!(a && b))
$display ("Assertion failed");
end
SystemVerilog Assertions is a declarative language used to specify temporal conditions, and is very concise and easier to maintain.
// The property above written in SystemVerilog Assertions syntax
assert property(@(posedge clk) a && b);
Types of Assertion Statements
An assertion statement can be of the following types:
Type | Description |
---|---|
assert | To specify that the given property of the design is true in simulation |
assume | To specify that the given property is an assumption and used by formal tools to generate input stimulus |
cover | To evaluate the property for functional coverage |
restrict | To specify the property as a constraint on formal verification computations and is ignored by simulators |
Building Blocks of Assertions
Sequence
A sequence of multiple logical events typically form the functionality of any design. These events may span across multiple clocks or exist for just a single clock cycle. To keep things simple, smaller events can be depicted using simple assertions which can then be used to build more complex behavior patterns.
// Sequence syntax
sequence <name_of_sequence>
<test expression>
endsequence
// Assert the sequence
assert property (<name_of_sequence>);
Property
These events can be represented as a sequence
and a number of sequences can be combined to create more complex sequences or properties.
It is necessary to include a clocking event inside a sequence
or property
in order to assert it.
// Property syntax
property <name_of_property>
<test expression> or
<sequence expressions>
endproperty
// Assert the property
assert property (<name_of_property>);
There are two kinds of assertions - Immediate and Concurrent.
Immediate Assertion
Immediate assertions are executed like a statement in a procedural block and follow simulation event semantics. These are used to verify an immediate property during simulation.
always @ (<some_event>) begin
...
// This is an immediate assertion executed only
// at this point in the execution flow
$assert(!fifo_empty); // Assert that fifo is not empty at this point
...
end
Click here to learn more on Immediate Assertions
Concurrent Assertions
Concurrent assertions are based on clock semantics and use sampled values of their expressions. Circuit behavior is described using SystemVerilog properties that gets evaluated everytime on the given clock and a failure in simulation indicates that the described functional behavior got violated.
// Define a property to specify that an ack should be
// returned for every grant within 1:4 clocks
property p_ack;
@(posedge clk) gnt ##[1:4] ack;
endproperty
assert property(p_ack); // Assert the given property is true always
Click here to learn more on Concurrent Assertions
Steps to create assertions
Following are the steps to create assertions:
- Step 1: Create boolean expressions
- Step 2: Create sequence expressions
- Step 3: Create property
- Step 4: Assert property
Example
The first sequence s_ab validates that b is high the next clock when a is high, and the second sequence s_cd validates that d is high 2 clocks after c is found high. The property
asserts that the second sequence is on the next cycle after the first sequence.
module tb;
bit a, b, c, d;
bit clk;
always #10 clk = ~clk;
initial begin
for (int i = 0; i < 20; i++) begin
{a, b, c, d} = $random;
$display("%0t a=%0d b=%0d c=%0d d=%0d", $time, a, b, c, d);
@(posedge clk);
end
#10 $finish;
end
sequence s_ab;
a ##1 b;
endsequence
sequence s_cd;
c ##2 d;
endsequence
property p_expr;
@(posedge clk) s_ab ##1 s_cd;
endproperty
assert property (p_expr);
endmodule
Note that there are some violations for the property that is asserted using assert
statement.
Compiler version P-2019.06-1; Runtime version P-2019.06-1; Jan 8 05:02 2020 Warning : License for product VCSRuntime_Net(725) will expire within 10 days, on: 17-jan-2020. If you would like to temporarily disable this message, set the VCS_LIC_EXPIRE_WARNING environment variable to the number of days before expiration that you want this message to start (the minimum is 0). 0 a=0 b=1 c=0 d=0 10 a=0 b=0 c=0 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 10ns failed at 10ns Offending 'a' 30 a=1 b=0 c=0 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 30ns failed at 30ns Offending 'a' 50 a=0 b=0 c=1 d=1 70 a=1 b=1 c=0 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 70ns failed at 70ns Offending 'a' "testbench.sv", 28: tb.unnamed$$_3: started at 50ns failed at 70ns Offending 'b' 90 a=1 b=1 c=0 d=1 110 a=0 b=1 c=0 d=1 130 a=0 b=0 c=1 d=0 "testbench.sv", 28: tb.unnamed$$_3: started at 130ns failed at 130ns Offending 'a' "testbench.sv", 28: tb.unnamed$$_3: started at 90ns failed at 130ns Offending 'c' 150 a=0 b=0 c=0 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 150ns failed at 150ns Offending 'a' 170 a=1 b=1 c=0 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 170ns failed at 170ns Offending 'a' 190 a=0 b=1 c=1 d=0 210 a=1 b=1 c=0 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 210ns failed at 210ns Offending 'a' 230 a=1 b=1 c=0 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 190ns failed at 230ns Offending 'c' 250 a=1 b=1 c=0 d=0 270 a=1 b=0 c=0 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 230ns failed at 270ns Offending 'c' 290 a=0 b=1 c=1 d=0 "testbench.sv", 28: tb.unnamed$$_3: started at 270ns failed at 290ns Offending 'b' "testbench.sv", 28: tb.unnamed$$_3: started at 250ns failed at 290ns Offending 'c' 310 a=0 b=1 c=0 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 310ns failed at 310ns Offending 'a' 330 a=1 b=0 c=1 d=0 "testbench.sv", 28: tb.unnamed$$_3: started at 330ns failed at 330ns Offending 'a' "testbench.sv", 28: tb.unnamed$$_3: started at 290ns failed at 330ns Offending 'c' 350 a=0 b=1 c=0 d=1 370 a=0 b=1 c=1 d=1 "testbench.sv", 28: tb.unnamed$$_3: started at 370ns failed at 370ns Offending 'a' "testbench.sv", 28: tb.unnamed$$_3: started at 390ns failed at 390ns Offending 'a' $finish called from file "testbench.sv", line 13. $finish at simulation time 400 V C S S i m u l a t i o n R e p o r t