Wednesday, December 12, 2012

UVM Questions - 5

Q. In the accellera's UVM User guide, there are two monitors shown one at the agent level and another at the environment level, why ?
                                     Picture Courtesy- Accellera


A: There are variety of reasons why you need Monitor at different levels

    Any agent monitor also has a collector inside which collects only that data from DUT interfaces and forms a transaction which is destined to that particular agent.  As shown in the above diagram, Monitor will also have a UVM analysis ports to pass the transaction to other components in the environment like Scoreboard.

   However, the Monitor at the environment level (called as 'bus monitor' here) also snoops the DUT interface and forms the transactions destined to any master/slave agent on the bus but it won't pass the transactions to other components of the environment like scoreboard. This bus-level monitor uses those transactions to perform checking and coverage for the activities that are not necessarily related to a single agent.

Bus monitor is very useful for debugging at the SOC top level testbench environment where both source and destination of data flow (transactions) are within DUT itself. 

UVM Questions - 4

Q: What is the difference between uvm_component and uvm_object?
                       OR
Q: We already have uvm_object, why do we need uvm_component which is actually derived class of uvm_object?


A: uvm_component is a static entity and always tied(bind) to a given hardware and/or a TLM interface
 
   uvm_object is a dynamic entity and is not tied to any hardware/TLM interface

   uvm_component like uvm_driver is always connected to a particular DUT interface because throughout the simulation its job is fixed i.e. to drive the designated signals into DUT

   uvm_object like uvm_transaction is not connected to any particular DUT interface and its fields can take any random value based on randomization constraints.
 
   Though uvm_component is derived from uvm_object, uvm_component has got these additional interfaces

       * Hierarchy provides methods for searching and traversing the component hierarchy.
       * Phasing defines a phased test flow that all components follow, with a group of standard phase methods and an API for custom phases and multiple independent phasing domains to mirror DUT behavior e.g. power
       * Configuration provides methods for configuring component topology and other parameters ahead of and during component construction.
       * Reporting provides a convenience interface to the uvm_report_handler.  All messages, warnings, and errors are processed through this interface.
       * Transaction recording provides methods for recording the transactions produced or consumed by the component to a transaction database (vendor specific).
        * Factory provides a convenience interface to the uvm_factory. The factory is used to create new components and other objects based on type-wide and instance-specific configuration

Acronyms used:-
DUT - Design Under Test
TLM - Transaction Level Modelling
API - Application Programming Intefaces

Friday, December 7, 2012

UVM Questions - 3

Q. What is the advantage of using type_id::create() over new() while creating objects ?

There is nothing wrong in creating the objects for any uvm_component with constructor function new(), however if you are using UVM, there are some advantages of using factory way of creating objects i.e using

classname ::type_id::create("object name", parent)

This is what UVM1.1 Class Reference says

"Using the factory instead of allocating them directly (via new) allows different objects to be substituted for the original without modifying the requesting class"


Q: How to implement polymorphism in UVM?

The above advantage is illustrated through the polymorphism of a 'generic monitor' as follows:-

Any generic Monitor component's implementation will be

   class xyz_monitor extends uvm_monitor ;

      task run_phase ;
         // Implements monitor functionality here
      endtask
   endclass

Monitor has following modes of operation apart from basic xyz_monitor mode
     1. Mode1
     2. Mode2

   class monitor_mode1 extends xyz_monitor;
     // Implement monitor mode1
   endclass

   class monitor_mode2 extends xyz_monitor;
     // Implement monitor mode2
   endclass

    class parent extends uvm_env;
         .....
         ....
         xyz_monitor mon;
        mon = xyz_monitor::type_id::create("mon",this);
    endclass

Now during compilation you can specify which mode of the monitor you need for a particular simulation run using

    +uvm_set_type_override=<\req_type\>, <\overrid_type\>[,<\replace\>]

which work like the name based overrides in the factory--factory.set_type_override_by_name()

For the above example, If we need mode1 of monitor then the command line will be
    +uvm_set_type_override=xyz_monitor,monitor_mode1

For mode2, it would be
    +uvm_set_type_override=xyz_monitor,monitor_mode2

Effectively, there were no exclusive objects created for monitor mode1 or mode2, it basically override the object created for the object 'mon' which was originally of type 'xyz_monitor' and this is called Polymorphism because 'mon' object can potentially be any one of these types i.e. xyz_monitor or monitor_mode1 or monitor_mode2 for a given simulation run.

In fact, for the same monitor example if we have two instances(or objects) of xyz_monitor in your environment

    class parent extends uvm_env;
         .....
         ....
         xyz_monitor mon;
         xyz_monitor mon_extra;
        mon           = xyz_monitor::type_id::create("mon",this);
        mon_extra = xyz_monitor::type_id::create("mon",this);
    endclass

Now during compilation(command line) you can specify which modes of the monitor you need for a particular simulation run using
 +uvm_set_inst_override=<\req_type\>,<\overrid_type\>,<\full_inst_path\>

We can override 'mon' object to be of type monitor_mode1 using
 +uvm_set_inst_override=xyz_monitor,monitor_mode1,uvm_test_top.env.mon

We can override 'mon_extra' object to be of type monitor_mode2 using
 +uvm_set_inst_override=xyz_monitor,monitor_mode2,uvm_test_top.env.mon_extra

Please note that for 'uvm_set_inst_overrride', you need extra argument which is the path of 'object' and it has to start from uvm_test_top

Thursday, December 6, 2012

UVM Questions -2

Q. How to Create a scoreboard with add_item() , check_item() functions using UVM ?
A:  You need to first declare a class for the Scoreboard

    class scoreboard extends uvm_scoreboard;

Now you actually need two TLM ports one for the add_item() and another for check_item(). however UVM by default allows only one port per UVM 'component'. In order to have more ports you have to tell the factory in the following way, outside the class declaration.

UVM allows more than one imp ports to be declared which will not affect source of the analysis ports. Declaring two Analysis imp ports; one for the expected transaction and another for actual transaction

// In ocp imp port for the expected transaction (add_item())
`uvm_analysis_imp_decl(_add_item)

// Out ocp imp port for the actual transaction( check_item())
`uvm_analysis_imp_decl(_check_item)


Now you delcare these UVM analysis ports with the above extesions respectively.

   // Internally SCBD_ADD looks for the write_add_item() function
   uvm_analysis_imp_add_item#(transaction, scoreboard) SCBD_ADD;
   // Internally SCBD_CHECK looks for the write_check_item() function
   uvm_analysis_imp_check_item#(transaction, scoreboard) SCBD_CHECK;


where transaction is a 'uvm_transaction' and scoreboard is 'uvm_scoreboard'.

Now,  you need to create seperate constructors for the above imp ports

   function new(string name, uvm_component parent = null);  
       super.new(name, parent);
       SCBD_ADD  = new("SCBD_ADD", this);
       SCBD_CHECK = new("SCBD_CHECK",this);
   endfunction

 In order to implement the 'write()' functions of the producer of transaction i.e Monitor, we need the following functions in the scoreboard which is the consumer of the 'transaction'

   function void write_add_item( transaction t1);
       // Implement adding of the items to scoreoboard here
   endfunction

   function void write_check_item( transaction t2);

      // Implement checking of items against the expected
      // remove the expected item if match PASSES otherwise
      // fire an error
   endfunction

In reality,  UVM analysis port SCBD_ADD would get connected to the Monitor on 'Generator' which is giving expected data and SCBD_CHECK would get connected to the Collector which is providing actual data.