Deep Dive into UVM Register Model
UVM Register Model, a key component of the Universal Verification Methodology (UVM), is a standardized methodology for verifying digital designs. It provides a framework for creating robust and reusable testbenches in the field of hardware verification. One essential aspect of UVM is its Register Abstraction Layer (RAL), which enables efficient verification of register-rich designs. In this article, we’ll take a closer look at the UVM Register Model and explore its key components and concepts.
Register Abstraction Layer (RAL)
The UMV Register Layer is designed to model and verify register-based functionalities in a design. This includes registers, memory-mapped registers, and the associated fields within those registers. The primary purpose of RAL is to provide a systematic and efficient way of accessing and manipulating registers during verification.
RAL Model in UVM Environment
The UVM environment is a collection of components, including the generator, sequences, register model, and other testbench components. It provides a structured and modular framework for organizing and managing the verification process. The environment coordinates the generation of stimuli, checking of responses, and collection of coverage data.
The generator, often referred to as the register model generator, is responsible for automatically creating the register model based on a specification provided by the design team. It takes the register description (register map) of the DUT and generates the corresponding UVM register model.
Sequences in the RAL context are sets of register transactions that define specific operations on the registers, such as read and write operations. Sequences encapsulate the desired register behavior and are used to generate realistic test scenarios for the DUT.
The register model, built using UVM’s RAL classes (uvm_reg and uvm_reg_field), represents the hierarchical structure of registers and their fields within the DUT. It includes information about register properties, such as names, widths, access policies, reset values, and more.
The DUT is the digital design that is being verified. It includes the actual hardware or digital logic that implements the functionality specified by the design team. The DUT is the target of the verification process, and the goal is to ensure that it operates according to its specifications.
Classes of UVM Register Model
Classes are part of the UVM Register Abstraction Layer (RAL). These classes are used to model and verify hardware registers and their fields within the design under test (DUT). The RAL provides a standardized way to interact with registers and facilitates the creation of reusable and scalable register verification environments.
Class | Description |
uvm_reg_field | Used for register field implementation |
uvm_reg | Used to implement design register |
uvm_reg_file | Used to collect a group of registers |
uvm_reg_map | Represents an address map |
uvm_mem | Used to represent memory in design |
uvm_reg_block | Container class to store registers, maps and memories |
Table 1: Classes of UVM register model
- uvm_reg_field :
“uvm_reg_field” is a class that is used to model individual fields within a register. They encapsulate the behavior and attributes of specific portions of a register, such as access type (read/write), reset values, and more. - uvm_reg :
“uvm_reg” is a fundamental unit in the UVM Register Model. It represents a hardware register in the design. Each register has properties such as name, address, and size. Registers are the building blocks that encapsulate the control and status information of a design.
Example :-
class Block1_Reg1 extends uvm_reg; `uvm_object_utils(Block1_Reg1) rand uvm_reg_field F1;/**/ rand uvm_reg_field F2;/**/ // Function : new function new(string name = "Block1_Reg1"); super.new(name, 32, build_coverage(UVM_NO_COVERAGE)); add_coverage(build_coverage(UVM_NO_COVERAGE)); endfunction // Function : build virtual function void build(); this.F1 = uvm_reg_field::type_id::create("F1"); this.F1.configure(.parent(this), .size(16), .lsb_pos(16), .access("RW"), .volatile(0), .reset(16'd0), .has_reset(1), .is_rand(1), .individually_accessible(0)); this.F2 = uvm_reg_field::type_id::create("F2"); this.F2.configure(.parent(this), .size(16), .lsb_pos(0), .access("RW"), .volatile(0), .reset(16'd0), .has_reset(1), .is_rand(1), .individually_accessible(0)); endfunction endclass
- uvm_reg_block:
“uvm_reg_block” can contain registers, register files, memories and sub-blocks. Register blocks are used to organize registers into hierarchical structures. This is particularly useful for modeling complex designs with multiple levels of hierarchy. A register block typically represents a module or subsystem in the design.
Example :-
class Block1_block extends uvm_reg_block; `uvm_object_utils(Block1_block) rand Block1_Reg1 Reg1; // Function : new function new(string name = "Block1_block"); super.new(name, UVM_NO_COVERAGE); endfunction // Function : build virtual function void build(); //define default map and add reg/regfiles default_map= create_map("default_map", 'h0, 4, UVM_BIG_ENDIAN, 1); //REG1 Reg1 = Block1_Reg1::type_id::create("Reg1"); Reg1.configure(this, null, "Reg1"); Reg1.build(); default_map.add_reg( Reg1, 'h0, "RW"); lock_model(); endfunction endclass
Register Sequences and Tests
In UVM register sequences and tests are used to model and verify the desired behavior of registers and their interactions. Register sequences define specific sequences of register operations, such as read, write, or modify operations.
class my_sequence extends uvm_sequence #(my_register); `uvm_object_utils(my_sequence) task body(); // Register access operations endtask endclass
UVM Register Layer API
The UVM Register Layer API also provides a set of methods for performing register operations, such as reading, writing, and checking register values. Some commonly used methods include:
- read/write: The normal access APIs are the read() and write() methods. “read” API is used to read the current value of a register and the “write” API is used to write a new value to a register.
- peek/poke: Using the peek() and poke() methods reads or writes directly to the register respectively, which bypasses the physical interface.
- get/set: Using the get() and set() methods reads or writes directly to the desired mirrored value respectively, without accessing the DUT.
- randomize: Using the randomize() method copies the randomized value in the uvm_reg_field::value property into the desired value of the mirror by the post_randomize() method.
- update: Using the update() method invokes the write() method if the desired value (previously modified using set() or randomize()) is different from the mirrored value
mirror: Using the mirror() method invokes the read() method to update the mirrored value based on the readback value. mirror() can also compare the readback value with the current mirrored value before updating it.
Conclusion
The UVM Register Model is a powerful feature of the UVM methodology, providing an effective way to model and verify register-based designs. By utilizing registers, fields, and register blocks, engineers can create comprehensive and reusable testbenches for thorough verification of hardware designs. Understanding the key components and concepts of the UVM Register Model is crucial for achieving successful and efficient verification in modern digital design projects.
This article has provided a glimpse into the UVM Register Model, but there is much more to explore and understand. As you delve deeper into UVM-based verification, you’ll discover additional features and techniques that contribute to building robust and scalable testbenches for complex digital designs.