Register Agent: A UVC for Register Access

The register verification process consists of access verification and functional verification. Register access verification ensures that each register can be correctly accessed in any succession of transactions, with no DUT (Design Under Test) freezing, etc. In order to achieve this, a large spectrum of transactions needs to be generated with high reaccess frequencies for the same register.

If the register access becomes divided into multiple phases, it may end up having a sequence layer and a driving layer. The driving layer is something closely connected to the physical interface used to drive the register access, thus it will basically differ from one design/implementation to another. However, the sequence layer is more like an abstract operation that almost always does the same thing, even if we change the DUT. The only difference observed when changing the DUT is that the sequence layer operates on different sets of registers for each DUT. I saw here an opportunity for a UVC (Universal Verification Component) that could automate operations performed from this sequence layer.

The Register Agent is a UVC that is ready to be used by the verification environment. It is a “plug and play”, portable and universal component. The main feature of this UVC consists of a sequence library. This library contains configurable sequences for every register type and register access order.

Table of contents

UVC requirements

Here is a set of requirements established before starting to develop the Register Agent UVC:

  • Provide access to a wide range of sequences to be used when accessing registers
  • Provide a reaccess option for every register access (ability to access the same register multiple times)
  • Provide various register write patterns for use in checking that all bits in the register are toggling properly
  • Provide an option to specify a set of registers that should NOT be accessed. The user should be able to specify a partial string match mechanism for the name of the registers to avoid
  • Provide access to a coverage component designed to collect information about scenarios that have been driven
  • Provide an option to access unmapped address ranges

The Register Agent UVC architecture was chosen so as to fulfill the above requirements.


The structure of the Register Agent is similar to any other UVM (Universal Verification Methodology) agent. Its main class, amiq_reg_agent, extends uvm_agent and contains handlers to the following sub components and objects:

  • amiq_reg_agent_cfg_object
  • amiq_reg_sequencer
  • amiq_reg_agent_coverage_collector

The Register Agent also includes a uvm_reg_block reference. This reference must be set by the user and represents a storage location where the register agent searches for the next registers to access.

A graphical representation of the data flow when using the Register Agent is shown below:

Fig. 1. Data flow through the VE

Every register access is performed using the uvm_reg read() and write() functions. Whenever a register sequence requests a register access, the UVM RAL (Register Abstraction Layer) mechanism implemented by the verification engineer must adapt and drive the reg_item according to the protocol implemented by the DUT interface. The collected item should also be adapted to RAL and sent from uvm_reg_predictor to the coverage collector.

Sequence Library

As mentioned above, the Register Agent implements a series of sequences used in register access. Here is a list and a short description of those sequences:

  • amiq_reg_rwr_seq – access all registers in Read-Write-Read order;
  • amiq_reg_random_read_seq – reads every register in a shuffled order;
  • amiq_reg_random_seq – randomize both the access type and the register order. Do this for a random number of times
  • amiq_reg_walking_1_seq – performs a walking 1 sequence, toggling every bit of every register;
  • amiq_reg_unmapped_seq – access of every block of unmapped addresses in the following way: min_address, random_in_between_address, and max_address. Every selected address is accessed in Read-Write-Read order;
  • amiq_reg_all_unmapped_seq – access every address of unmapped space in Read-Write-Read order;
  • amiq_reg_main_seq – sequence that runs the following four upper sequences: amiq_reg_rwr_seq, amiq_reg_random_seq, amiq_reg_walking_1_seq, and amiq_reg_unmapped_seq. When constraining fields of amiq_reg_main_seq those constraints will apply to all four sub-sequences.

    The total number of register accesses is linearly dependent on the number of registers and also depends on the configuration (probability to start a new reg access or not).

    The probability of accessing a register more than once (reaccess) is given by a geometric distribution with stopping probability of 1-P (P is the reaccess probability field and its value is set by the user). Taking into consideration only the reaccess probability for each register, the average number of accesses are:



    • x =- number of accesses simulating a sequence;
    • rn =- number of registers;
    • P =- reaccess probability;

Instantiation and usage

By using the Register Agent UVC, the verification of register accesses is made complete and automated. Even though the solution is scalable and can support a large number of registers, it is recommended to split the verification of registers by creating multiple groups based on functionality or address ranges.

The Register Agent performs a basic check of the sequence configuration and can trigger multiple warnings in the event that it observes high probabilities of reaccess and access to other registers. This is because the simulation time will grow linearly with the number of registers and could potentially lead to a test case timeout.
Before instantiating and starting the Register Agent sequences, several steps must first be performed on the verification environment:

  • Create the Register Abstraction Layer (Register Block, Adapter, Predictor). It is the user’s responsibility to correctly implement the architecture specific to its environment;
  • Include the amiq_reg_agent_pkg in the environment package, in order for the agent to be visible in the environment;
    import amiq_reg_agent_pkg::*;
  • Create and assign the Register Agent Configuration Object through uvm_config_db with field_name = “amiq_reg_agent_cfg_object”.
    reg_agent_cfg = amiq_reg_agent_cfg_object::type_id::create("reg_agent_cfg");
    //configure reg_agent_cfg fields;
    uvm_config_db#(amiq_reg_agent_cfg_object)::set(null, "*", "amiq_reg_agent_cfg_object", reg_agent_cfg);
  • Instantiate the Register Agent in the build_phase of the environment;
    reg_agent = amiq_reg_agent::type_id::create("reg_agent", this);
  • Assign the Register Block handle to the reg_block field of the agent, in the connect_phase;
    reg_agent.reg_block = reg_block;
  • If the has_coverage field of Register Agent Configuration Object is set, the user must connect the predictor’s base port reg_ap to the reg_item_imp port of the agent’s coverage collector, at connect_phase;

Next, the user must do the following:

  • Instantiate a sequence from the library
  • Constrain sequence fields in order to determine the type of access pattern
  • Start the sequence amiq_reg_rwr_seq rwr_seq;
    1. Starting a sequence without elements in the pattern_queue: the easiest way of starting a sequence is using the uvm macro:`uvm_do_on_with
      `uvm_do_on_with(rwr_seq, reg_agent.sequencer,{
        reaccess_register_knob == 1;
        do_first_read == 1;
        do_write == 1;
        do_second_read == 1;
        default_pattern == local::default_pattern;
        max_number_of_iteration == 100;
        min_number_of_iteration == 10;})
    2. Starting a sequence with elements in the pattern_queue:
      rwr_seq = amiq_reg_rwr_seq::type_id::create("rwr_seq");            
      rwr_seq.randomize() with {
        reaccess_register_knob == 1;
        do_first_read == 1;					
        do_write == 1;						
        do_second_read == 1;					
        default_pattern == local::default_pattern;		
        max_number_of_iteration == 100;		
        min_number_of_iteration == 10;
      repeat(number_of_patterns) begin
        uvm_reg_data_t pattern;


The Register Agent also provides a coverage definition, based on the register block, in order to be able to observe the type of register access and the addresses which have been accessed. This makes it easier for the user to collect information about the driven scenarios.

The coverage consists of one covergroup, which samples the uvm_reg_item provided by the predictor on the monitoring data flow. Here is a list of elements existing in the covergroup:

  1. register_addr_cp: a coverpoint containing the addresses of registers in the register block including the registers the agent will not access due to the configuration provided by the user. Removing these is best suited to the refinement phase;
  2. register_access_kind_cp: a coverpoint containing information about the access types that have been driven and the transitions between them;
  3. access_on_every_address_cr: a cross between the previous two coverpoints that ensures every kind of access has been driven on the same address.
  4. walking_1_cp: a coverpoint containing the positions of the toggle bit in the walking 1 pattern.
  5. walking_1_on_every_address_cr: a cross between walking_1_cp and register_addr_cp that ensures the walking 1 pattern has been driven for every address.


The proposed solution aims to ease the process of verifying DUT registers by providing the following:

  • Register accessibility
  • Reusability
  • Simplified RAL architecture
  • Code modularity

By using the Register Agent the verification engineer is able to shorten development time and will not need to redefine register access sequences for each DUT.

The coverage definition inside the Register Agent is another key element in terms of the reusability of the code because it offers information about the access (address, type, and bits toggled individually).

This project fulfills all the requirements listed at the beginning of this article. The Register Agent is a universal verification component that is reconfigurable for every type of register access, while also providing a framework for additional functionality.

Please join this project so that it will benefit all of the verification community.


You may download the source code from AMIQ Github. Feel free to contribute by leaving a comment, ask for improvements or update the code yourself.


One Response

  1. Interesting development.

    I’m a bit concerned though how does the component know that an unmapped register access should report an error at the physical level.

    Assume you have an APB interface and you want to go through all your registers, usually any unmapped register should be causing the perror to assert and your APB VIP should know that.

    Is there a mechanism to make sure that any unmapped register is correctly reporting the failure? Usually the APB VIP doesn’t have any notion of what is the register map, so it can’t possibly predict that a register access should result in a failure.

    Any suggestions?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to our newsletter

Do you want to be up to date with our latest articles?