9 Register and Memory Package
44 reg_sequencer.set_container(rdb.uart_ctrl_addr)map);
45 if (!$cast(uart_ctrl0.addr_map_ptr, rdb.uart_ctrl_addr_map))
46 ‘uvm_fatal("CASTFAIL", Failed to cast the Address Map to the rdb AM") 47 // TLM port connection to module UVC for RGM update, compare and update 48 apb0.bus_monitor.item_collected_port.connect(uart_ctrl0.apb_in);
49 // Connect TLM Ports for other testbench components (not shown) 50 endfunction : connect
Notes
“Updating the Register Database Model” describes how the module UVC is used to update the shadow register database based on the bus operations seen in the bus monitor. The module UVC contains whitebox knowledge and references to the device, which enables it to make intelligent decisions about whether a value should be compared to and updated into the register database shadow. We recommend the use of a module UVC for this purpose. However, it is possible to perform that function within the testbench class by creating the analysis_imp locally in the testbench. See “Updating the Register Database Model” for more details on updating the shadow register database.
It is possible to update the database from multiple agents, as needed.
9.4.4 Reset Handling
Whenever a device is going through a hard reset, its registers are set to predefined values. In this case, the shadow registers should keep in sync with the actual values. Reset values for each field are provided in IP-XACT format and, using the IP-XACT utility, added to the uvm_rgm classes. You can reset a register, register file, or even the entire address map using the built-in reset method and specifying which type of reset to execute. The example below shows an initial shadow model reset that is typically required for all devices.
1 // Testbench task to reset the register database 2 task uart_ctrl_tb::reset_rdb();
3 forever begin
4 wait (top.reset === 1);
5 ‘uvm_info(get_type_name(), "Resetting RDB Shadow Registers", UVM_LOW) 6 rdb.uart_ctrl_addr_map.reset(uvm_rgm_hard_reset);
7 end
8 endtask : reset_rdb
9 // Start the reset_rdb() task in the testbench run() task 10 task uart_ctrl_tb::run();
Note Failing to reset the shadow model will cause a run-time error message when the first comparison between the shadow value and the actual device value takes place. This is probably the most common mistake users make in initial integration.
9.5 Controlling Register Scenarios
As part of the regular register activity, you might need to apply the following to the device:
Drive the device’s initial configuration to enable operation modes.
Drive the device’s initial configuration to enable operation modes.
The device configuration may need to be changed multiple times during a run. For example, a DMA may be configured for several different tasks on the same run.
Normal run-time operations of reading and moving values between registers and other memory locations. For example, some devices require polling status registers or serving interrupts by reading and writing to a certain register.
Users typically want to write and read registers using the register’s name or address (ideally, the register’s name, since addresses can change throughout the course of a project). Instead of inventing a new solution, uvm_rgm leverages the standard sequence mechanism. To do this, you create UVM sequences of register reads and write that leverage the uvm_rgm register operation class. This allows you to easily model read and write scenarios with the desired mix of randomness and directed operations. The following section describes basic register sequence capabilities.
9.5.1 Register Operations
The data item for register sequences is a uvm_rgm_reg_op class that contains the register, the address on which to operate, and attributes, such as direction (read or write) and the access mode (through the bus—frontdoor, or using the hdl_path—backdoor).
Note Setting the access mode to frontdoor sends a transaction on the bus to access a register. Setting the access mode to backdoor bypasses the bus logic and goes directly into the HDL signal that holds the register value. In reality, such access is not possible but it can save simulation cycles and help testing in verification.
The following code snippet shows the fields present in the uvm_rgm_reg_op class definition (accessor functions are provided but not shown here for the properties):
1 class uvm_rgm_reg_op extends uvm_sequence_item;
2 // operation hdl connection
3 protected uvm_rgm_hdl_connection_t hdl_connection = FRONTDOOR;
4 // operation address
5 protected uvm_rgm_addr_t address;
6 // operation direction
7 protected uvm_rgm_op_direction_t direction;
8 // operation register variable
9 protected uvm_rgm_register_base reg_var[$];
10 ‘uvm_object_utils_begin(uvm_rgm_reg_op) 11 ‘uvm_field_int(address, UVM_DEFAULT)
12 ‘uvm_field_enum(op_direction_t, direction, UVM_DEFAULT) 13 ‘uvm_field_object(reg_var, UVM_DEFAULT)
14 ‘uvm_object_utils_end 15 ...
16 endclass : uvm_rgm_reg_op
Note Although a register operation is executed, we are really randomizing the defined registers and their field values. For performance and capacity requirements, the register database types (rdb, address map, register file) only include the register-specific information and do not include all the rgm_reg_op fields and methods.
9.5.2 Register Read/Write Sequences
Register sequences are derived from the class uvm_rgm_sequence (created to provide additional automation and convenience when writing register sequences), which in turn is derived from the uvm_sequence. You can read or write registers by name or by address. In a register
sequence, you may need to apply constraints for constrained random tests or in a directed way, set a field to a specific value. A set of functions and macros allow you to perform register operations with or without additional constraints.
There are multiple ways to write and read registers:
Single-step operation mode, which is easiest to write and understand
Two-step operation mode (not shown here)
Low-level manual means to cause a register operation to be executed (not shown here)
Example 9–7 Register Sequence
The following example shows the single-step operation mode.
1 class rd_wr_reg_seq extends uvm_rgm_sequence;
2 ua_lcr_c lcr_reg;
3 ua_ier_c ier_reg;
4 ‘uvm_sequence_utils(rd_wr_reg_seq, user_reg_sequencer) 5 function new(string name="rd_wr_reg_seq");
6 super.new(name);
7 endfunction
8 virtual task body();
9 ‘uvm_info(get_type_name(), "Executing...", UVM_MEDIUM) 10 ‘rgm_write_by_name_with(lcr_reg, "uart_ctrl_rf.ua_lcr", 11 {value.div_latch_access == 1'b1)
12 ‘rgm_write_by_name(ier_reg, "uart_ctrl_rf.ua_ier" ) 13 #1000; // Allow time to pass or execute other sequences 14 ‘rgm_read(lcr_reg)
15 ‘rgm_read_by_name(ier_reg,"uart_ctrl_rf.ua_ier") 16 endtask
17 endclass : rd_wr_reg_seq Notes
• The rgm_write_by_name and rgm_write_by_name_with macros perform a write operation after finding the register in the string argument (“uart_ctrl_rf.ua_lcr”).
• The rgm_read macro performs a read operation using its register argument. The rgm_read_by_name() macro will find the register in the database and then execute the read into the register argument.
• Within the register database, you can traverse through the address space and register-file hierarchies and use the get_reg_by_addr for a specific register file. For example, to get the register in offset 5 within the DMA and print it, use the following code:
uvm_rgm_register_base base_reg;
base_reg = rdb.addr_map.dma_rf.get_reg_by_addr(5);
base_reg.print();
The function call returns the register at that address. When you print it, you will get all the fields defined for that register.
• To get all the registers in the register file and print, use the following code:
uvm_rgm_register_base base_regs[$];
rdb.addr_map.dma_rf.get_all_regs(base_regs);
foreach (base_regs[i]) base_regs[i].print();
get_all_regs() is a void function which returns a queue of registers via the base_regs reference argument to the function.
• You can call the get_reg_response() task to retrieve the response to a specific register read. This is shown in “Read-Modify-Write Sequence” below.
• A full set of register sequence tasks and macros can be found in the UVM Register and Memory Reference provided with the uvm_rgm register package.
9.5.2.1 Read-Modify-Write Sequence
Many times you need to read a certain address, review the field values, modify a few fields, and write the result back to the register. The following example illustrates how to create this scenario:
1 class read_modify_write_seq extends uvm_rgm_reg_sequence;
2 ua_lcr_c lcr_reg;
3 uvm_rgm_register_base reg_rsp_var;
4 ‘uvm_sequence_utils(read_modify_write_seq, reg_sequencer) 5 function new(string name="read_modify_write_seq");
6 super.new(name);
7 endfunction