UVM/UVM Tutorial for Candy Lovers/Register Access Methods — различия между версиями
ANA (обсуждение | вклад) (Новая страница: «{{UVM TOC}} The register abstraction layer (RAL) of UVM provides several methods to access registers. This post will explain how the register-access methods work…») |
ANA (обсуждение | вклад) |
||
| Строка 4: | Строка 4: | ||
Регистр уровень абстракции (RAL) из УВМ предоставляет несколько методов для доступа к регистрам. Это сообщение будет объяснить, как методы регистров доступа работать. Регистрация Абстракция, мы ввели обзор RAL и объяснил, как определить регистры. В этой статье мы рассмотрим, как получить доступ к регистрам. | Регистр уровень абстракции (RAL) из УВМ предоставляет несколько методов для доступа к регистрам. Это сообщение будет объяснить, как методы регистров доступа работать. Регистрация Абстракция, мы ввели обзор RAL и объяснил, как определить регистры. В этой статье мы рассмотрим, как получить доступ к регистрам. | ||
| + | |||
| + | == Properties of uvm_reg_field == | ||
| + | |||
| + | Before diving into the register-access methods, let’s look at how a register value is stored. As seen in [http://cluelogic.com/2012/10/uvm-tutorial-for-candy-lovers-register-abstraction/ Register Abstraction], <code>uvm_reg_field</code> is the lowest register-abstraction layer which represents the bits of a register. The <code>uvm_reg_field</code> uses several properties to store a variety of register-field values: | ||
| + | |||
| + | * <code>m_reset["HARD"]</code> stores a hard reset value. Note that the <code>m_reset</code> is an associative array with a kind of reset as the key. | ||
| + | * <code>m_mirrored</code> stores the value of what we ''think'' in our design under test (DUT). | ||
| + | * <code>m_desired</code> stores the value of what we ''want'' to set to the DUT. | ||
| + | * <code>value</code> stores the value to be sampled in a functional coverage, or the value to be constrained when the field is randomized. | ||
| + | |||
| + | Note that among these properties, only the <code>value</code> property is public. The other properties are local, thus we cannot access them directly from the out side of the class. We will show you how to access these local properties using register-access methods later. | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img alt="Properties of uvm_reg_field" src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_reg_field_properties.png" width="800" /> | ||
| + | </html> | ||
| + | |- | ||
| + | !Properties of uvm_reg_field | ||
| + | |} | ||
| + | |||
| + | |||
| + | === configure() === | ||
| + | |||
| + | The first thing we do after creating a <code>uvm_reg_field</code> is configuring it. In [http://cluelogic.com/2012/10/uvm-tutorial-for-candy-lovers-register-abstraction/ Register Abstraction], we configured the <code>flavor</code> field as follows. Note that in [http://cluelogic.com/2012/10/uvm-tutorial-for-candy-lovers-register-abstraction/ Register Abstraction], we defined the <code>flavor</code> field as <code>"WO"</code> (write-only), but we defined it as <code>"RW"</code> (read/write) here to make the field more generic. | ||
| + | |||
| + | <div> | ||
| + | {| | ||
| + | |- | ||
| + | | <pre>1 | ||
| + | 2 | ||
| + | 3 | ||
| + | 4 | ||
| + | 5 | ||
| + | 6 | ||
| + | 7 | ||
| + | 8 | ||
| + | 9 | ||
| + | 10 | ||
| + | </pre> | ||
| + | | <pre>flavor = uvm_reg_field::type_id::create( "flavor" ); | ||
| + | flavor.configure( .parent ( this ), | ||
| + | .size ( 3 ), | ||
| + | .lsb_pos ( 0 ), | ||
| + | .access ( "RW" ), | ||
| + | .volatile ( 0 ), | ||
| + | .reset ( 0 ), | ||
| + | .has_reset ( 1 ), | ||
| + | .is_rand ( 1 ), | ||
| + | .individually_accessible( 0 ) );</pre> | ||
| + | |} | ||
| + | </div> | ||
| + | |||
| + | If the <code>has_reset</code> argument is <code>1</code>, the value of <code>reset</code> argument is taken as the <code>"HARD"</code> reset value. If the <code>has_reset</code> value is <code>0</code>, the value of <code>reset</code> is ignored. The value of <code>reset</code> should match the reset state of the DUT. If you want to modify the reset value after the configuration, you can use <code>set_reset()</code> method. | ||
| + | |||
| + | <div> | ||
| + | {| | ||
| + | |- | ||
| + | | <pre>flavor.set_reset( .value( 0 ), .kind( "HARD" ) ); // kind == "HARD" by default</pre> | ||
| + | |} | ||
| + | </div> | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img src="http://cluelogic.com/wp-content/uploads/2013/02/jb16_configure.png" width="800" /></html> | ||
| + | |- | ||
| + | ! How configure() and set_reset() methods work | ||
| + | |} | ||
| + | |||
| + | |||
| + | === reset() === | ||
| + | |||
| + | The <code>reset()</code> method resets the properties of a register field, if the <code>m_reset[kind]</code> exists. The default <code>kind</code> is <code>"HARD"</code>. If the <code>m_reset[kind]</code> does not exist, the <code>reset()</code> method does nothing. Note that the <code>reset()</code> method '''does not''' reset a register in the DUT. It only resets the properties of a register-field object. | ||
| + | |||
| + | <div> | ||
| + | {| | ||
| + | |- | ||
| + | | <pre>flavor.reset( .kind( "HARD" ) ); // kind == "HARD" by default</pre> | ||
| + | |} | ||
| + | </div> | ||
| + | |||
| + | |||
| + | </div> | ||
| + | {| | ||
| + | !<html><img src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_reset.png" width="800" /></html> | ||
| + | |- | ||
| + | ! How the reset() method works | ||
| + | |} | ||
| + | |||
| + | === set() === | ||
| + | |||
| + | The <code>set()</code> method sets the desired value of a register field. The <code>set()</code> method '''does not''' set the value to a register in the DUT. It only sets the value to the <code>m_desired</code> and the <code>value</code> properties of a register-field object. To actually set the value to the register in the DUT, use <code>write()</code> or <code>update()</code> method. These methods will be explained later. | ||
| + | |||
| + | <div> | ||
| + | {| | ||
| + | |- | ||
| + | | <pre>flavor.set( .value( 1 ) );</pre> | ||
| + | |} | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img alt="How the set() method works" src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_set.png" width="800" /></html> | ||
| + | |- | ||
| + | ! How the set() method works | ||
| + | |} | ||
| + | |||
| + | |||
| + | === get() === | ||
| + | |||
| + | The <code>get()</code> method gets the desired value of a register field. The <code>get()</code> method '''does not''' get the value from a register in the DUT. It only gets the value of the <code>m_desired</code> property. To actually get the value from the DUT, use <code>read()</code> or <code>mirror()</code> methods. These methods will be explained later. Similarly to the <code>get()</code> method, there are two more ''getters'' to access the local properties. The <code>get_reset()</code> retrieves the value of the <code>m_reset[kind]</code> property, while the <code>get_mirrored_value()</code> method retrieves the value of the <code>m_mirrored</code> property. | ||
| + | |||
| + | {| | ||
| + | |- | ||
| + | | <pre>uvm_reg_data_t desired_value = flavor.get(); | ||
| + | uvm_reg_data_t reset_value = flavor.get_reset( .kind( "HARD" ) ); // kind == "HARD" by default | ||
| + | uvm_reg_data_t mirrored_value = flavor.get_mirrored_value();</pre> | ||
| + | |} | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img alt="How the get(), get_reset(), and get_mirrored_value() methods work" src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_get.png" width="800" /></html> | ||
| + | |- | ||
| + | ! How the get(), get_reset(), and get_mirrored_value() methods work | ||
| + | |} | ||
| + | |||
| + | |||
| + | === randomize() === | ||
| + | |||
| + | The <code>randomize()</code> method is a SystemVerilog method. It randomizes the <code>value</code> property of a register-field object. After the randomization, the <code>post_randomize()</code> method copies the value of the <code>value</code> property to the <code>m_desired</code> property. Note that the <code>pre_randomize()</code> method copies the value of the <code>m_desired</code> to the <code>value</code> property if the <code>rand_mode</code> of the <code>value</code> property is <code>OFF</code>. | ||
| + | |||
| + | {| | ||
| + | |- | ||
| + | | <pre>assert( flavor.randomize() );</pre> | ||
| + | |} | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img alt="How the randomize() method works" src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_randomize.png" width="800" /></html> | ||
| + | |- | ||
| + | ! How the randomize() method works | ||
| + | |} | ||
| + | |||
| + | |||
| + | === write() === | ||
| + | |||
| + | The <code>write()</code> method actually writes a value to the DUT. | ||
| + | |||
| + | <div> | ||
| + | {| | ||
| + | |- | ||
| + | | <pre>uvm_status_e status; | ||
| + | |||
| + | flavor.write( .status( status ), .value( 1 ) );</pre> | ||
| + | |} | ||
| + | </div> | ||
| + | |||
| + | The <code>write()</code> method involves multiple steps. | ||
| + | |||
| + | # A <code>uvm_reg_item</code> object corresponding to the write operation is created. | ||
| + | # The <code>uvm_reg_adapter</code> converts the write operation to a corresponding bus transaction. | ||
| + | # The <code>uvm_driver</code> executes the bus transaction to the DUT. | ||
| + | # The <code>uvm_monitor</code> captures the bus transaction. | ||
| + | # The <code>uvm_reg_predictor</code> asks the <code>uvm_reg_adapter</code> to convert the bus transaction to a corresponding register operation. | ||
| + | # The register operation is converted to a <code>uvm_reg_item</code>. | ||
| + | # The <code>uvm_reg_item</code> is used to update the <code>value</code>, <code>m_mirrored</code>, and <code>m_desired</code> properties. | ||
| + | |||
| + | Note that if the <code>individually_accessible</code> argument was <code>0</code> when the register field was configured, the entire register containing the field is written, because the field is not individually accessible. In this case, the <code>m_mirrored</code> values are used as the write values for the other fields. | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img alt="How the write() method works" src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_write.png" width="800" /></html> | ||
| + | |- | ||
| + | ! How the write() method works | ||
| + | |} | ||
| + | |||
| + | |||
| + | === read() === | ||
| + | |||
| + | The read() method actually reads a register value from the DUT. | ||
| + | |||
| + | <div> | ||
| + | {| | ||
| + | |- | ||
| + | | <pre>uvm_status_e status; | ||
| + | uvm_reg_data_t value; | ||
| + | |||
| + | flavor.read( .status( status ), .value( value ) );</pre> | ||
| + | |} | ||
| + | </div> | ||
| + | |||
| + | Similarly to the <code>write()</code> method, the <code>read()</code> method involves multiple steps. | ||
| + | |||
| + | # A <code>uvm_reg_item</code> object corresponding to the read operation is created. | ||
| + | # The <code>uvm_reg_adapter</code> converts the read operation to a corresponding bus transaction. | ||
| + | # The <code>uvm_driver</code> executes the bus transaction to the DUT. | ||
| + | # The <code>uvm_reg_apapter</code> converts the bus transaction with read data to a register operation. | ||
| + | # The <code>read()</code> method returns the read value to the caller. | ||
| + | # In the mean time, the <code>uvm_monitor</code> captures the bus transaction. | ||
| + | # The <code>uvm_reg_predictor</code> asks the <code>uvm_reg_adapter</code> to convert the bus transaction to a corresponding register operation. | ||
| + | # The register operation is converted to a <code>uvm_reg_item</code>. | ||
| + | # The <code>uvm_reg_item</code> is used to update the <code>value</code>, <code>m_mirrored</code>, and <code>m_desired</code> properties. | ||
| + | |||
| + | Note that if the <code>individually_accessible</code> argument was <code>0</code> when the register field was configured, the entire register containing the field is read. In this case, the <code>m_mirrored</code> values are updated for the other fields as well. | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img alt="How the read() method works" src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_read.png" width="800" /></html> | ||
| + | |- | ||
| + | ! How the read() method works | ||
| + | |} | ||
| + | |||
| + | |||
| + | === update() === | ||
| + | |||
| + | The <code>update()</code> method actually writes a register value to the DUT. The <code>update()</code> method belongs to the <code>uvm_reg</code> class. The <code>uvm_reg_field</code> class does not have the <code>update()</code> method. | ||
| + | |||
| + | <div> | ||
| + | {| | ||
| + | |- | ||
| + | | <pre>uvm_status_e status; | ||
| + | |||
| + | jb_recipe_reg.update( .status( status ) );</pre> | ||
| + | |} | ||
| + | </div> | ||
| + | |||
| + | The differences between the <code>write()</code> method and the <code>update()</code> method are: | ||
| + | |||
| + | * The <code>write()</code> method takes a value as its argument, while the <code>update()</code> method uses the value of the <code>m_desired</code> property as the value to write. | ||
| + | * The <code>update()</code> method writes the value only if the <code>m_mirrored</code> and the <code>m_desired</code> are not equal. | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img alt="Before the update() is executed" src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_before_update.png" width="800" /></html> | ||
| + | |- | ||
| + | ! Before the update() is executed | ||
| + | |} | ||
| + | |||
| + | |||
| + | The <code>update()</code> method internally calls the <code>write( .value( m_desired ) )</code>. Because of this, the value of the <code>m_mirrored</code> will be updated as well, after the update. | ||
| + | |||
| + | <div>[http://cluelogic.com/wp-content/uploads/2013/01/jb16_after_update.png [[Файл:jb16_after_update.png|1951px|After update()]]] | ||
| + | |||
| + | After the update() is executed | ||
| + | </div> | ||
| + | |||
| + | |||
| + | === mirror() === | ||
| + | |||
| + | The <code>mirror()</code> method actually reads a register from the DUT. | ||
| + | |||
| + | <div> | ||
| + | {| | ||
| + | |- | ||
| + | | <pre>uvm_status_e status; | ||
| + | |||
| + | flavor.mirror( .status( status ), .check( UVM_CHECK ) );</pre> | ||
| + | |} | ||
| + | </div> | ||
| + | |||
| + | The differences between the <code>read()</code> method and the <code>mirror()</code> method are: | ||
| + | |||
| + | * The <code>read()</code> method returns the register value to the caller, while the <code>mirror()</code> method does not return the register value. The <code>mirror()</code> method only updates the value of the <code>m_mirrored</code> property. | ||
| + | * The <code>mirror()</code> method compares the read value against the <code>m_desired</code> if the value of the <code>check</code> argument is <code>UVM_CHECK</code>. <del>Note that the UVM Class Library document states that it compares the read value against the mirrored value, but if you look at the line 2,944 of <code>uvm_reg.svh</code> of uvm-1.1c code base, it actually compares against the desired value, not against the mirrored value.</del> '''(Update 4/11/2014: uvm-1.1d code base has corrected this issue. The <code>mirror()</code> compares the read value against the mirrored value now. Please see the line 2,951 of <code>uvm_reg.svh</code> if you are curious about this fix.)''' Another caveat about the check is that if you set the <code>volatile</code> argument to be <code>1</code> when you configured the register field, the register field won’t be checked even though you set the <code>check</code> argument to be <code>UVM_CHECK</code>. This is because we cannot predict the value of the register field deterministically as it might have been changed (volatile) in the DUT. | ||
| + | |||
| + | The <code>mirror()</code> method internally calls <code>do_read()</code> method. This is the same method the <code>read()</code> method internally calls. Because of this, the <code>mirror()</code> method will update the <code>value</code> and the <code>m_desired</code> properties, in addition to the <code>m_mirrored</code> property. | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img alt="How the mirror() method works" src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_mirror.png" width="800" /></html> | ||
| + | |- | ||
| + | ! How the mirror() method works | ||
| + | |} | ||
| + | |||
| + | |||
| + | === predict() === | ||
| + | |||
| + | The <code>predict()</code> method updates the mirrored value. | ||
| + | |||
| + | <div> | ||
| + | {| | ||
| + | |- | ||
| + | | <pre>flavor.predict( .value( 1 ) );</pre> | ||
| + | |} | ||
| + | </div> | ||
| + | |||
| + | The <code>predict()</code> method also updates the <code>value</code> and the <code>m_desired</code> properties. | ||
| + | |||
| + | |||
| + | {| | ||
| + | !<html><img alt="How the predict() method works" src="http://cluelogic.com/wp-content/uploads/2013/01/jb16_predict.png" width="800" /></html> | ||
| + | |- | ||
| + | ! How the predict() method works | ||
| + | |} | ||
| + | |||
| + | |||
| + | === Summary === | ||
| + | |||
| + | The table below summarizes how each method updates the properties of the register-field object. | ||
| + | |||
| + | <div> | ||
| + | {| border="1" | ||
| + | ! Method | ||
| + | ! <code>m_reset | ||
| + | ["HARD"]</code> | ||
| + | ! <code>value</code> | ||
| + | ! <code>m_desired</code> | ||
| + | ! <code>m_mirrored</code> | ||
| + | ! DUT | ||
| + | |- | ||
| + | | <code>configure( | ||
| + | .reset(val), | ||
| + | .has_reset(1))</code> | ||
| + | | set the value of <code>val</code> | ||
| + | | | ||
| + | | | ||
| + | | | ||
| + | | | ||
| + | |- | ||
| + | | <code>set_reset(val)</code> | ||
| + | | set the value of <code>val</code> | ||
| + | | | ||
| + | | | ||
| + | | | ||
| + | | | ||
| + | |- | ||
| + | | <code>reset()</code> | ||
| + | | | ||
| + | | copy the value of <code>m_reset | ||
| + | ["HARD"]</code> | ||
| + | | copy the value of <code>m_reset | ||
| + | ["HARD"]</code> | ||
| + | | copy the value of <code>m_reset | ||
| + | ["HARD"]</code> | ||
| + | | | ||
| + | |- | ||
| + | | <code>set(val)</code> | ||
| + | | | ||
| + | | set the value of <code>val</code> | ||
| + | | set the value of <code>val</code> | ||
| + | | | ||
| + | | | ||
| + | |- | ||
| + | | <code>get_reset()</code> | ||
| + | | return the value of <code>m_reset | ||
| + | ["HARD"]</code> | ||
| + | | | ||
| + | | | ||
| + | | | ||
| + | | | ||
| + | |- | ||
| + | | <code>get()</code> | ||
| + | | | ||
| + | | | ||
| + | | return the value of <code>m_desired</code> | ||
| + | | | ||
| + | | | ||
| + | |- | ||
| + | | <code>get_mirrored_value()</code> | ||
| + | | | ||
| + | | | ||
| + | | | ||
| + | | return the value of <code>m_mirrored</code> | ||
| + | | | ||
| + | |- | ||
| + | | <code>randomize()</code> | ||
| + | | | ||
| + | | randomize | ||
| + | | copy the value of <code>value</code> | ||
| + | | | ||
| + | | | ||
| + | |- | ||
| + | | <code>write(.value(val))</code> | ||
| + | | | ||
| + | | set the value of <code>val</code> | ||
| + | | set the value of <code>val</code> | ||
| + | | set the value of <code>val</code> | ||
| + | | write the value of <code>val</code> | ||
| + | |- | ||
| + | | <code>read(.value(val))</code> | ||
| + | | | ||
| + | | set the read value | ||
| + | | set the read value | ||
| + | | set the read value | ||
| + | | read the register | ||
| + | |- | ||
| + | | <code>update()</code> | ||
| + | | | ||
| + | | set the value of <code>m_desired</code> | ||
| + | | set the value of <code>m_desired</code> | ||
| + | | set the value of <code>m_desired</code> | ||
| + | | write the value of <code>m_desired</code> | ||
| + | |- | ||
| + | | <code>mirror()</code> | ||
| + | | | ||
| + | | set the read value | ||
| + | | set the read value | ||
| + | | set the read value | ||
| + | | read the register | ||
| + | |- | ||
| + | | <code>predict( | ||
| + | .value(val))</code> | ||
| + | | | ||
| + | | set the value of <code>val</code> | ||
| + | | set the value of <code>val</code> | ||
| + | | set the value of <code>val</code> | ||
| + | | | ||
| + | |} | ||
| + | </div> | ||
| + | In this post, we only covered so-called front-door access. We will cover back-door access in a separate post. I hope this tutorial helped you to understand the register access methods. | ||
Версия 12:53, 15 ноября 2014
- Sequences
- Analysis Components & Techniques
- UVM Tutorial for Candy Lovers
- Register Access Methods (link)
- Использование Register model
The register abstraction layer (RAL) of UVM provides several methods to access registers. This post will explain how the register-access methods work. In Register Abstraction, we introduced the overview of RAL and explained how to define registers. In this post, we will cover how to access the registers.
Регистр уровень абстракции (RAL) из УВМ предоставляет несколько методов для доступа к регистрам. Это сообщение будет объяснить, как методы регистров доступа работать. Регистрация Абстракция, мы ввели обзор RAL и объяснил, как определить регистры. В этой статье мы рассмотрим, как получить доступ к регистрам.
Содержание |
Properties of uvm_reg_field
Before diving into the register-access methods, let’s look at how a register value is stored. As seen in Register Abstraction, uvm_reg_field is the lowest register-abstraction layer which represents the bits of a register. The uvm_reg_field uses several properties to store a variety of register-field values:
-
m_reset["HARD"]stores a hard reset value. Note that them_resetis an associative array with a kind of reset as the key. -
m_mirroredstores the value of what we think in our design under test (DUT). -
m_desiredstores the value of what we want to set to the DUT. -
valuestores the value to be sampled in a functional coverage, or the value to be constrained when the field is randomized.
Note that among these properties, only the value property is public. The other properties are local, thus we cannot access them directly from the out side of the class. We will show you how to access these local properties using register-access methods later.
|
|---|
| Properties of uvm_reg_field |
configure()
The first thing we do after creating a uvm_reg_field is configuring it. In Register Abstraction, we configured the flavor field as follows. Note that in Register Abstraction, we defined the flavor field as "WO" (write-only), but we defined it as "RW" (read/write) here to make the field more generic.
1 2 3 4 5 6 7 8 9 10 |
flavor = uvm_reg_field::type_id::create( "flavor" );
flavor.configure( .parent ( this ),
.size ( 3 ),
.lsb_pos ( 0 ),
.access ( "RW" ),
.volatile ( 0 ),
.reset ( 0 ),
.has_reset ( 1 ),
.is_rand ( 1 ),
.individually_accessible( 0 ) );
|
If the has_reset argument is 1, the value of reset argument is taken as the "HARD" reset value. If the has_reset value is 0, the value of reset is ignored. The value of reset should match the reset state of the DUT. If you want to modify the reset value after the configuration, you can use set_reset() method.
flavor.set_reset( .value( 0 ), .kind( "HARD" ) ); // kind == "HARD" by default |
|
|---|
| How configure() and set_reset() methods work |
reset()
The reset() method resets the properties of a register field, if the m_reset[kind] exists. The default kind is "HARD". If the m_reset[kind] does not exist, the reset() method does nothing. Note that the reset() method does not reset a register in the DUT. It only resets the properties of a register-field object.
flavor.reset( .kind( "HARD" ) ); // kind == "HARD" by default |
</div>
|
|---|
| How the reset() method works |
set()
The set() method sets the desired value of a register field. The set() method does not set the value to a register in the DUT. It only sets the value to the m_desired and the value properties of a register-field object. To actually set the value to the register in the DUT, use write() or update() method. These methods will be explained later.
flavor.set( .value( 1 ) ); |
|
|---|
| How the set() method works |
get()
The get() method gets the desired value of a register field. The get() method does not get the value from a register in the DUT. It only gets the value of the m_desired property. To actually get the value from the DUT, use read() or mirror() methods. These methods will be explained later. Similarly to the get() method, there are two more getters to access the local properties. The get_reset() retrieves the value of the m_reset[kind] property, while the get_mirrored_value() method retrieves the value of the m_mirrored property.
uvm_reg_data_t desired_value = flavor.get(); uvm_reg_data_t reset_value = flavor.get_reset( .kind( "HARD" ) ); // kind == "HARD" by default uvm_reg_data_t mirrored_value = flavor.get_mirrored_value(); |
|
|---|
| How the get(), get_reset(), and get_mirrored_value() methods work |
randomize()
The randomize() method is a SystemVerilog method. It randomizes the value property of a register-field object. After the randomization, the post_randomize() method copies the value of the value property to the m_desired property. Note that the pre_randomize() method copies the value of the m_desired to the value property if the rand_mode of the value property is OFF.
assert( flavor.randomize() ); |
|
|---|
| How the randomize() method works |
write()
The write() method actually writes a value to the DUT.
uvm_status_e status; flavor.write( .status( status ), .value( 1 ) ); |
The write() method involves multiple steps.
- A
uvm_reg_itemobject corresponding to the write operation is created. - The
uvm_reg_adapterconverts the write operation to a corresponding bus transaction. - The
uvm_driverexecutes the bus transaction to the DUT. - The
uvm_monitorcaptures the bus transaction. - The
uvm_reg_predictorasks theuvm_reg_adapterto convert the bus transaction to a corresponding register operation. - The register operation is converted to a
uvm_reg_item. - The
uvm_reg_itemis used to update thevalue,m_mirrored, andm_desiredproperties.
Note that if the individually_accessible argument was 0 when the register field was configured, the entire register containing the field is written, because the field is not individually accessible. In this case, the m_mirrored values are used as the write values for the other fields.
|
|---|
| How the write() method works |
read()
The read() method actually reads a register value from the DUT.
uvm_status_e status; uvm_reg_data_t value; flavor.read( .status( status ), .value( value ) ); |
Similarly to the write() method, the read() method involves multiple steps.
- A
uvm_reg_itemobject corresponding to the read operation is created. - The
uvm_reg_adapterconverts the read operation to a corresponding bus transaction. - The
uvm_driverexecutes the bus transaction to the DUT. - The
uvm_reg_apapterconverts the bus transaction with read data to a register operation. - The
read()method returns the read value to the caller. - In the mean time, the
uvm_monitorcaptures the bus transaction. - The
uvm_reg_predictorasks theuvm_reg_adapterto convert the bus transaction to a corresponding register operation. - The register operation is converted to a
uvm_reg_item. - The
uvm_reg_itemis used to update thevalue,m_mirrored, andm_desiredproperties.
Note that if the individually_accessible argument was 0 when the register field was configured, the entire register containing the field is read. In this case, the m_mirrored values are updated for the other fields as well.
|
|---|
| How the read() method works |
update()
The update() method actually writes a register value to the DUT. The update() method belongs to the uvm_reg class. The uvm_reg_field class does not have the update() method.
uvm_status_e status; jb_recipe_reg.update( .status( status ) ); |
The differences between the write() method and the update() method are:
- The
write()method takes a value as its argument, while theupdate()method uses the value of them_desiredproperty as the value to write. - The
update()method writes the value only if them_mirroredand them_desiredare not equal.
|
|---|
| Before the update() is executed |
The update() method internally calls the write( .value( m_desired ) ). Because of this, the value of the m_mirrored will be updated as well, after the update.
mirror()
The mirror() method actually reads a register from the DUT.
uvm_status_e status; flavor.mirror( .status( status ), .check( UVM_CHECK ) ); |
The differences between the read() method and the mirror() method are:
- The
read()method returns the register value to the caller, while themirror()method does not return the register value. Themirror()method only updates the value of them_mirroredproperty. - The
mirror()method compares the read value against them_desiredif the value of thecheckargument isUVM_CHECK.Note that the UVM Class Library document states that it compares the read value against the mirrored value, but if you look at the line 2,944 of(Update 4/11/2014: uvm-1.1d code base has corrected this issue. Theuvm_reg.svhof uvm-1.1c code base, it actually compares against the desired value, not against the mirrored value.mirror()compares the read value against the mirrored value now. Please see the line 2,951 ofuvm_reg.svhif you are curious about this fix.) Another caveat about the check is that if you set thevolatileargument to be1when you configured the register field, the register field won’t be checked even though you set thecheckargument to beUVM_CHECK. This is because we cannot predict the value of the register field deterministically as it might have been changed (volatile) in the DUT.
The mirror() method internally calls do_read() method. This is the same method the read() method internally calls. Because of this, the mirror() method will update the value and the m_desired properties, in addition to the m_mirrored property.
|
|---|
| How the mirror() method works |
predict()
The predict() method updates the mirrored value.
flavor.predict( .value( 1 ) ); |
The predict() method also updates the value and the m_desired properties.
|
|---|
| How the predict() method works |
Summary
The table below summarizes how each method updates the properties of the register-field object.
| Method | m_reset
["HARD"]
|
value
|
m_desired
|
m_mirrored
|
DUT |
|---|---|---|---|---|---|
configure(
.reset(val),
.has_reset(1))
|
set the value of val
|
||||
set_reset(val)
|
set the value of val
|
||||
reset()
|
copy the value of m_reset
["HARD"]
|
copy the value of m_reset
["HARD"]
|
copy the value of m_reset
["HARD"]
|
||
set(val)
|
set the value of val
|
set the value of val
|
|||
get_reset()
|
return the value of m_reset
["HARD"]
|
||||
get()
|
return the value of m_desired
|
||||
get_mirrored_value()
|
return the value of m_mirrored
|
||||
randomize()
|
randomize | copy the value of value
|
|||
write(.value(val))
|
set the value of val
|
set the value of val
|
set the value of val
|
write the value of val
| |
read(.value(val))
|
set the read value | set the read value | set the read value | read the register | |
update()
|
set the value of m_desired
|
set the value of m_desired
|
set the value of m_desired
|
write the value of m_desired
| |
mirror()
|
set the read value | set the read value | set the read value | read the register | |
predict(
.value(val))
|
set the value of val
|
set the value of val
|
set the value of val
|
In this post, we only covered so-called front-door access. We will cover back-door access in a separate post. I hope this tutorial helped you to understand the register access methods.