Misc Constructs

1.Program Block#

The module is the basic building block in Verilog which works well for Design. However, for the testbench, a lot of effort is spent getting the environment properly initialized and synchronized, avoiding races between the design and the testbench, automating the generation of input stimuli, and reusing existing models and other infrastructure. System Verilog adds a new type of block called program block. It is declared using the program and endprogram keywords.

syntax:
program program_name(port_list);
initial begin
.....
end
endprogram

All items defined inside the program block will be performed in the reactive region because of the race-free interaction provided by the program construct. Initial blocks within program blocks are planned in the Reactive region, while non-blocking assignments within the module are scheduled in the Active region and assign value in NBA Region .

This Re-Active Region set consists of :

image

Statements within program blocks that depend on changes in design signals are scheduled in the reactive region. By scheduling the active region before the reactive region, the race condition between the testbench and the design is avoided. -> It does not allow always block. Only initial and methods are allowed, which are more controllable.
-> Each program can be explicitly exited by calling the $exit system task. Unlike $finish, which exits the simulation immediately, even if there are pending events.
-> Just like a module, program block has ports. One or more program blocks can be instantiated in a top-level netlist, and connected to the DUT.

The following example demonstrates the difference between the module-based testbench and the program-based testbench.

code snippet:

module DUT();
  reg a = 0;
  initial begin
    a<= 1;
  end
endmodule

module TB_using_Module();
  initial begin
    $display("Module_based_TB : a = %b\n", DUT.a);
  end
endmodule

program TB_using_Program();
  initial begin
    $display("Program_based_TB : a = %b\n", DUT.a);
  end
endprogram

output:

program

If we observe that in the module it gives a value of 0, but in the program block, the value of a is 1 . Because it’s already assigned a value of ‘a’ in the active region.’

2.Dynamic Casting#

SystemVerilog casting means the conversion of one data type to another datatype.

It has two types
i.static casting
ii.Dynamic casting

Static casting is not applicable to OOP so we go for Dynamic casting for OOPs. It is done while run time.

Using $cast keyword we can achieve dynamic casting. This $cast can be a function or a task.

Syntax:

$cast(destination,source);

code snippet:

class hyd;
  string a;
  int d=8;
  function display();
    $display("a = %0s",a);
    $display("d=%0d",d);
  endfunction
endclass

class branch extends hyd;
  string b;
  function display();
    super.display();
    $display("b = %0s",b);
  endfunction
endclass

module casting;
   hyd p;
   branch  c;
   branch c1;
     
   initial begin:BEGIN_I
      c = new;
      c.a = "charminar";
      c.b = "cafe";
      p = c;
      $cast(c1,p);
      $display("contents of c1");
      c1.display();
   end:BEGIN_I

endmodule:casting

output:

dynamic casting

3.File Handling#

System verlilog allows us to read and write files in the system or disk.

We will have different file operations in system verilog

$fopen()#

A file can be opened for either read or write using the $fopen() system task.This task will return a datatype handle called a file descriptor. This handle should be used to read and write into that file until it is closed.

We will have read ,write and append modes in the file operations.

Cheat sheet for working modes:

ArgumentDescription
“r”Open for reading
“w”Create for writing, overwrite if it exists
“a”Create if file does not exist, else append; open for writing at end of file
“r+”Open for update (reading and writing)
“w+”Truncate or create for update
“a+”Append, open or create for update at EOF(end of file)

syntax:
datatype file_handle;
file_handle = $fopen("filename","working_mode");

$fclose()#

The file is closed is using $fclose() system task.

syntax:
$fclose(filehandle);

$fdisplay()#

This is a system task used to add the contents into the file.

syntax:
$fdisplay(filehandle,"content to add into file");

code snippet:

module file_handles;
int f;
   initial begin
      f=$fopen("file_handle","w");
      
      $fdisplay(f,"fileoperations");
      $fdisplay(f,"sv course");

      $fclose(f);
   end 
endmodule

Output:

example

$fgetc()#

This is a system task used to read one character(byte) from the file.

syntax:. $fgetc(filehandle);

$ungetc()#

This is the system task used to insert the character in the file.

syntax:
$ungetc(c,f);

$fgets()#

This is a system task used to read a single line from the file.

syntax:
$fgets(variable,filehandle);

code snippet:

module f_get;
   int c;
   int f;
   string line;
   int dummy;

   initial begin
      
      //write operation
      f=$fopen("file","w");
     
      $fdisplay(f,"sv course");
      $fdisplay(f,"filehandling");
     
      $fclose(f);
      
      //read operation
      f=$fopen("file","r");
      $display("");
      
      c = $fgetc(f);
      $display("reading one character : %0s",c);

      dummy = $ungetc(c,f);
      $display("character insert : %0s",c);

      dummy = $fgets(line,f);
      $display("line read : %0s",line);
     
      $fclose(f);
   end
endmodule

Output:

fil_get

fscanf()#

This is used to reads the data from file.

syntax:
$fscanf(filehandle,"variable = format_specifier",variable);

example:

$sscanf()#

sscanf reads the data from the given variable.

syntax:
$fgets(variable,filehandle);
$sscanf(variable,%0s,variable1);

code snippet:

module scanf;
 
   int fd;
   int i;
   string str,str2;
   int dummy;
 
   initial begin

      fd = $fopen ("hihihi.sv", "w");

      $fdisplay(fd,"bhavana");
      $fdisplay(fd,"Teams");
      $fdisplay(fd,"BJT");

      $fclose(fd);

      fd = $fopen("hihihi.sv","r");
      
      //Usage of fscanf
      dummy = $fscanf(fd,"str=%0s",str);
      repeat(2)
      begin
         dummy = $fgets(str,fd);
         $display("");
         $display("contents of fscanf");
         $display("str = %0s",str);
      end

      //Usage of sscanf
      $display("contents of sscanf");

      dummy = $fgets(str,fd);
      dummy =  $sscanf(str,"%0s",str2);
      
      $display("str = %0s",str);
      $display("str2 = %0s",str2);
      $display("");
      
      $fclose(fd);
   end
endmodule

Output:

scanf

$sformat()#

This system task is used to update a variable with particular content.

syntax: data_type var1,var2; $sformat(var2,"content",var1);

$sformatf()#

This is a system function which returns the updated content to a variable.

syntax: data_type var1,var2; var2 = $sformatf("content",var1);

code snippet:

module format;

   int a=9;
   int fd;
   string b="hii";
   string c;
  
   initial begin:BEGIN_I
  
      fd=$fopen("file","w");

      c = $sformatf("delta_%0d",a);
      $display("c=%0s",c);
  
      $sformat(b,"delta_%0d",a);
      $display("b=%0s",b);

      $fclose(fd);

   end:BEGIN_I
endmodule:format

output:

file_format

$feof#

SystemVerilog has another task called $feof() that returns true when end of the file has reached

syntax:
$feof(filehandle);

$rewind#

$rewind can be used to change the current read or write position within a file.We use this $rewind in “w+” mode to get the write position to the starting.

syntax:
$rewind(filehandle);

code snippet :

module tb;

   int fd;
   string str1,str2;

   initial begin

      //open the file in the write mode
      fd = $fopen ("hihihi.sv", "w+");

      //displays the contents into the file
      $fdisplay(fd,"teams");
      $fdisplay(fd,"c");
      $rewind(fd);

      //close the file
      $fclose(fd);

      //open the file in read mode
      fd = $fopen("hihihi.sv","r");
      $feof(fd);
      fd =$fopen("hihihi.sv","r");
    
      $fgets(str1,fd);
      $display("line:%0s",str1);
      
      $fclose(fd);

   end
endmodule

output:

rewind

$readmemb()#

readmemb() task reads the binary data.

syntax: $readmemb("filename",mem);

$readmemh()#

readmemh() task reads the hexadecimal data.

syntax: $readmemh("filename",mem);

code snippet:

module readmem;

   int fd;
   int i;
   int mem[3];
   string str;

   initial begin:BEGIN_I
      //open the file in write mode
      fd = $fopen ("hihihi.sv", "w");

      $fdisplay(fd,10000);
      $fdisplay(fd,11011);
      $fdisplay(fd,"c");

      //close the file in write mode
      $fclose(fd);

      $readmemh("hihihi.sv",mem);
      $readmemb("hihihi.sv",mem);
      repeat($size(mem))

      begin:BEGIN_II
         $display(""); 
         $display("hexadecimal[%0d] = %0h",i,mem[i]);
         $display("Binary[%0d] = %0b",i,mem[i]);
         $display("");
         i++;
      end:BEGIN_II

   end:BEGIN_I
endmodule:readmem

output:

output-readmem

4.Packages#

Packages are group of functions ,tasks ,classes that are shareable.Packages are meant for the code reusability similar to functions ,tasks and classes but all under one entity.

image

  • In a package we can have classes,functions and tasks but cannot have modules.
  • If there is a requirement of using the same class or function or task or all in multiple modules,instead of writing them again and again,we just put all of them under one identity,package and by importing that package we can use them anywhere in the module.

Syntax:

package <package_name>;

endpackage:<package_name>

  • To use a package in any module we should import the package using import keyword followed by package_name.

Syntax :

import <package_name>::<method_name>;
import <package_name>::*; //to import everything

code snippet:

Package code:

package one;

  int a;
  string k;

  class details;
    
    int age;
    string name;
    
    function new(int a,string b);
      age=a;
      name=b;
    endfunction
    
    function void getdetails();
      $display("name is  %0s",name," ,age is %0d",age);
    endfunction
    
    task t1;
      $display("it is in task of class");
    endtask: t1
    
    function void hi;
      $display("hi");
    endfunction
  
  endclass
  
  function void pack_func;
    details d;
    d=new(40,"raj");
    a=d.age;
    k=d.name;
    $display("in package function");
    $display("name given is %0s",k,", age is %0d",a);
  endfunction

  task pack_task;
    input int a;
    output string k="it is odd";
    if(a%2==0)begin
      k="it is even";
    end
  endtask

endpackage : one  

In the above code the package one contains a class details with few functions.And along with that we have a function in package pack_func and a task pack_task.

The code within the package can only be compiled.

Module code:

import one::*;

module mod1;

  string id1;
  details emp1=new(21,"kumar");

  initial begin
    string g;
    $display("details of id1 are : %0d",emp1.age);
    emp1.getdetails();
    emp1.t1();
    pack_func();
    pack_task(10,g);
    $display(g);
  end
endmodule : mod1 

Output:

image

Here, in the code of the module we would like to use the class details of the package one, and for that we import the package using import keyword.It simply means that all the code written in the package is a part of the module now and can be accessed.Here the class handle emp1 is used to access the class properties and class methods.The package functions and tasks can be accessed as it they were like module functions and tasks.

Package lab link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/production/Misc_constructs/Package/package_ex.sv
Module lab link: https://github.com/muneeb-mbytes/SystemVerilog_Course/blob/production/Misc_constructs/Package/package_mod1.sv

More about packages#

  • We can have multiple packages in single file.
  • Package cannot be static, extern, virtual, pure.
  • We can import a package within a package but cannot write a package inside a package.
  • If two packages have similar functions,then we use package name followed by scope resolution operator to access that function.
  • Packages cannot be imported with in the scope of the class but can be imported within a function & is valid within that function.
  • Packages can be imported into another package but the imported package must be compiled before use.
  • If two or more packages have same names then the compiler will take the recently compiled package.
  • Importing a package in a file means that pointing to that package whose scope is only visible to the file in which it is imported,means let us have a pkg P1 in which P2 is imported,we will think that importing P1 gives us advantage of using P2 contents but not, as the scope of P2 ends in P1 itself. to use P2 contents again just by importing p1 we use export
    syntax: export P2;

5.Scope Resolution Operator#

Scope Resolution operator is denoted as :: It is used to refer an identifier within the scope of the class. Left side of an scope resolution operator must be class type name, package name, typedef name and right hand side should be like variable name of any method name(task/function).

In System Verilog, Scope resolution operator :: being used in following cases :

1.Defining Extern class methods

With help of scope resolution operator we can define a class method outside the body of class

Code snippet:

class my_class;
  
  int a=5;
  int b=10;
  
  extern function void sum();
  extern function void sub();
  
endclass:my_class
 
function void my_class::sum();
  int result1;
  result1=a+b;
  $display("After summation the result1 is =%0d",result1);
endfunction
 
function void my_class::sub();
  int result2;
  result2=b-a;
  $display("After subsration the result2 is =%0d",result2);
endfunction

module extern_exm;
 
  initial begin:BEGIN_I
  
    my_class A1;
    A1=new();
    
    A1.sum();
    A1.sub();
  
  end:BEGIN_I
 
endmodule:extern_exm

Output:

On above code with help of scope resolution operator we define sum and sub class function outside the class so and inside module after create the object we access the both method then he display result1= 15 and result2=5

Untitled Diagram drawio

2.Accessing Static methods/properties

Static member of the class is accessed outside of the class by using scope resolution operator

Code snippet:

class my_class;
     
  int a;
  static int b;
 
  function void display();
    $display("value of a=%0d",a);
    $display("value of b=%0d",b);
  endfunction
 
endclass:my_class
 
module static_exm;
 
  initial begin:BEGIN_I
    my_class A1;
    A1 =new();
    A1.a=10;
    $display("Using the scope resolution operator we can access the static properties");
    my_class::b=20;   
    A1.display();
  end:BEGIN_I
 
endmodule:static_exm  

Output:

On above code with help of scope resolution operator we access the static properties (b) of class inside the module in module is assign the value of a and b both so it display value of a=10 and value of b=20

static-Page-4 drawio

3.Package parameter accessing without import in module

Without importing package we can accessed the package parameter here by using scope resolution operator

Code snippet:

package my_pkg;

  int a= 5;
 
endpackage:my_pkg
 
module pkg_exm;
 
  int b;
  
  initial begin:BEGIN_I
    b=my_pkg::a;      
    $display("Assining the value of a (properties of package) into b without importing package");
    $display("b=%0d",b);
  end:BEGIN_I
 
endmodule:pkg_exm  

Output:

On above code we access the package properties inside the module without importing the package with help of scope resolution operator here package properties a assign into b so it display b=5

pkg-Page-2 drawio

4.To avoid name Space Collision

If the package or class properties and module variable is same then with help of scope resolution we can differentiate both

Code snippet:

package my_pkg;

  int a=5;
 
endpackage :my_pkg
 
module pkg_exm;

  int a=10;
  int b=20;
  int c,d;
 
  initial begin:BEGIN_I
    $display("value a (package parameter) =%0d and  value of a (module variable)=%0d",my_pkg::a,a);
    c =my_pkg::a+b;
    d=a+b;
    $display("value c=%0d",c);
    $display("value d=%0d",d);
  end:BEGIN_I
 
endmodule:pkg_exm

Output:

On the above code we display the value of a =5 which is define in package without importing and value of a=10 which is define in module and we assign the sum of a and b into c where a is package properties and assign sum of a and b into d where a is module variable

avoid-Page-3 drawio

6.Command-Line inputs#

Command line arguments are used when we want to avoid test bench recompilation. As the name suggests, we can give values to the program mentioning in the command line. The arguments passed in the command line are accessible in our SV code with the help of system functions called plusargs.

Plusargs#

$test$plusargs#

This function is used when there is a need to get some instruction from command line precisely a string to perform next lines of code.

It is to be noted that all characters of the string mentioned in the function should match the plusarg we provide after + in the command line. When the string matches, the function $test$plusargs returns 1 otherwise it returns 0.

Syntax:

$test$plusargs("string")

Simulation command:

vsim module_name -c -do "run -all;quit" +string

Note: We are using Mentor Questa simulator in Command Line Interface which explains the above command format.

Code Snippet 1:

module CLI_testargs;
  bit x;
  
  initial begin:BEGIN-I
    x=$test$plusargs("START");
    $display("$test$plusargs returns %d",x);
    if(x)
      $display("Start process");
    else
      $display("exit");
  end:BEGIN-I

endmodule

Simulation command:

vsim CLI_testargs -c -do "run -all;quit" +START

-> In the above code snippet, if we give START in the CL then we’ll get x=1 and Start process is displayed. '

$test$plusargs returns 1  
Start process

-> The below code makes the usage of $test$plusargs in parallel execution of initial blocks.

Code Snippet 2:

initial begin:BEGIN_I
  x=$test$plusargs("START");
  $display("@%0dns In first begin block",$time);
  $display("@%0dns $test$plusargs returns %d",$time,x);
  if(x)
    $display("@%0dns Start process",$time);
  else
    $display("@%0dns exit",$time);
end:BEGIN_I

initial begin:BEGIN_II
  x=$test$plusargs("START");
  $display("@%0dns In second begin block",$time);
  $display("@%0dns $test$plusargs returns %d",$time,x);
  if(x)
    $display("@%0dns Start process",$time);
  else
    $display("@%0dns exit",$time);
end:BEGIN_II

Simulation command:

vsim CLI_testargs2 -c -do "run -all;quit" +START

@0ns In first begin block
@0ns $test$plusargs returns 1
@0ns Start process
@0ns In second begin block
@0ns $test$plusargs returns 1
@0ns Start process

->Since the string START is available for both the blocks the functions returns 1 in both at the same timestamp.

$value$plusarg#

This function is used when we need to take an input value from user through command line which can be further used or modified in the code.

In the simulation (in command line) we should explicitly give the value as string=value which follows +.

Syntax:

$value$plusargs("string=format_specifier",variable_name)

Here, format_specifier can be %d, %s etc.
The value we give is stored in variable_name and is accessible in the code.

Simulation command:

vsim module_name -c -do "run -all;quit" +string=value

Code Snippet 1

module CLI_valargs;
  bit x;
  int y;
  string message;

  initial begin:BEGIN_I
    x=$value$plusargs("msg=%s",message);
    $display("$value$plusargs used above returns %0d",x);
    $display(message);
    void'($value$plusargs("value=%d",y));
    y+=1;
    $display("Incremeneted value of y:%0d",y);
  end:BEGIN_I

endmodule

-> In the above code we are trying to give two value arguments(one is a string and the other is an integer) in the command line.

Simulation command:

vsim CLI_valargs -c -do "run -all;quit" +msg=HEY! +value=2

$value$plusargs used above returns 1
HEY!
Incremeneted value of y:3

Code Snippet 2

module CLI_valargs1;
  bit x;
  string y;
  string s;
  int fd,f;
  string message;
  
  initial begin
    x=$value$plusargs("msg=%s",message);
    $display("$value$plusargs used above returns %0d",x);
    $display(message);
    void'($value$plusargs("file=%s",y));
    fd=$fopen(y,"r");
    
    $fgets(s,fd);
    $display(s);
    
    $fclose(fd);

    fd=$fopen(y,"a");
    
    $fdisplay(fd,"Hurray!");
    
    $fclose(fd);
  end

endmodule

-> Here, we are trying to add contents to a file which we get from command line.

cl1-Page-2 drawio

Simulation command:

vsim CLI_valargs1 -l "CLI_valargs1.log" -c -do "run -all;quit" +msg=HEY! +file="sample.txt"

$value$plusargs used above returns 1
HEY!
We are trying to open this file using command line arhgument and it worked!

cl1-Page-1 drawio

Note: Both the functions $test$plusargs and $value$plusargs are case sensitive.