【轉載】【UVM】目前看到的關於uvm regmodel訪問方法最詳盡的介紹

註明:本文轉自UVM Tutorial for Candy Lovers – 16. Register Access Methods

翻譯來自UVM糖果愛好者教程 - 16.寄存器訪問方法

 

 

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”(讀/寫),以使該字段更通用。


 
  1. flavor = uvm_reg_field::type_id::create( "flavor" );

  2. flavor.configure( .parent ( this ),

  3. .size ( 3 ),

  4. .lsb_pos ( 0 ),

  5. .access ( "RW" ),

  6. .volatile ( 0 ),

  7. .reset ( 0 ),

  8. .has_reset ( 1 ),

  9. .is_rand ( 1 ),

  10. .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屬性的值。


 
  1. uvm_reg_data_t desired_value = flavor.get();

  2. uvm_reg_data_t reset_value = flavor.get_reset( .kind( "HARD" ) ); // kind == "HARD" by default

  3. 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寫入一個值。


 
  1. uvm_status_e status;

  2.  
  3. flavor.write( .status( status ), .value( 1 ) );

write()方法涉及多個步驟。

  1. 創建與寫入操作對應的uvm_reg_item對象。
  2. uvm_reg_adapter將寫入操作轉換爲相應的總線事務。
  3. uvm_driver執行到DUT的總線事務。
  4. uvm_monitor捕獲總線事務。
  5. uvm_reg_predictor要求uvm_reg_adapter將總線事務轉換爲相應的寄存器操作。
  6. 寄存器操作轉換爲uvm_reg_item。
  7. uvm_reg_item用於更新值,m_mirrored和m_desired屬性。

請注意,如果在配置寄存器字段時個別可訪問參數爲0,則包含該字段的整個寄存器會被寫入,因爲該字段不可單獨訪問。在這種情況下,m_mirrored值將用作其他字段的寫入值。

                                                                                 write()方法如何工作

read()

read()方法實際上從DUT中讀取一個寄存器值。


 
  1. uvm_status_e status;

  2. uvm_reg_data_t value;

  3.  
  4. flavor.read( .status( status ), .value( value ) );

與write()方法類似,read()方法涉及多個步驟。

  1. 創建與讀操作對應的uvm_reg_item對象。
  2. uvm_reg_adapter將讀取操作轉換爲相應的總線事務。
  3. uvm_driver執行到DUT的總線事務。
  4. uvm_reg_apapter將讀取數據的總線事務轉換爲寄存器操作。
  5. read()方法將讀取值返回給調用者。
  6. 同時,uvm_monitor捕獲總線事務。
  7. uvm_reg_predictor要求uvm_reg_adapter將總線事務轉換爲相應的寄存器操作。
  8. 寄存器操作轉換爲uvm_reg_item。
  9. uvm_reg_item用於更新值,m_mirrored和m_desired屬性。

請注意,如果在配置寄存器字段時individually_accessible 參數爲0,則會讀取包含字段的整個寄存器。在這種情況下,也會爲其他字段更新m_mirrored值。

                                                                                        read()方法如何工作

update()

update()方法實際上是向DUT寫入一個寄存器值。 update()方法屬於uvm_reg類。 uvm_reg_field類沒有update()方法。


 
  1. uvm_status_e status;

  2.  
  3. 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讀取一個寄存器。


 
  1. uvm_status_e status;

  2.  
  3. 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
["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
 

 

在這篇文章中,我們只介紹了所謂的前門訪問。我們將在單獨的帖子中介紹後門訪問。我希望本教程能幫助您理解寄存器的訪問方法。

原文中有一些QA可以加深理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章