Assertion with Dynamic Repetition

SoC HL Architecture

Insert Element in a Dynamic Array

To perform the operations like insertion or deletion of elements, queue is the best option. But still, if required to perform such operations in a dynamic array then we can create a function as below.

module main();
  initial begin
    int a[];
    a = {0,1,2,3,4,5,6,7,8,9};
    // Insert value 'd10 at 5th location
  function automatic void dyn_insert(ref int b[],input int idx, val);
    int q[$] = b;
    b = q;

Link to EDA Playground:

Be careful while comparing real values!!

Recently I faced an issue regarding real values comparison using $floor command where cadence simulator was giving unpredictable result.

Please note, the $floor rounds down the real number to integer, while $ceil rounds up.


The $floor was returning wrong integer number after differentiating two real numbers. The values were,

  • $floor(32958.327 – 22988.3)
  • Expected output: 9970
  • Simulator output: 9969


  • Comparing / Operating 2 real numbers aren’t straight forward
  • From cadence support page: “Precision differences in floating point is a problem with digital computers. When the computer converts a decimal real number into a binary representation, the precision is lost. It happens in all computers. Because of these precision differences, you need to be careful when you test equality of two floating point numbers.”
  • There are 2 possible solutions to it:

Case 1: Fixed number of Fractional digits

  • In this case convert the real numbers to integer by multiplying with 10(num of fractional digits)
  • And perform any arithmetic operation

Case 2: Random number of fractional digits

  • In this case the system functions like $floor or $ceil are required to round down or up to integer
  • To solve this kind of rounding errors, we should add some tolerance while using these functions
  • The standard tolerance value is 1e-9
  • Floor command after tolerance gives expected result: $floor((32958.327 – 22988.3) + 1e-9) = 9970

Disabling Threads in SystemVerilog: Be careful while using it…!!!

Many times we need to disable the active threads spawned by the fork. But while disabling a fork, one should always be careful, as it can cause an unexpected behaviour. This article explains the unexpected behaviour of disabling a fork, using the different scenarios.

Here, We have two threads, executes parallelly using fork-join_any and our intention is to disable a fork after completion of Thread 1.

Example 1] Disable fork and Disable label with single object of a class

Let’s start with a simple example, where we have a fork-join_any inside a class, which executes two threads parallelly. As in below example 1, a fork is disabled once Thread 1 is completed. This example will produce the same output if we use “disable kill_me” instead of “disable fork” at line number 9, where “kill_me” is a label of the fork (see line number: 4), which we want to disable.

Disable fork Ex 1

For a single object of a class, “disable fork” and “disable label” works fine. But what if the class has multiple objects. Let’s see in the following examples (2 and 3).

Example 2] Disable fork with two objects of the class

Here, the code in example 1 is modified for the two objects of the class. In the class disable_fork, an additional variable “obj_id” is taken to identify that the main method inside the class is called using which object.

Disable fork Ex 2

By looking at the output on the above image, both the objects complete Thread 1 and then disable their “own” fork. What if we use “disable label” (here, a label is kill_me) instead of disable fork?

Example 3] Disable label with two objects of the class

Here, at line 15, the “disable fork” is replaced by “disable kill_me”.

Disable fork Ex 3

Oops, the “disable kill_me” of object 0 has also killed the fork of object 1. This is not the output we were expecting.

So, after looking at all the three examples, it seems that “disable fork” is safer than “disable label”. But “disable fork” is really safe in this context…..??? Let’s see Example 4.

Example 4] Disable fork with multiple forks in the same task

Here, we have added one more fork (join_none) in the main() task of the class. This new fork should not be disabled.

Disable fork Ex 4

But, when we use disable fork, then it disables all the forks in the current scope.

From examples 3 and 4,

  1. if we use “disable label”, then it is visible across all the objects of the same class, so it disables all the forks with the same label in the different objects.
  2. If we use “disable fork”, then it disables all the forks in the current scope.

This problem is resolved in example 5.

Example 5] Safest way to use the disable fork

Here, we have wrapped the fork “kill_me” inside another fork-join.

Disable fork Ex 5


Always use an additional fork to wrap-up all the forks, you want to diable. This is a safe way, as it limits the scope of a disable fork.

P.S.: Please follow the below link if you want to play with all these five examples 🙂


Why is always block not allowed in Program Block?

The program block came from the Vera verification language that was donated to SystemVerilog. In Vera, a program was a single procedure that represented the “test”. Your test was started at time 0 and when the test terminated, the program terminated the simulation. If you needed multiple test threads, you either had to use the fork statement to start it, or use multiple programs. When the last program terminated, the simulation terminated.

As part of the integration with SystemVerilog, the program was turned into a module-like construct with ports and initial blocks are now used to start the test procedure. Because an always block never terminates, it was kept out of the program block so the concept of test termination would still be there.

Today, most people do not utilize this termination feature because the OVM/UVM have their own test termination mechanisms. The program block is no longer a necessary feature of the language other than to help people converting over from Vera to SystemVerilog.

See my blog: Are Program Blocks Necessary?

Automatic Storage



Automatic Storage Output

Pass by Ref

Ref: System Verilog For Verification – Chris Spear, Greg TumBush

=> In SystemVerilog, you can specify that an argument is passed by reference, rather than copying its value. This argument type, ref, has several benefits over input, output, and inout.

1. Increased performance

=> you can pass an array into a routine, here one that prints the checksum.


=> SystemVerilog allows you to pass array arguments without the ref direction, but the array is copied onto the stack, this is an expensive operation.
=> Always use ref when passing arrays to a routine for best performance. If you don’t want the routine to change the array values, use the const ref type, which causes the compiler to check that your routine does not modify the array.

Note: The SystemVerilog LRM states that ref arguments can only be used in routines with automatic storage. If you specify the automatic attribute for programs and module, all the routines inside are automatic.

2. A task can modify a variable and is instantly seen by the calling function.


=> The data argument is passed as ref, and as a result, the @data statement triggers as soon as data changes in the task. If you had declared data as output, the @data statement would not trigger until the end of the bus transaction.

=> In other words, In exa 3.12, in initial block, the bus_read task and thread 2 are parallelly executed in fork-join loop. Thread 2 waits for a data change. In the bus_read task, data is changed inside a blue circle.

If data’s direction was not ref (it was not pass by ref), in that case, the bus_read task would be executed completely and after negedge of bus_grand, the thread 2 would get a changed value of data

But here data is passed by ref, so once data is assigned a value as in blue circle in bus_read task, at a time, thread 2 will get a changed value of data. It will not wait for completion of bus_read task.

Streaming Operators

Ref: System Verilog For Verification – Chris Spear, Greg TumBush

When used on the right side of an assignment, the streaming operators << and >> take an expression, structure, or array, and packs it into a stream of bits. The >>

The >> operator streams data from left to right while << streams from right to left, as shown in Sample 2.51.

You can also give a slice size, used to break up the source before being streamed. You can not assign the bit stream result directly to an unpacked array. Instead, use the streaming operators on the left side of an assignment to unpack the bit stream into an unpacked array.


You could do the same operations with many concatenation operators, {}, but the streaming operators are more compact and easier to read.

If you need to pack or unpack arrays, use the streaming operator to convert between arrays of different element sizes. For instance, you can convert an array of bytes to an array of words. You can use fixed size arrays, dynamic arrays, and queues.

Sample 2.52 converts between queues, but would also work with dynamic arrays. Array elements are automatically allocated as needed.


Note: A common mistake when streaming between arrays is mismatched array subscripts. The word subscript [ 256 ] in an array declaration is equivalent to [ 0:255 ], not [ 255:0 ]. Since many arrays are declared with the word subscripts [ high:low ], streaming them to an array with the subscript [ size ] would result in the elements ending up in reverse order. Likewise, streaming an unpacked array declared as bit [ 7:0 ] s rc[255:0] to the packed array declared as bit [ 7:0 ] [ 255:0 ]. Likewise, streaming an unpacked array declared as bit [ 7:0 ] s rc[255:0] to the packed array declared as bit [ 7:0 ] [ 255:0 ] dst will scramble the order of values. The correct declaration for a packed array of bytes is bit [255:0] [7:0] dst.

You can also use the streaming operator to pack and unpack structures, such as an ATM cell, into an array of bytes. In Sample 2.53 a structure is streamed into a dynamic array of bytes, then the byte array is streamed back into the structure.


How to choose a random element from the associative array?

To randomize elements for Fixed arrays, Queues, Dynamic Array and Associative Array:

$urandom_range($size(array) – 1);   or   $urandom_range(array.size() – 1);

For Associative array, it’s not easy to pick up a random element, as elements are stored in sparse manner.

We can use the below code to choose a random element in an associative array.

module main();
    int assoc_array[int] = '{0:100, 1:200, 5:300, 15:400, 50:500, 1000:600};   // Assign values 100,200,300,400,500 at index 0,1,5,15,50,1000, respectively

    int element_num, count, indx;

    initial begin
        element_num = $urandom_range(assoc_array.size()-1);
        $display("find %0d%0s element from total %0d elements",element_num,((element_num==1)? "st" :((element_num==2)? "nd":((element_num==3)? "rd":"th"))),assoc_array.size());
        foreach(assoc_array[i]) begin
            if(count++ == element_num) begin
                indx = i;
        count = 0;
        $display("The %0d%0s element is: %0d at index = %0d",element_num,((element_num==1)? "st":((element_num==2)? "nd":((element_num==3)? "rd":"th"))),assoc_array[indx],indx);


find 2nd element from total 6 elements

The 2nd element is: 300 at index = 5

find 0th element from total 6 elements

The 0th element is: 100 at index = 0