04.UVM_Factory Method - mbits-mirafra/UVMCourse GitHub Wiki

uvm_factory

As the name says, uvm_factory is used to create components and objects. UVM Factory is also known as Factory registration. With the help of lightweight proxies, Object and component types are registered with the factory to the actual objects and components being created.

Steps to follow to make use of factory

  1. Factory registration
  2. Default constructor new()
  3. Component and object creation
  4. Factory Overriding (if needed)

1. Factory registration

Using a pre-defined factory macro both uvm_component and uvm_object must be registered with the factory.

Factory registration for uvm_component

      class our_test extends uvm_test;    
      // factory registration for test    
      `uvm_component_utils(our_test)   
       ...   
       ...    
      endclass       

Factory registration for uvm_object

     class reg_seq extends uvm_sequence #(seq_item);   
     // factory registration for sequence     
     `uvm_object_utils(reg_seq)    
      ...    
      ...    
     endclass     

2. Default constructor new()

The constructors for uvm_object and uvm_components are virtual methods that are they have a fixed template that needs to be followed.

Constructor for uvm_component
Two arguments are provided for the default constructor: name and parent.

  1. The name denotes an instance name for an object.
  2. The parent denotes the handle to its parent. In the constructor, the parent argument is null and the actual parent can be provided while creating an object.
  3. All derived classes must call super.new() methods.

Note Any component whose parent is set to null becomes a child of uvm_top.

     class our_test extends uvm_component_name;   
    `uvm_component_utils(our_test)   
   
      // default constructor for test    
      function new(string name = "our_test", uvm_component_name parent)   
       super.new(name, parent);    
      endfunction    
     ...    
     ...   
    endclass     

Constructor for uvm_object

In an object, we can only have one argument, unlike a component.

    class reg_seq extends uvm_object_name ;
    `uvm_object_utils(reg_seq)

     // default constructor for sequence
     function new(string name = "reg_seq")
      super.new(name);
     endfunction
     ...
     ...  
    endclass  

3. Component and object creation

The create() method of the wrapper class is used to create objects for the uvm_object and uvm_component classes.

  1. Component instances and component hierarchy are created in the build phase.
  2. uvm_object are created in run time, so create UVM objects in the run phase.

Syntax for component creation
handle_name = class_name :: type_id :: create("name",parent)

Syntax for object creation
handle_name = class_name :: type_id :: create("name")

  • Example
      `include "uvm_macros.svh"  
       import uvm_pkg::*;  

      //Extend seq from uvm_sequence_item  
      class seq extends uvm_sequence_item;  

       //a is rand variable and bit data type  
       rand bit a;  

       //UVM Factory Registration Macro  
       `uvm_object_utils_begin(seq)  
       `uvm_field_int(a,UVM_DEFAULT)  
       `uvm_object_utils_end  

       //constructor Method  
       function new(input string name = "seq");  
       super.new(name);  
       endfunction  
       endclass  

       module top;
       seq s1;

       //Within initial
       initial 
           begin
          //create an instance of seq using factory create()
             s1= seq::type_id::create("s1");
               //repeating 5 times using repeat
                repeat(5) 
                   begin
                //using `uvm_info to display
                   `uvm_info("INFO","factory is created by using create method",UVM_NONE);
                   void'(s1.randomize());
    
                s1.print();
               end  
              end  
            endmodule 
 ` Example.1 - Factory registration`

Github lab code link https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_SiliconCrew/factory_method/creat_method/factory_creation_code.sv

Github log code link https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_SiliconCrew/factory_method/creat_method/factory_creation_log.log

In the above example, trying to create a factory method by using the create method. we extend the class name by seq by using UVM inbuild library uvm_sequence_item and after that initializing the Factory registration Macro. Then declaring the constructor method. s1 is the handle of the seq class. By using the following syntax, created the Factory method
handle_name= class_name::type_id::create("handle_name");
then class_handle.print is used to print the output.

  • output snap

Untitled Diagram drawio (14)

          output.1 - output for factory creation and randomizing some transactions  

In the above output, we created a factory using the create method and displayed some random values in 5 iterations.


Why do we need factory registration in UVM?

The factory requires knowledge of every class type that is produced within the testbench through a procedure known as registration. With the help of certain UVM macros classes can be registered with the factory, as well as methods that allow derived types to override certain types and instances of class objects.

  • Example

Example for object creation using new constructor

     `include "uvm_macros.svh"
      import uvm_pkg::*;

      //Extend seq from uvm_sequence_item
      class seq extends uvm_sequence_item;

      //a is rand variable and bit data type
      rand int a;

      //UVM Factory Registration Macro
      `uvm_object_utils_begin(seq)
      `uvm_field_int(a,UVM_DEFAULT)
      `uvm_object_utils_end

      //constructor Method
      function new(input string name = "seq");
      super.new(name);
      endfunction
  
      //constraint Method
      constraint cons1{a inside {[5:10]};}
      endclass


      //Extend extend_seq from seq;
      class extend_seq extends seq;
       //UVM Factory Registration 
       `uvm_object_utils(extend_seq);
  
       //constructor Method
      function new (input string name="extend_seq");
       super.new(name);
      endfunction

      //constraint method
      constraint cons2 {a inside {9};}
      endclass


      module top;
      seq s1;
      extend_seq s2;
  
      function void build();
      void'(s1.randomize());
      s1.print();
      endfunction


     //Within initial
      initial 
            begin
            //create an instance of seq using factory new()
            s1=new();
            //repeating 5 times using repeat
            repeat(5)  begin
               //using `uvm_info to display
               `uvm_info("B_INFO","1...factory is created by using create method",UVM_NONE);
               build ();
            end

            factory.set_type_override_by_type(seq::get_type(),extend_seq::get_type());
        
            repeat(5)  begin
               //using `uvm_info to display
               `uvm_info("A_INFO","2...factory is created by using new method",UVM_NONE); 
               s1=new();
               build();       
            end
        end
      endmodule   

Example.2 - Component creation using new constructor

GitHub lab code link https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_SiliconCrew/factory_method/new_method/factory_new_code.sv

Github log code link https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_SiliconCrew/factory_method/new_method/factory_new_log.log

In the above example, here trying to create a factory method by using the new method. we extend the class name seq by using UVM inbuild library uvm_sequence_item and after that initializing the Factory registration Macro. then we declare the constructor method.
s1 is the handle of the seq class we use this syntax to create the Factory method
handle_name= class_name::type_id::create("handle_name");
then class_handle.print using to print the output. Trying to over-riding the parent class with the child class but here we are using only a new method so we can't override the factory things, this is the main drawback of the new method,so that's we will be moving to factory registration with create method.

  • output

Untitled Diagram drawio (15)

                  output.2 - output for object creation by using new constructor  

In the above output, creating the factory we were using the new method. we declared 2 constraints, the 1st constraint is declared in the parent class and the second constraint is declared in the child class i.e., the 5 to 10 range in constraint 1, and the 2nd constraint is only 9. If the override is possible then it constraint solver gives 9 but it is not the case here, the other numbers were also given as we used new method.


4. Factory Override

factory_override

                         Fig.1 - Over-riding types   

Factory override means to override the base class with the child class. Factory overriding helps exchange the test bench's behaviour by substituting one class for another when it is constructed without having to edit or recompile the test bench code.
Using the polymorphism concept, the factory override mechanism returns a derived type handle using a base type handle. This means when the create method is being called for the base class type, uvm_factory will return a pointer to an object of a derived class type.

Note: The factory override ways are applicable for both uvm components and uvm objects.

There are two ways to override the factory -

1. Global Override
2. Instance Override

1.Global Override

In a global override, a substitute component class type is created instead of an original component class in the testbench hierarchy. It applies to all instances of that component type. (It means the changes done by type override are reflected for the entires testbench)
There are two methods for a global override -

1.1. set_type_ovrrride_by_type
Syntax
set_type_override_by_type(original_type::get_type(),substitute_type::get_type(),replace=1);
//replace =1 is the default value

1.2. set_type_override_by_name
Syntax
set_type_override_by_name (string original_type_name, string override_type_name, bit replace = 1)

2. Instance Override

Instance override does override only specified components in the uvm Testbench hierarchy.
There are two methods of instance override.
2.1.set_inst_override_by_type

Syntax
set_inst_override_by_type (uvm_object_wrapper original_type,uvm_object_wrapper override_type string full_inst_path);

2.2. set_inst_override_by_name
Syntax
set_inst_override_by_name (string original_type_name,string override_type_name,string full_inst_path);

  • Example

Let's take an example of Global Override for better understanding.

     `include "uvm_macros.svh"
      import uvm_pkg::*;

      //Extend seq from uvm_sequence_item
      class seq extends uvm_sequence_item;

      //a is rand variable and bit data type
       rand int a;

       //UVM Factory Registration Macro
       `uvm_object_utils_begin(seq)
       `uvm_field_int(a,UVM_DEFAULT)
       `uvm_object_utils_end

        //constructor Method
        function new(input string name = "seq");
         super.new(name);
         endfunction
  
        //constraint Method
        constraint cons1{a inside {[5:10]};}
        endclass


        //Extend extend_seq from seq;
         class extend_seq extends seq;
        //UVM Factory Registration 
        `uvm_object_utils(extend_seq);
  
        //constructor Method
        function new (input string name="extend_seq");
        super.new(name);
        endfunction

        //constraint method
        constraint cons2 {a inside {9};}
        endclass

        module top;
        seq s1;
        extend_seq s2;
        //Within initial
        initial 
            begin
              //create an instance of seq using the factory create method
              s1=seq::type_id::create("s1");  
               //s1=new();
              //repeating 5 times using repeat
              repeat(5)  begin
                  //using `uvm_info to display
                  `uvm_info("A_INFO","1...before global_overriding ",UVM_NONE);
                   void'(s1.randomize());
                   s1.print();
               end
                   factory.set_type_override_by_type(seq::get_type(),extend_seq::get_type());
            s1=seq::type_id::create("s1");  
           // s1=new();
              repeat(5)  begin
                  //using `uvm_info to display
                  `uvm_info("B_INFO","2...after factory overriding by using global_override ",UVM_NONE);
                  void'(s1.randomize());
                  s1.print();
                end
      end
      endmodule    

Example.3 - Global Over-riding by using factory registration

In the above example, we were doing global overring, we extend the class name seq by using UVM inbuild library is uvm_sequence_item and after that initialized the Factory registration Macro and in this class, we wrote constraint its range from 5 to 10 values. another class name is extend_seq is extends from the seq, In this class, we wrote constraint a=9 if factory override is done it gives the output as 9. this is done by using their global overriding and we followed syntax is factory.set_type_override_by_type(seq::get_type(),extend_seq::get_type());

  • output snap

Untitled Diagram drawio (16)

               output.3 - output for Global over-riding by type

In the above output, creating the factory we were using the create method and overriding the things by using the global override method. we declared 2 constraints, the 1st constraint is displayed in the 5 to 10 range and the 2nd constraint is only 9. If the override is correct it displays the 9. see the last 3 iterations of output it displays the output as 9.

GitHub lab code link https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_SiliconCrew/factory_method/override/global_ov/global_override_code.sv

GitHub log code link https://github.com/mbits-mirafra/UVMCourse/blob/b7_Team_SiliconCrew/factory_method/override/global_ov/global_override_log.log