In the UVM world there exists a function to reset a register block within a model. This is a step that many beginners often overlook because the need to invoke this might not be very clear until errors crop up. The register model primarily holds three different kinds of values each for a different purpose. Let's see how the
reset() method affects each of them.
The desired value stores the value we want the register to have, and a call to the
update() task will update the hardware register to match that desired value. The mirrored value always reflects the latest known value of the hardware. For example, if we do a read from a register, then the value that we read will get updated in the mirrored value. The reset value is the value a hardware register should have after coming out of reset. This is often specified when a register is instantiated within a register block.
The desired values in the model are often manipulated by
get() methods, while the mirrored values are obtained from
get_mirrored_value() function. Even the reset values can be modified by
set_reset() and retrieved later by
When a design has finished its reset stage during any simulation, we expect to see all its registers to have certain reset values. So, we would also want our register model to return appropriate reset values. For example, consider the following info statements that show the desired, mirrored and reset values of a register right after reset, by invoking appropriate methods from
UVM_INFO ./tb/test_lib.sv(52) @ 30: uvm_test_top [Reg] get=0x0 UVM_INFO ./tb/test_lib.sv(53) @ 30: uvm_test_top [Reg] has_reset=0x1 UVM_INFO ./tb/test_lib.sv(54) @ 30: uvm_test_top [Reg] get_reset=0x2c UVM_INFO ./tb/test_lib.sv(55) @ 30: uvm_test_top [Reg] get_mirrored_value=0x0 UVM_INFO ./tb/test_lib.sv(56) @ 30: uvm_test_top [Reg] needs_update=0x0
The has_reset value shows that this particular register has a reset value and the value of 0x2c is returned by a call to
get_reset(). Note that
get_mirrored_value() still returned zero which implies that you have to call the correct function based on the current state of the design. But, you don't have to if you reset the register model as well. This would avoid having to perform a read on all the registers after reset just to update the mirrored values.
class reg_model extends uvm_reg_block; ... endclass class my_test extends uvm_test; reg_model m_reg_model; virtual task reset_phase (uvm_phase phase); .. m_reg_model.reset(); ... endtask endclass
Once you do this you'll get the correct reset values from
UVM_INFO ./tb/test_lib.sv(53) @ 30: uvm_test_top [Reg] get=0x2c UVM_INFO ./tb/test_lib.sv(54) @ 30: uvm_test_top [Reg] has_reset=0x1 UVM_INFO ./tb/test_lib.sv(55) @ 30: uvm_test_top [Reg] get_reset=0x2c UVM_INFO ./tb/test_lib.sv(56) @ 30: uvm_test_top [Reg] get_mirrored_value=0x2c UVM_INFO ./tb/test_lib.sv(57) @ 30: uvm_test_top [Reg] needs_update=0x0
A word of caution : Don't simply reset the register model and design, compare the value returned from
get_reset() method with
get_mirrored_value() and declare that it passed the reset test ! It's better not to do a model reset in your reset test, because it could mask away a potential bug.