• No results found

9 Register and Memory Package

8 virtual task body();

9 ‘uvm_info(get_type_name(),"Executing...", UVM_MEDIUM) 10 ‘rgm_read_by_name(lcr_reg, "uart_ctrl_rf.ua_lcr") 11 get_reg_response(req);

12 $cast(lcr_reg, req)

13 // invert the div_latch_access bit

14 lcr_reg.value.div_latch_access = !lcr_reg.value.div_latch_access;

15 ‘rgm_write_send(lcr_reg) 16 endtask

17 endclass : read_modify_write_seq

Line 10: The rgm_read_by_name call executes a read on the APB bus.

Lines 11-12: The get_response() and $cast() calls retrieve the result into the lcr_reg register.

Line 14: Then the div_latch_access field of that register is inverted.

Line 15: The rgm_write_send call will execute a write operation without randomizing the value of lcr_reg.

9.5.3 Multi-Register Sequence Operations

In many cases, you want to perform operations on a subset of registers, or on all registers in the address map or register file. For example, perhaps a certain sequence would like to write to all writable registers in a register file. To achieve this, all of the containers (register files and address map) need to provide a get_all_regs() function, as follows:

Syntax

virtual function void get_all_regs(ref uvm_rgm_register_base regs[$], input bit clone = 1);

Description

regs Returned queue of all the registers in the container

clone Returns the clone of all the registers if 1

Example 9–8 Multi-Register Sequence

The following example shows how to fetch all of the registers in an address map and read their values:

1 class read_all_reg_seq extends uvm_rgm_built_in_base_seq;

2 ‘uvm_sequence_utils(read_all_reg_seq, uvm_rgm_sequencer) 3 function new(string name="unnamed-rgm_read_all_reg_seq");

4 super.new(name);

5 endfunction

6 uvm_rgm_register_base r_list[$];

7 virtual task body();

8 ‘uvm_info(get_type_name(), "Read all registers sequence starting...") 9 uart_ctrl_rf.get_all_regs(r_list);

10 // Perform the reads 11 foreach(r_list[j]) 12 ‘rgm_read(r_list[j]) 13 endtask

14 endclass : read_all_reg_seq Notes

By default, get_all_regs() creates a copy of all registers. You can also access these registers by reference by setting the clone bit to 0. We recommend that you avoid getting a register by reference and randomizing it. Avoiding this is a good practice that prevents corruption of the shadow model and overlooking bugs.

A full set of built-in functions are provided in the uvm_rgm package. Please see the UVM Register and Memory Reference.

9.5.4 Sequences Reuse

UVM sequences are reusable, and register sequences are a perfect candidate for reuse. In module-level environments, you create multiple configuration sequences for multiple devices. In an integrated system-level environment, it is desirable to use these configuration sequences and combine them into system configuration sequences. The uvm_rgm sequences can be executed on multiple register file instances or with a different address offset in a larger system. To direct a sequence for a different location in the address hierarchy, use the set_config statement.

This insulates the body() of the sequence from becoming invalid when the hierarchical context is added to a larger address map at some offset or instance name.

9.6 Using uvm_rgm for Checking

The uvm_rgm package provides built-in checking capabilities, which are flexible enough to accommodate many checking strategy requirements.

9.6.1 Using the Shadow Model for Checking

9.6.1 Using the Shadow Model for Checking

The register model gets updated as read/write transfers are identified by the bus monitor, sent to the module UVC monitor and compared/updated against the register database shadow model.

In some cases, a register is modified by the DUT and should not be compared. In that case, you need to set the comparison mask in the IP-XACT file to zero (0). The register compare mask can be set to any value of masking and compare selected fields as needed.

9.6.2 Advanced Register Checking

Many times, the DUT will modify register values during simulation time (status registers, for example). When this is the case, the shadow model is not in sync with the actual DUT register values. Masking the comparison will remove the error message, but still the question remains:

How do we verify status registers or read-only registers? Also, a scoreboard may need to know the DUT configuration for a certain check.

This can be achieved in the following manner:

• For these types of checks, a reference model or a predictor is required to determine the expected value. This predictor can be:

• Cycle accurate, updating the shadow model to always match the DUT registers

• Partially accurate, only checking equivalency at certain times or on a subset of the registers

For implementing the reference model or for updating the shadow register model values, the uvm_rgm containers provide a set of functions to set or get register values.

9.6.2.1 Get Register Functions

The following list shows the syntax for the get_reg_by_name() and get_reg_by_addr() methods:

virtual function uvm_rgm_register_base get_reg_by_name(string name, bit clone_bit=1);

virtual function uvm_rgm_register_base get_reg_by_addr(uvm_rgm_addr_t addr, bit clone_bit=1);

Note For other get_* methods, see the uvm_rgm User Guide.

Example 9–9 Updating a Get Register Field in the Register Database

The following example demonstrates how to update a field inside of the lcr_reg register on an interrupt event signal (Users integrating an example like this could trigger the interrupt event when an interface sees the appropriate interrupt signal transition.):

1 class uart_ctrl_env extends uvm_env;

2 ...

3 event interrupt;

4 virtual task update_reg_model();

5 forever begin

6 uvm_rgm_register_base lcr_reg;

7 @interrupt;

8 lcr_reg = addr_map_ptr.uart_ctrl_rf.get_reg_by_name("ua_lcr");

9 lcr_reg.set_field_value("div_latch_access", 0);

10 end

11 endtask : update_reg_model 12 endclass

12 endclass

9.7 Updating the Register Database Model

Every operation (reads and writes) performed on the DUT’s registers through the bus, is observed by the bus monitor, which sends the transaction to the module UVC. The module UVC then performs a corresponding update, or compare (and update) of the shadow model. That way, there is constant alignment between the DUT’s status and the registers’ model, which resides inside the register database.

This task should be done by the integrator in charge of connecting the register model with the UVC.

To keep the model up to date with the DUT, do the following:

1. Update the module UVC (or create a new one if it does not exist). The module UVC is in charge of updating the register model after each transaction that is captured by the bus interface UVC monitor.

2. Using a uvm_analysis port, connect the bus interface UVC monitor to the module UVC such that the transactions collected are forwarded to the module UVC.

3. When each write transaction is received by the module UVC, the module UVC should update the register model by calling the RGM_DB update_bv() method, providing the address and data. This keeps the register model in sync with what was written into the DUT.

4. When each read transaction is received by the module UVC, the module UVC should compare the data to what is contained in the register model by calling the RGM_DB compare_and_update_bv() method. The compare_and_update_bv() method, as indicated by the name, also updates the register model to the data that was provided after the compare has taken place.

9.7.1 Updating the Module UVC

The module UVC is the component in charge of updating the register model after each interface UVC transaction related to the registers is detected. This task should be done by the integrator.

The module UVC keeps the shadow model aligned with the DUT’s register status by notifying the register model after each UVC register transaction is received. This is done by calling the update_bv() method after each write transaction and calling compare_and_update_bv() after each read transaction.

The following example shows updates to the module UVC we introduce in Chapter 10 “System UVCs and Testbench Integration” in the section “Module UVC Architecture”.

When an APB transaction is received the register model is updated according to the operation direction (read or write).

1 class uart_ctrl_env extends uvm_env;

2 // Instances of the uart_ctrl config, monitor are not shown here 3 uvm_analysis_imp #(apb_transfer, uart_ctrl_env) apb_in;

4 uart_ctrl_addr_map_c addr_map_ptr; // pointer to the address map 5 ‘uvm_component_utils(uart_ctrl_env)

6 function new (string name, uvm_component parent);

7 super.new(name, parent);

8 apb_in = new("apb_in", this);

9 endfunction

10 function void write(apb_transfer transfer);

11 if(apb_slave_cfg.check_address_range(transfer.addr)) begin

12 if (transfer.diretion == APB_WRITE) begin

20 addr_map_ptr.compare_and_update_bv(transfer.addr, transfer.data, 1);

21 end

22 else ‘uvm_error("ex_rgm_mod_uvc", "Unsupported access!!!") 23 end

24 endfunction : write 25 endclass : uart_ctrl_env

9.8 Collecting Coverage of Register Activities

Many device operation modes translate directly into register control modes. This makes register field values coverage a good indicator of a complete verification.

9.8.1 Using uvm_rgm Automatic Coverage Facilities

The uvm_rgm automatically creates coverage groups for fields that are marked to be covered by way of the vendor extensions in IP-XACT.

Syntax

<vendorExtensions:coverage_en>true</vendorExtensions:coverage_en>

Once a field is tagged for coverage, a coverage point is created in the register coverage groups.

Example 9–10 Generated Coverage Group

The following example demonstrates a generated coverage group for a register that has a default single field named value. The auto-generated coverage is collected when you call the update() or compare_and_update() routines. Just the covergroup information is shown here.

1 class ua_lcr_c extends uvm_rgm_sized_register #(8);

2 typedef struct packed {

9 covergroup compare_and_update_cg;

10 option.per_instance=1;

11 coverpoint value.char_lngth;

12 coverpoint value.num_stop_bits;

13 coverpoint value.p_en;

14 coverpoint value.div_latch_access;