Updated for UVM 1.0
From Design Entities and Modules to the UVM Component
Every language used to describe electronic systems has hierarchical building blocks. VHDL has the design entity. Verilog has the module. UVM has the component. The syntax of UVM components is a little different in spirit to VHDL or Verilog because UVM makes use of the dynamic, object-oriented programming features of SystemVerilog, but in many cases the correspondence is pretty clear. For example:
// VERILOG module A; wire w; B B_instance( .p(w) ); C C_instance( .q(w) ); endmodule
// UVM class A extends uvm_component; `uvm_component_utils(A) B B_h; C C_h; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); B_h = B::type_id::create("B_h", this); C_h = C::type_id::create("C_h", this); endfunction function void connect_phase(uvm_phase phase); B_h.p_port.connect( C_h.q_export ); endfunction endclass
In the example above, a top-level block named A instantiates two lower level blocks named B and C. The Verilog module instances named B_instance and C_instance are replaced in UVM by the SystemVerilog variables B_h and C_h, the suffix _h indicating that the variable is a handle to an object rather than being the object itself. The UVM equivalent of Verilog module instantiation is done within function build_phase, and the UVM equivalent of Verilog port connection is done within function connect_phase. UVM ports are analogous to Verilog ports and can even be connected by name like Verilog ports, although unlike Verilog ports UVM ports are used to pass transactions using function calls (more on this later).
The rest of the UVM component should be treated like boilerplate code and just reproduced as shown in each and every component. This includes the uvm_component_utils line, the function new (which is known technically as the constructor of the class), and the skeleton of the functions build_phase and connect_phase.
Now, there is no denying that the UVM version is more verbose than its Verilog equivalent. There is some truth in the claim that as the blocks grow in size the difference would become a little less noticable, but UVM would remain more verbose than Verilog nonetheless. There are good reasons for this.
In Verilog and VHDL there are three fixed phases known as compilation (or analysis), elaboration, and simulation during which the syntax gets checked, the design hierarchy/module hierarchy gets built, and simulation gets run, respectively. UVM offers more than three phases in order to support the integration and execution of verification IP. Because UVM is SystemVerilog it shares SystemVerilog's phases, but the SystemVerilog simulation phase is further broken down within UVM into:
and further user-defined phases can be inserted as needed. The UVM component may contain a separate function corresponding to each of these phases. In the world of class-based programming, such functions are known as methods. This may still look to you like unnecessary verbosity and overkill. The real power of this approach only becomes apparent when we need to override the behavior of a verification component in the context of a specific test bench or for a specific test; we can replace selected methods from the outside, without any need to modify the original source code.