Uvm components, uvm env and uvm test are the three main building blocks of a testbench in uvm based verification.
uvm_env is extended from uvm_component and does not contain any extra functionality. uvm_env is used to create and connect the uvm_components like driver, monitors , sequeners etc. A environment class can also be used as sub-environment in another environment. As there is no difference between uvm_env and uvm_component , we will discuss about uvm_component, in the next section.
uvm verification component classes are derived from uvm_component class which provides features like hierarchy searching, phasing, configuration , reporting , factory and transaction recording.
Following are some of the uvm component classes
NOTE: uvm_env and uvm_test are also extended from uvm_component.
A typical uvm verification environment:
An agent typically contains three subcomponents: a driver, sequencer, and monitor. If the agent is active, subtypes should contain all three subcomponents. If the agent is passive, subtypes should contain only the monitor.
About Uvm_component Class:
uvm_compoenent class is inherited from uvm_report_object which is inherited from uvm_object.
As I mentioned previously, uvm_component class provides features like hierarchy searching, phasing, configuration , reporting , factory and transaction recording.
We will discuss about phasing concept in this section and rest of the features will be discussed as separate topics.
UVM Components execute their behavior in strictly ordered, pre-defined phases. Each phase is defined by its own virtual method, which derived components can override to incorporate component-specific behavior. By default , these methods do nothing.
--> virtualfunctionvoid build()
This phase is used to construct various child components/ports/exports and configures them.
--> virtualfunctionvoid connect()
This phase is used for connecting the ports/exports of the components.
--> virtualfunctionvoid end_of_elaboration()
This phase is used for configuring the components if required.
--> virtualfunctionvoid start_of_simulation()
This phase is used to print the banners and topology.
--> virtualtask run()
In this phase , Main body of the test is executed where all threads are forked off.
--> virtualfunctionvoid extract()
In this phase, all the required information is gathered.
--> virtualfunctionvoid check()
In this phase, check the results of the extracted information such as un responded requests in scoreboard, read statistics registers etc.
--> virtualfunctionvoid report()
This phase is used for reporting the pass/fail status.
Only build() method is executed in top down manner. i.e after executing parent build() method, child objects build() methods are executed. All other methods are executed in bottom-up manner. The run() method is the only method which is time consuming. The run() method is forked, so the order in which all components run() method are executed is undefined.
uvm_test is derived from uvm_component class and there is no extra functionality is added. The advantage of used uvm_test for defining the user defined test is that the test case selection can be done from command line option +UVM_TESTNAME=<testcase_string> . User can also select the testcase by passing the testcase name as string to uvm_root::run_test(<testcase_string>) method.
In the above <testcase_string> is the object type of the testcase class.
Lets implement environment for the following topology. I will describe the implementation of environment , testcase and top module. Agent, monitor and driver are implemented similar to environment.
1)Extend uvm_env class and define user environment.
class env extends uvm_env;
2)Declare the utility macro. This utility macro provides the implementation of create() and get_type_name() methods and all the requirements needed for factory.
3)Declare the objects for agents.
4)Define the constructor. In the constructor, call the super methods and pass the parent object. Parent is the object in which environment is instantiated.
function new(string name , uvm_component parent = null);
5)Define build method. In the build method, construct the agents.
To construct agents, use create() method. The advantage of create() over new() is that when create() method is called, it will check if there is a factory override and constructs the object of override type.