image/svg+xml
  • Contents
      • Back
      • Digital Basics
      • Verilog
      • Verification
      • SystemVerilog
      • UVM
Most Popular
Verification
  Testbench Evolution
  Constraint Random Verification
  Verification Techniques
  Verification Plan
  Code Coverage

Verilog
  Data Types
  Basic Constructs
  Behavioral Modeling
  Gate Modeling
  Simulation Basics
  Design Examples

SystemVerilog
  Data Types
  Class
  Interface
  Constraints and more!
  Testbench Examples

UVM
  Sequences
  Testbench Components
  TLM Tutorial
  Register Model Tutorial
  Testbench Examples

Digital Fundamentals
  Binary Arithmetic
  Boolean Logic
  Karnaugh Maps
  Combinational Logic
  Sequential Logic




SystemVerilog Program Blocks

A module is the fundamental construct used for building designs. Each module can contain hierarchies of other modules, nets, variables and other procedural blocks to describe any hardware functionality. The testbench on the other hand is a complete environment to verify the design and hence an emphasis is placed on the way it is modeled to make it more re-usable and effective. It must be properly initialized and synchronized avoiding race conditions between the design and the testbench.

What is the need for a program block ?

SystemVerilog program block was introduced for the following reasons.

  • To provide an entry point to the execution of testbenches
  • To create a container to hold all other testbench data such as tasks, class objects and functions
  • Avoid race conditions with the design by getting executed during the reactive region of a simulation cycle

The reactive region is one of the last few phases before simulation time advances, and by then all design element statements would have been executed and testbench will see the updated value. It is important to have this demarcation between the execution of design and testbench statements because it will give a more deterministic output between simulators.

Syntax


program [name] [port_list];
	...
endprogram

Examples


	program test1 (input clk, reset);
		initial ...
	endprogram
	
	program test2 (interface wb_if);
		initial ...
	endprogram
	
	program test3;
		initial ...
	endprogram

A program block can be nested within modules and interfaces and hence multiple programs within the same module can share variables local to that scope. In the example below, mode is a local variable within tb and can be accessed by both programs p1 and p2.


module tb;
	bit [3:0] mode;
	
	program p1;
		...
	endprogram
	
	program p2;
		...
	endprogram
endmodule

Creating user-defined phases

Creation of user-defined phases in UVM is a possibility although it may hinder in complete re-usability of the testbench. There are chances for components to go out of sync and cause errors related to null pointer handles. But, in case you decide that you have to use one for your project, keep reading.

user-defined phase in uvm

Some of the main steps to using a custom phase are:

  • Create and define a new phase class
  • Add the new phase to an existing schedule
  • Use the new phase in a component that supports this phase

Read more: Creating user-defined phases

UVM Register Model Classes

  1. What is a register model ?
  2. UVM RAL Classes
  3. uvm_reg_field
  4. uvm_reg
  5. uvm_reg_block
  6. What are desired and mirrored values ?

What is a register model ?

A register model, provide a structured and standardized way to model and verify the registers and memory-mapped structures within a digital design. It consists of a hierarchy of blocks represented by UVM class objects that are structured equivalent to the registers and memory in design.

uvm_ral_overview

Since typical designs contain hundreds of registers, register model generation is usually done by custom scripts or standard software tools like RalGen from Synopsys or RGM from Cadence. These tools take the register specification as an input such as an IPXACT XML file and generates a SystemVerilog file which contains fields and registers specified using standard UVM register classes.


// Sample IPXACT register specification

<spirit:usage>register</spirit:usage>
	<spirit:register>
    	<spirit:name>REG_CTL</spirit:name>
      	<spirit:addressOffset>0x0</spirit:addressOffset>
      	<spirit:size>32</spirit:size>
      	<spirit:reset>
         	<spirit:value>0x2A</spirit:value>
      	</spirit:reset>
      	<spirit:access>read-write</spirit:access>
      	<spirit:field>
          <spirit:name>EN</spirit:name>
          <spirit:description>Enable the module</spirit:description>
          <spirit:bitOffset>0</spirit:bitOffset>
          <spirit:bitWidth>1</spirit:bitWidth>
          <spirit:access>read-write</spirit:access>
      </spirit:field>

      ...      

UVM RAL Classes

uml_uvm_ral_hier
ClassDescription
uvm_reg_fieldUsed for register field implementation
uvm_regUsed to implement design register
uvm_reg_fileUsed to collect a group of registers
uvm_reg_mapRepresents an address map
uvm_memUsed to represent memory in design
uvm_reg_blockContainer class to store registers, maps and memories

uvm_reg_field

uvm_reg_field is a class that is used to model individual fields within a register. Fields in a register represent specific bits or groups of bits that have distinct functionalities, access permissions, reset values, and other attributes.

uml_uvm_reg_field

These are some of the most commonly used methods in uvm_reg_field. Please refer to the UVM reference manual to see the full set of methods.


	// Configure the register field class
	extern function void configure(uvm_reg        parent, 		// Parent register handle
                                   int unsigned   size, 		// Bit-width of the field
                                   int unsigned   lsb_pos, 		// LSB index of the field in register
                                   string         access, 		// Read/read-write/etc access policy
                                   bit            volatile, 		
                                   uvm_reg_data_t reset,
                                   bit            has_reset, 	
                                   bit            is_rand,
                                   bit            individually_accessible); 


	// Get width of the field, in number of bits
	extern virtual function int unsigned get_n_bits();

	// Returns index of LSB of the field in the register that instantiates it
	extern virtual function int unsigned get_lsb_pos();

	// Set desired value in the regmodel for this field
	extern virtual function void set(uvm_reg_data_t  value,
                                    string          fname = "",
                                    int             lineno = 0);

	// Get desired value in regmodel for this field
	extern virtual function uvm_reg_data_t get(string fname = "",
                                              int    lineno = 0);

	// Get mirrored value in regmodel for this field
	extern virtual function uvm_reg_data_t get_mirrored_value(string fname = "",
                                               				 int    lineno = 0);

Here is an example of how user register field of type uvm_reg_field is instantiated and configured inside a register.


	// Declare register field handle
	uvm_reg_field 	m_enable;

	// Create an instance and configure the register field handle
	m_enable = uvm_reg_field::type_id::create("m_enable");
	m_enable.configure(this, 1, 0, "RW", 0, 1'h0, 1, 1, 1);

uvm_reg

uvm_reg is a base class provided by the UVM library that is used to model registers, and user defined classes are extended from this base class.

uml_uvm_reg

These are some of the most commonly used methods in uvm_reg.


   // Get fields of this register as a queue
   extern virtual function void get_fields (ref uvm_reg_field fields[$]);

   // Get a particular field by name
   extern virtual function uvm_reg_field get_field_by_name(string name);

   // Get address of this register
   extern virtual function uvm_reg_addr_t get_address (uvm_reg_map map = null);

   // Set desired value in regmodel
   extern virtual function void set (uvm_reg_data_t  value,
                                     string          fname = "",
                                     int             lineno = 0);

   // Get desired value in regmodel
   extern virtual function uvm_reg_data_t  get(string  fname = "",
                                               int     lineno = 0);

   // Get last known design value 
   extern virtual function uvm_reg_data_t  get_mirrored_value(string  fname = "",
                                               int     lineno = 0);

   // Issue a register write with the given value
   extern virtual task write(output uvm_status_e      status,
                             input  uvm_reg_data_t    value,
                             input  uvm_door_e        path = UVM_DEFAULT_DOOR,
                             input  uvm_reg_map       map = null,
                             input  uvm_sequence_base parent = null,
                             input  int               prior = -1,
                             input  uvm_object        extension = null,
                             input  string            fname = "",
                             input  int               lineno = 0);

   // Issue a register read and get value into the given variable
   extern virtual task read(output uvm_status_e      status,
                            output uvm_reg_data_t    value,
                            input  uvm_door_e        path = UVM_DEFAULT_DOOR,
                            input  uvm_reg_map       map = null,
                            input  uvm_sequence_base parent = null,
                            input  int               prior = -1,
                            input  uvm_object        extension = null,
                            input  string            fname = "",
                            input  int               lineno = 0);

   // Update design if desired value is not same as mirrored value
   extern virtual task update(output uvm_status_e      status,
                              input  uvm_door_e        path = UVM_DEFAULT_DOOR,
                              input  uvm_reg_map       map = null,
                              input  uvm_sequence_base parent = null,
                              input  int               prior = -1,
                              input  uvm_object        extension = null,
                              input  string            fname = "",
                              input  int               lineno = 0);

   // Update regmodel with mirrored value
   extern virtual task mirror(output uvm_status_e      status,
                              input uvm_check_e        check  = UVM_NO_CHECK,
                              input uvm_door_e         path = UVM_DEFAULT_DOOR,
                              input uvm_reg_map        map = null,
                              input uvm_sequence_base  parent = null,
                              input int                prior = -1,
                              input  uvm_object        extension = null,
                              input string             fname = "",
                              input int                lineno = 0);

Here is an example of a user register extended from uvm_reg base class.


class reg_ctl extends uvm_reg;
	rand uvm_reg_field  En;

	function new (string name = "reg_ctl");
		super.new (name, 32, UVM_NO_COVERAGE);
	endfunction

	virtual function void build ();	
		// Create object instance for each field
		this.En     = uvm_reg_field::type_id::create ("En");
		
		// Configure each field
		this.En.configure (this, 1, 0, "RW", 0, 1'h0, 1, 1, 1);
	endfunction
endclass

uvm_reg_block

A uvm_reg_block can contain registers, register files, memories and sub-blocks.

uml_uvm_reg_block

	// Get queue of registers
   extern virtual function void get_registers (ref uvm_reg regs[$],
                                               input uvm_hier_e hier=UVM_HIER);

	// Get register block by name
  extern virtual function uvm_reg_block get_block_by_name (string name);  

	// Get register by name
   extern virtual function uvm_reg get_reg_by_name (string name);

	// Get field by name
   extern virtual function uvm_reg_field get_field_by_name (string name);

	// Update registers in this reg block
   extern virtual task update(output uvm_status_e       status,
                              input  uvm_door_e         path = UVM_DEFAULT_DOOR,
                              input  uvm_sequence_base  parent = null,
                              input  int                prior = -1,
                              input  uvm_object         extension = null,
                              input  string             fname = "",
                              input  int                lineno = 0);

What are desired and mirrored values ?

Every register in the model corresponds to an actual hardware register in the design. There are two kinds of variables inside the register within a model.

design-register-model-desired-mirrored-values

Desired value is what we the design to have. In other words, the model has an internal variable to store a desired value that can be updated later in the design. For example, if we want the register REG_STAT in the design to have a value of 0x1234_5678, then the desired value of that register has to be set to 0x1234_5678 within the model and an update task should be called for this to be reflected in the design.

desired-value

Read more: UVM Register Model Classes

SystemVerilog Parameterized Classes

Why do we need parameterization for classes ?

At times it would be much easier to write a generic class which can be instantiated in multiple ways to achieve different array sizes or data types. This avoids the need to re-write code for specific features like size or type and instead allow a single specification to be used for different objects. This is achieved by extending the SystemVerilog parameter mechanism to classes.

Parameters are like constants that are local to the specified class. Classes are allowed to have default value for each parameter that can be overridden during class instantiation.

Syntax


	// Declare parameterized class
	class <name_of_class> #(<parameters>);
	class Trans #(addr = 32);
	
	// Override class parameter
	<name_of_class>  #(<parameters>) <name_of_inst>;
	Trans #(.addr(16)) obj;

Examples

Parameterized Classes

Given below is a parameterized class which has size as the parameter that can be changed during instantiation.


// A class is parameterized by #() 
// Here, we define a parameter called "size" and gives it 
// a default value of 8. The "size" parameter is used to
// define the size of the "out" variable
class something #(int size = 8);
	bit [size-1:0] out;
endclass

module tb;
  
  // Override default value of 8 with the given values in #()
  something  #(16) sth1;                 // pass 16 as "size" to this class object
  something  #(.size (8)) sth2;          // pass 8 as "size" to this class object
  typedef something #(4) td_nibble;      // create an alias for a class with "size" = 4 as "nibble"
  td_nibble nibble;
  
  initial begin
    // 1. Instantiate class objects
    sth1 = new;
    sth2 = new;
  	nibble = new;  
    
    // 2. Print size of "out" variable. $bits() system task will return
    // the number of bits in a given variable
    $display ("sth1.out   = %0d bits", $bits(sth1.out));
    $display ("sth2.out   = %0d bits", $bits(sth2.out));
    $display ("nibble.out = %0d bits", $bits(nibble.out));
  end
endmodule
 Simulation Log
ncsim> run
sth1.out   = 16 bits
sth2.out   = 8 bits
nibble.out = 4 bits
ncsim: *W,RNQUIE: Simulation is complete.

Pass datatype as a parameter

Data-type is parameterized in this case and can be overridden during instantiation. In the previous case, we defined parameters to have a specific value.

Read more: SystemVerilog Parameterized Classes

SystemVerilog super Keyword

The super keyword is used from within a sub-class to refer to properties and methods of the base class. It is mandatory to use the super keyword to access properties and methods if they have been overridden by the sub-class.

Example

The super keyword can only be used within a class scope that derives from a base class. The code shown below will have compilation errors because extPacket is not a child of Packet. Note that new method is implicitly defined for every class definition, and hence we do not need a new defintion in the base class Packet.


class Packet;
	int addr;
	function display ();
		$display ("[Base] addr=0x%0h", addr);
	endfunction
endclass

class extPacket;                       // "extends" keyword missing -> not a child class
	function new ();
		super.new ();
	endfunction
endclass

module tb;
	Packet p;
  	extPacket ep;
  
  	initial begin
      ep = new();
      p = new();
      p.display();
    end
endmodule
 Simulation Log
super.new ();
        |
ncvlog: *E,CLSSPX (testbench.sv,12|8): 'super' can only be used within a class scope that derives from a base class.

Now let us see the output when extPacket is a derivative of class Packet.


class extPacket extends Packet;                       // extPacket is a child class of Packet
	function new ();
		super.new ();
	endfunction
endclass	

You can see from the simulation result below that there were no compilation errors.

 Simulation Log
ncsim> run
[Base] addr=0x0
ncsim: *W,RNQUIE: Simulation is complete.

Accessing base class methods

In the example shown below, display method of the base class is called from the display method of the child class using super keyword.


class Packet;
  int addr;
  
  function display ();
    $display ("[Base] addr=0x%0h", addr);
  endfunction
endclass
 
class extPacket extends Packet;
  function display();
    super.display();                          // Call base class display method
    $display ("[Child] addr=0x%0h", addr);
  endfunction
  
  function new ();
    super.new ();
  endfunction
endclass
 
module tb;
 	Packet p;
  	extPacket ep;
  
  	initial begin
      ep = new();
      p = new();
      ep.display();
    end
endmodule	
 Simulation Log
ncsim> run
[Base] addr=0x0
[Child] addr=0x0
ncsim: *W,RNQUIE: Simulation is complete.
  1. SystemVerilog Virtual Methods
  2. SystemVerilog Inheritance
  3. SystemVerilog Copying Objects
  4. SystemVerilog 'this' keyword
  5. SystemVerilog Static Variables & Functions

Page 32 of 63

  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
Interview Questions
  Verilog Interview Set 1
  Verilog Interview Set 2
  Verilog Interview Set 3
  Verilog Interview Set 4
  Verilog Interview Set 5

  SystemVerilog Interview Set 1
  SystemVerilog Interview Set 2
  SystemVerilog Interview Set 3
  SystemVerilog Interview Set 4
  SystemVerilog Interview Set 5

  UVM Interview Set 1
  UVM Interview Set 2
  UVM Interview Set 3
  UVM Interview Set 4
Related Topics
  Digital Fundamentals
  Verilog Tutorial

  Verification
  SystemVerilog Tutorial
  UVM Tutorial
  • Verilog Testbench
  • Verilog Coding Style Effect
  • Verilog Conditional Statements
  • Verilog Interview Set 10
  • Synchronous FIFO
  • SystemVerilog Interview Set 10
  • SystemVerilog Interview Set 9
  • SystemVerilog Interview Set 8
  • SystemVerilog Interview Set 7
  • SystemVerilog Interview Set 6
  • UVM Singleton Object
  • UVM Component [uvm_component]
  • UVM Object [uvm_object]
  • UVM Root [uvm_root]
  • UVM Interview Set 4
© 2015 - 2023 ChipVerify
Terms and Conditions | DMCA.com Protection Status