註明:本文轉自UVM Tutorial for Candy Lovers – 16. Register Access Methods
UVM的寄存器抽象層(RAL)提供了幾種訪問寄存器的方法。 這篇文章將解釋寄存器訪問方法的工作原理。 在Register Abstraction中,我們介紹了RAL的概述並解釋瞭如何定義寄存器。 在這篇文章中,我們將介紹如何訪問寄存器。
uvm_reg_field的屬性
在深入瞭解寄存器訪問方法之前,讓我們看看如何存儲寄存器值。 如寄存器抽象中所示,uvm_reg_field是表示寄存器的位的最低寄存器抽象層。 uvm_reg_field使用多個屬性來存儲各種寄存器字段值:
- m_reset [“HARD”]存儲硬重置值(hard reset)。 請注意,m_reset是一種帶有一種重置鍵的關聯數組。
- m_mirrored存儲我們在待測試設計(DUT)中所認爲應該存儲的值。
- m_desired存儲我們想要設置給DUT的值。
- value將要採樣的值存儲在功能覆蓋率中,或者當該字段被隨機化時將value約束。
請注意,在這些屬性中,只有值屬性是公共的。 其他屬性是本地的,因此我們無法直接從類外訪問它們。 稍後我們將向您介紹如何使用寄存器訪問方法訪問這些本地屬性。
uvm_reg_field的屬性
configure()
我們在創建uvm_reg_field後執行的第一件事是配置它。在寄存器抽象中,我們如下配置flavor字段。請注意,在Register Abstraction中,我們將flavor字段定義爲“WO”(只寫),但我們在此將其定義爲“RW”(讀/寫),以使該字段更通用。
-
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 ) );
如果has_reset參數爲1,則復位參數的值將被視爲“HARD”復位值。如果has_reset值爲0,則復位值將被忽略。復位值應與DUT的復位狀態相匹配。如果您想在配置後修改復位值,可以使用set_reset()方法。
flavor.set_reset( .value( 0 ), .kind( "HARD" ) ); // kind == "HARD" by default
configure()和set_reset()方法如何工作
reset()
如果m_reset [kind]存在,reset()方法將重置寄存器字段的屬性。默認類型是“HARD”。如果m_reset [kind]不存在,則reset()方法不執行任何操作。請注意,reset()方法不會復位DUT中的寄存器。它只復位寄存器字段對象的屬性。
flavor.reset( .kind( "HARD" ) ); // kind == "HARD" by default
reset()方法如何工作
set()
set()方法設置寄存器字段的期望值。 set()方法不會將值設置爲DUT中的寄存器的值。它只將值設置爲m_desired和寄存器字段對象的值屬性。要真正將值設置爲DUT中的寄存器,請使用write()或update()方法。這些方法將在稍後解釋。
flavor.set( .value( 1 ) );
set()方法如何工作
get()
get()方法獲取寄存器字段的期望值。 get()方法不會從DUT中的寄存器獲取值。它只獲取m_desired屬性的值。要實際從DUT獲取值,請使用read()或mirror()方法。這些方法將在稍後解釋。與get()方法類似,還有兩個getter訪問本地屬性。 get_reset()檢索m_reset [kind]屬性的值,而get_mirrored_value()方法檢索m_mirrored屬性的值。
-
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();
get(), get_reset(), and get_mirrored_value()方法如何工作
randomize()
randomize()方法是一個SystemVerilog方法。它隨機化一個寄存器字段對象的值屬性。隨機化後,post_randomize()方法將value屬性的值複製到m_desired屬性。請注意,如果value屬性的rand_mode爲OFF,則pre_randomize()方法會將m_desired的值複製到value屬性。
assert( flavor.randomize() );
randomize()方法如何工作
write()
write()方法實際上向DUT寫入一個值。
-
uvm_status_e status;
-
flavor.write( .status( status ), .value( 1 ) );
write()方法涉及多個步驟。
- 創建與寫入操作對應的uvm_reg_item對象。
- uvm_reg_adapter將寫入操作轉換爲相應的總線事務。
- uvm_driver執行到DUT的總線事務。
- uvm_monitor捕獲總線事務。
- uvm_reg_predictor要求uvm_reg_adapter將總線事務轉換爲相應的寄存器操作。
- 寄存器操作轉換爲uvm_reg_item。
- uvm_reg_item用於更新值,m_mirrored和m_desired屬性。
請注意,如果在配置寄存器字段時個別可訪問參數爲0,則包含該字段的整個寄存器會被寫入,因爲該字段不可單獨訪問。在這種情況下,m_mirrored值將用作其他字段的寫入值。
write()方法如何工作
read()
read()方法實際上從DUT中讀取一個寄存器值。
-
uvm_status_e status;
-
uvm_reg_data_t value;
-
flavor.read( .status( status ), .value( value ) );
與write()方法類似,read()方法涉及多個步驟。
- 創建與讀操作對應的uvm_reg_item對象。
- uvm_reg_adapter將讀取操作轉換爲相應的總線事務。
- uvm_driver執行到DUT的總線事務。
- uvm_reg_apapter將讀取數據的總線事務轉換爲寄存器操作。
- read()方法將讀取值返回給調用者。
- 同時,uvm_monitor捕獲總線事務。
- uvm_reg_predictor要求uvm_reg_adapter將總線事務轉換爲相應的寄存器操作。
- 寄存器操作轉換爲uvm_reg_item。
- uvm_reg_item用於更新值,m_mirrored和m_desired屬性。
請注意,如果在配置寄存器字段時individually_accessible
參數爲0,則會讀取包含字段的整個寄存器。在這種情況下,也會爲其他字段更新m_mirrored值。
read()方法如何工作
update()
update()方法實際上是向DUT寫入一個寄存器值。 update()方法屬於uvm_reg類。 uvm_reg_field類沒有update()方法。
-
uvm_status_e status;
-
jb_recipe_reg.update( .status( status ) );
write()方法和update()方法之間的區別是:
- write()方法將一個值作爲其參數,而update()方法使用m_desired屬性的值作爲要寫入的值。
- 只有當m_mirrored和m_desired不相等時,update()方法才寫入該值。
update()方法執行前
update()方法在內部調用write(.value(m_desired))。因此,更新後,m_mirrored的值也會更新。
update()方法執行後
mirror()
mirror()方法實際上是從DUT讀取一個寄存器。
-
uvm_status_e status;
-
flavor.mirror( .status( status ), .check( UVM_CHECK ) );
read()方法和mirror()方法之間的區別是:
- read()方法返回寄存器值給調用者,而mirror()方法不返回寄存器值。 mirror()方法只更新m_mirrored屬性的值。
- 如果check參數的值爲UVM_CHECK,則mirror()方法將讀取值與m_desired進行比較。請注意,UVM類庫文檔指出,它將讀取值與鏡像值進行比較,但如果您查看uvm-1.1c代碼庫的uvm_reg.svh的第2,944行,它實際上會與所需的值進行比較,而不是針對鏡像值。
2014年4月11日:uvm-1.1d代碼庫已糾正此問題。mirror()將讀取值與鏡像值進行比較。如果您對此修復感興趣,請參閱uvm_reg.svh的第2,951行。)
關於檢查的另一個警告是,如果在配置寄存器字段時將volatile參數設置爲1,則即使將check參數設置爲UVM_CHECK,也不會檢查寄存器字段。這是因爲我們無法確定性地預測寄存器字段的值,因爲它可能在DUT中被更改(易失性)。
mirror()方法在內部調用do_read()方法。這是與read()方法內部調用的相同方法。因此,除m_mirrored屬性外,mirror()方法還會更新值和m_desired屬性。
mirror()如何工作
predict()
predict()方法更新鏡像值。
flavor.predict( .value( 1 ) );
predict()方法也會更新值和m_desired屬性。
predict()方法如何工作
Summary
下表總結了每種方法如何更新寄存器字段對象的屬性。
Method | m_reset |
value |
m_desired |
m_mirrored |
DUT |
---|---|---|---|---|---|
configure |
set the value of val |
||||
set_reset(val) |
set the value of val |
||||
reset() |
copy the value of m_reset |
copy the value of m_reset |
copy the value of m_reset |
||
set(val) |
set the value of val |
set the value of val |
|||
get_reset() |
return the value of m_reset |
||||
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 |
set the value of val |
set the value of val |
set the value of val |
在這篇文章中,我們只介紹了所謂的前門訪問。我們將在單獨的帖子中介紹後門訪問。我希望本教程能幫助您理解寄存器的訪問方法。
原文中有一些QA可以加深理解。