By Mitesh Patel , Bonny Vora (eInfochips Ltd.)
There are two major challenges typically faced in any system design: shrinking size of the technology nodes and TTM (Time to Market). To cope with the speed of the competitive market landscape, most of the systems are designed in a generic way - which means the same design can be used in different ways with different configurations. More the number of configurations, more the number of registers in the design. On top of it, due to the high demand for data storage in the current market, memory size is also getting larger. To access and verify the numerous registers and the huge size of memory, some innovative approach is required. Therefore, UVM provides a base class library for register management and their access, called UVM RAL (Register Abstraction Layer).
UVM RAL as the name suggests, is a high-level object-oriented abstraction layer to access design registers. RAL model mimics the design registers and this entire model is fully configurable. Due to its abstraction behavior, RAL model can be easily migrated from block level to system level.
From the RAL model overview to register coverage, this paper provides different levels of information on UVM RAL - how same RAL model can be used with multiple interfaces, memory implementation inside the RAL model and their access methods, information on predictor model to predict the register value based on their operation, etc.. It has also a list of ready-made UVM register sequences. By merely configuring these sequences users can access and verify the functionality of all the design registers and memories.
The primary step of any design verification is its register verification where register accessibility and its functionality is checked. To perform this register verification it is not necessary to use UVM RAL model but when it is performed without using it, the user has to take care of each registers’ attributes and reset value. Also, the user has to make sure that each register field has been verified using all the possible values. To perform all these checks manually for the entire range of registers is a time-consuming task and therefore using the UVM RAL model is a much efficient approach.
UVM RAL is an object-oriented model for registers inside the design. To access these design registers, UVM RAL provides ready-made base classes and APIs. Some of the RAL model features are:
- Just like design, it supports different register attributes like R/W, RO, WO, W1C, etc.
- Supports two different paths for register access, frontdoor and backdoor.
- The same model can be accessed by multiple buses.
- Its abstraction nature allows the same model to be used at the block level as well as system level.
- Provides a connection to sample the user-defined coverage bins.
- Built-in comparison method to compare register value with its predicted value.
Each RAL model has majorly three levels of hierarchies:
- uvm_reg_block is the topmost hierarchy, usually, uvm_reg_block has an instance of all the registers (uvm_reg) or it may have an instance of other uvm_reg_block.
- uvm_reg mimics the register inside the design. Based on its definition each register may have one or more uvm_reg_field.
- uvm_reg_field represents the field of the register.
Figure 1. RAL hierarchy diagram
RAL model mimics the design register, value by which design register is updated, with the same value RAL model register is also updated. And for that, UVM has a common API to update both the design as well as the RAL model register. Apart from the register, design memory can also be replicated using RAL model and one of its advantages is burst operation. In the later section of this paper, an example of memory burst operation is shown followed by some information on predictor model, register coverage, and UVM pre-defined register sequences.
RAL register map and adapter
One of the essential steps of RAL model integration is the adapter class implementation. This class has two basic convert functions, bus2reg() and reg2bus(), which are used to convert the bus sequence items into uvm_reg_bus_op (known to RAL model) and vice versa. This user-defined adapter class should be implemented by extending the uvm_reg_adapter base class. This implies that all frontdoor register read/write operation happens through this adapter class. Since the implementation of the adapter class is dependent on the bus and for that, each bus has to have its own adapter class. Below code is for reference on how two APIs need to be implemented inside the adapter class:
Every frontdoor register write/read operation passes through reg2bus and bus2reg API. In the case of multiple buses, for example, APB and AXI, if they are accessing the same RAL model then adapter class needs to be created for each bus. Therefore, for each register maps, RAL model sequencer has to be set as shown below:
Example to access the RAL model register using a particular register map:
UVM supports memory implementation inside the RAL model, called uvm_mem. Like uvm_reg, the purpose of this uvm_mem is also to mimic the memory inside the design. Below code shows how memory can be implemented inside the RAL model:
One of the advantages of this memory is its burst read/write operation as shown below:
Like register, memory access can also happen through the frontdoor and backdoor. uvm_mem does not have a space to store the expected data that means one of the drawbacks of this uvm_mem is, unlike registers, it does not support in-built data comparison.
As mentioned before, the register model has a built-in self-checking mechanism. Whenever a register is accessed, uvm_reg is updated with the same value and that becomes its predicted value. This prediction can happen in three different ways:
- Implicit Prediction
- Explicit Prediction
- Passive Prediction
This is the simplest and the most common approach. Whenever register write/read operation happens, UVM RAL model base class calls predict() method of that particular uvm_reg class. And to enable this, user has to call set_auto_predict(1) method of uvm_reg_map as shown below. By default, it is disabled.
Figure 2. Implicit prediction flow
As shown in the above diagram, when auto prediction is on, the register model predicts the value with every write/read operation. Here, the expectation is that the user has to initiate register operation either by calling write() or read() method of uvm_reg.
In this approach, the user has to create the handle of uvm_reg_predictor class, which is a RAL model base class. This predictor class needs to be connected with the sampler/monitor class. Here, the monitor samples the register write/read operation happening on the interface and from the monitor it reaches to the predictor component. Predictor class converts bus transaction into the register transaction with the help of the adapter and then calls the predict() method of that register. Below diagram explains the explicit prediction flow:
Figure 3. Explicit prediction flow
In terms of coding efforts, there are three basic steps to do explicit prediction: creation, configuration, and connection.
Advantage of this approach is, here register model is always up to date with the actual data because prediction happens based on the data driven on interface. Therefore, in the case of erroneous transaction monitor needs to have a logic to filter out the data.
This approach is useful when register read/write operation is not happening via the register model. Here, register value is predicted based on the operation observed on the bus interface. This approach is very similar to the explicit prediction approach.
UVM RAL provides an API to sample the user-defined covergroup and to sample this covergroup, user has to override the sample() method of uvm_reg/uvm_reg_block class. For RAL model coverage, user has to enable register prediction as explained above.
Below code shows the covergroup implementation inside the extended uvm_reg_block where registers and their operations are covered.
Below example of covergroup implementation inside uvm_reg class is shown where the intention is to cover different values by which register is being accessed.
Selective covergroup sampling is also possible, for that, user has to provide the suitable functional coverage type identifier.
UVM RAL pre-defined sequences
UVM package provides a readymade set of sequences to test the functionality of registers such as their access or their reset value. All these sequences are unique in terms of their operation and out of them, description of a few register sequences are shown in the following table:
Checks the reset value of each register is matching with the specified reset value.
Sequentially writes 1’s and 0’s in each bit of the register and based on its read-write access, expects the value to be set.
Writes each register with frontdoor access and checks the value of the register is been set correctly via backdoor. Then do the reverse operation where write happens via backdoor and checking happens through frontdoor.
Writes walking pattern into each of the memory location and compares it with the read value.
For each location of the memory, writes via frontdoor and checks the if the value is set correctly via backdoor. Then, do the reverse operation where write happens via backdoor and verification occurs through frontdoor.
Writes all the register via each address map and confirms its written value by reading from all the address maps.
Writes all the memory locations via each address map and confirms its written value by reading from all the address maps.
Executes uvm_reg_shared_access_seq followed by uvm_mem_shared_access_seq.
Executes selected/all of the above pre-defined sequences.
Checks the specified HDL path is accessible or not.
There is a disable attribute for each of the above test, by which the user can skip particular testing of any register/memory. By setting the attribute, “NO_REG_TEST” or “NO_MEM_TEST” user can exclude particular register/memory from all the above tests.
UVM RAL is a simpler approach to access and for the verification of design registers and memories. Like the real design, uvm_mem supports burst write and read operation. On top of accessing the registers, UVM also has ready-made APIs, which can be used to sample the register coverage. Also, due to multiple scenarios in different UVM register pre-defined sequences, the task of register verification has become easy. Because of its hierarchical structure and a large number of available APIs, it provides an ample amount of flexibility. Apart from accessing APIs in the standard way, the user can do a list of other things using these APIs; such as, accessing register by their address or updating any particular register field. Overall, UVM RAL is a powerful abstraction layer, which supports all the features required for register verification and due to its organized structure, it is a highly recommended approach for register verification in the UVM based testbench.
If you wish to download a copy of this white paper, click here