What to expect from UVM in interviews?

UVM stands for "Universal Verification Methodology" which is a organized way of writing/implementing a verification testbench in Systemverilog. This page has the most frequently asked interview questions from this topic. As a UVM expoert, the candidate is expected to know how to architect UVM environments along with setting up the neccessary scripts, flows and other neccessary requirements to run the design with the UVM testbench. Followed by the verification plan development and later the implementation of that plan using UVM.

Theory Questions ( Click to expand )
    Universal Verification Methodology
    SystemVerilog
    UVM phases are predefined methods that dictate the sequence and timing of testbench operations. They fall into two categories: common phases and run-time phases. Common phases, which include build, connect, and end_of_elaboration, are executed by all components within the testbench hierarchy. Run-time phases, such as main_phase, pre_reset_phase, and post_shutdown_phase, are executed by specific components like the driver, monitor, and scoreboard. UVM phases enable control over the initialization, configuration, execution, and termination of testbench components.
    All consuming tasks are performed within the phase_objections start and drop. All objections are tracked by UVM_ROOT (the implicit top-level component created by UVM itself). Whenever objections are dropped, UVM_ROOT automatically triggers the post-simulation phases (extract, check, report), followed by $finish.
    Its a predefined task in uvm which will not ungate execution until the NBA region completes. Essentially if you go to the source code of UVM, you will see that there is a simple call to #0.
    You will find the UV source code in any simulator's install area. Even if you dont have access, you can always use the Verification Academy and Accelera's guids for the code.
    Yes we can have multiple implementations of analysis port inside a component. There are two wahys to do it. One very common and simple way is to create multiple write method declertaion inside that component using the `uvm_analysis_impl_decl(SUFFIX) macro. Example : `uvm_analysis_imp_decl(_port_a) and similarly, `uvm_analysis_imp_decl(_port_b)
    In UVM, drain time refers to the time allowed for all active sequences and pending transactions to complete before ending the test. During drain time, the UVM framework ensures that all ongoing operations, particularly those on sequencers, finish properly without being abruptly terminated. This is crucial in tests where sequences may still be generating transactions or when there are transactions in-flight. It ensures graceful shutdown and accurate coverage collection by allowing the system to "drain" any remaining activities. The drain time is typically controlled using the uvm_phase mechanism or through custom testbench control mechanisms.
    Phases make it possible to make sure the simulation happens in stages while making sure all the UVM components move from one stage to another (ie one phase to another) only when all components have executed a specific phase. This ensures synchronization between components, ie it ensures two components are not in two different phases at any given point of time.
    The concept of a uvm_agent is necessary because it provides a modular and reusable framework for handling a specific interface or protocol in the testbench. A uvm_agent encapsulates three key components: the driver, sequencer, and monitor, ensuring that stimulus is generated, driven to the DUT, and monitored in a coordinated manner. This structure helps in simplifying the testbench by organizing verification components for a particular interface, making it easier to reuse and maintain across different test environments, thus promoting scalability and reducing redundancy.
    In UVM, an active component refers to a component that both generates and drives stimulus to the DUT. Examples include the sequencer and driver. An active agent has these components enabled, allowing it to actively drive transactions. A passive component, on the other hand, only monitors the DUT without generating or driving any stimulus. It typically includes just a monitor that observes transactions and reports coverage or checks. A passive agent is useful when you want to observe the DUT's behavior without influencing its operation.
    // UVM_COMPONENT :
    // ---------------
    // 1. They are created from the begining of the simulation and continue to exist throughout the simulation. 
    // 2. UVM components have this concept of phases for synchronization. 
    // 3. Although they do not possess any predefined subroutines like print and copy.
    
    // UVM_OBJECT :
    // ------------
    // 1. These are created during the simulation (on the fly) and get consumed whenever there is no one using them or have been forcefully de-allocated. 
    // 2. These have many in-built subroutines. Its possible to create and destror instances of these whenever we want without any restrictions. 
    // 3. There is not need of any concept of synchronization between any two uvm_objects.
    
Coding Questions ( Click to expand )
    module top;
    
        initial
        begin
            run_test( "DEFAULT_UVM_TESTNAME_PASS_HERE" ); // This will ensure this test is run if no "TESTNAME" argument is passed
        end
    
    endmodule
    
    `uvm_analysis_imp_decl(_port_a)
    `uvm_analysis_imp_decl(_port_b)
    
    class component_b extends uvm_component;
     
        transaction trans;
        uvm_analysis_imp_port_a #(transaction,component_b) analysis_imp_a;  
        uvm_analysis_imp_port_b #(transaction,component_b) analysis_imp_b;
    
        `uvm_component_utils(component_b)
    
        //---------------------------------------
        // Constructor
        //---------------------------------------
        function new(string name, uvm_component parent);
            super.new(name, parent);
            analysis_imp_a = new("analysis_imp_a", this);
            analysis_imp_b = new("analysis_imp_b", this);
        endfunction : new
    
        //---------------------------------------
        // Analysis port write method
        //---------------------------------------
        virtual function void write_port_a(transaction trans);
            `uvm_info(get_type_name(),$sformatf(" Inside write_port_a method.
                                                  Recived trans On Analysis Imp Port"),UVM_LOW)
            `uvm_info(get_type_name(),$sformatf(" Printing trans, \n %s",
                                                  trans.sprint()),UVM_LOW)
        endfunction
    
        //---------------------------------------
        // Analysis port write method
        //---------------------------------------
        virtual function void write_port_b(transaction trans);
            `uvm_info(get_type_name(),$sformatf(" Inside write_port_b method.
                                                  Recived trans On Analysis Imp Port"),UVM_LOW)
            `uvm_info(get_type_name(),$sformatf(" Printing trans, \n %s",
                                                  trans.sprint()),UVM_LOW)
        endfunction
     
    endclass : component_b