0. 引言
在UVM支持的寄存器操作中,有get、update、mirror、write等等一些方法,在這里整理一下他們的用法。
寄存器模型中的寄存器值應該與DUT保持同步,但是由於DUT的值是實時更新的,所以寄存器模型並不能實時知道這種更新,在寄存器模型中專門有個值來盡可能與DUT中寄存器的值保持一致,叫鏡像值(mirrorred value)。寄存器模型中還有一個值叫期望值(respected value),這個值保存我們希望寫入寄存器的值。比如希望向DUT某個寄存器寫入'h1,用set函數設置期望值,然后用update任務(update會比較鏡像值和期望值,如果不一樣,將期望值寫入DUT,並更新鏡像值)。
1. 函數
1.1 set
virtual function void set ( uvm_reg_data_t value, string fname = "",int lineno = 0 )
設置模型中寄存器的期望值,不會改變DUT中這個寄存器的值。
1.2 get
virtual function uvm_reg_data_t get( string fname = "", int lineno = 0 )
返回模型中寄存器的期望值,而不是DUT中的寄存器值。
1.3 get_mirrored_value
virtual function uvm_reg_data_t get_mirrored_value( string fname = "", int lineno = 0 )
返回模型中寄存器的鏡像值。
1.4 get_reset
virtual function uvm_reg_data_t get_reset( string kind = "HARD" )
返回寄存器的復位值。
1.5 predict
virtual function bit predict ( uvm_reg_data_t value, uvm_reg_byte_en_t be = -1, uvm_predict_e kind = UVM_PREDICT_DIRECT, uvm_path_e path = UVM_FRONTDOOR, uvm_reg_map map = null, string fname = "", int lineno = 0 )
更新模型中的鏡像值。新的鏡像值通過value參數傳入。
當在DUT中實現一個計數器的時候,模型中的計數器是靜止的。如果想在模型中得到DUT的技術值,這就需要手動更新鏡像值,又不能對DUT進行操作,這可以通過predict函數。
第三個參數是uvm_predict_e枚舉類型,他有如下三個元素:
UVM_PREDICT_DIRECT | Predicted value is as-is |
UVM_PREDICT_READ | Predict based on the specified value having been read |
UVM_PREDICT_WRITE | Predict based on the specified value having been written |
如果想要更新鏡像值又不對DUT進行操作,要用UVM_PREDICT_DIRECT。
write、read、peek和poke在完成對DUT的讀寫之后也會調用這個函數,更新鏡像值。
1.6 randomize
無論是uvm_reg,還是uvm_field、uvm_block,都是支持randomize()。
assert(rm.invert.reg_data.randomize()); assert(rm.invert.randomize()); assert(rm.randomize()):
當寄存器隨機化后,期望值會被隨機,但是鏡像值不變,之后調用update任務,可以更新DUT中的寄存器值。
但是一個field能夠被隨機化,需要:
1. 在filed的configure第八個參數設為1.
2. filed為rand類型。
3. filed的讀寫類型為可寫的。
2. 任務
2.1 update
virtual task update( output uvm_status_e status, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input uvm_sequence_base parent = null, input int prior = -1, input uvm_object extension = null, input string fname = "", input int lineno = 0 )
將模型中的期望值更新到DUT中。改變DUT中的寄存器。update會檢查模型中的期望值和鏡像值,如果兩者不相等,那么將期望值更新到DUT中,並且更新鏡像值。update與mirror操作相反。
如果鏡像值和期望值相同,那么不會寫DUT寄存器,也就不會產生總線transaction。
2.2 mirror
virtual task mirror( output uvm_status_e status, input uvm_check_e check = UVM_NO_CHECK, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input uvm_sequence_base parent = null, input int prior = -1, input uvm_object extension = null, input string fname = "", input int lineno = 0 )
讀DUT中寄存器的值,與update操作相反。如果第二個參數check為UVM_CHECK,那么會檢查讀取的值與鏡像值是否一樣,如果不一樣報錯。通過mirror讀取DUT的寄存器值之后,會調用predict函數,更新鏡像值。
mirror有兩種應用場景:一是在仿真中不斷調用,但此時是UVM_NO_CHECK,保證鏡像值與DUT中的值相等;二是在仿真結束的時候調用,這時是UVM_CHECK檢查模型中的鏡像值與DUT中的寄存器值是否一致。
2.3 write
virtual task write( output uvm_status_e status, input uvm_reg_data_t value, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input uvm_sequence_base parent = null, input int prior = -1, input uvm_object extension = null, input string fname = "", input int lineno = 0 )
模仿DUT的行為,通過前門或者后門方式向DUT中寫入寄存器值,會產生總線transaction。並且調用predict更新鏡像值。
uvm_path_e定義寄存器操作類型,如下:
UVM_FRONTDOOR | Use the front door |
UVM_BACKDOOR | Use the back door |
UVM_PREDICT | Operation derived from observations by a bus monitor via the uvm_reg_predictor class. |
UVM_DEFAULT_PATH | Operation specified by the context |
我在使用中,如果用set_auto_predict(1)——采取自動更行鏡像值的方式,write之后,調用get和get_mirrored_value都能得到新寫入的值。
如果關閉auto_predict,用uvm_reg_predict來更新鏡像值,我在在使用中write之后,調用get和get_mirrored_value得到0。
如果是read任務,那么無論是auto_predict還是uvm_reg_predict都會自動更新鏡像值和期望值。
鏈接:https://github.com/east1203/uvm_codes/tree/master/tb1_wd/a.uvm_reg_predict
2.4 read
virtual task read( output uvm_status_e status, output uvm_reg_data_t value, input uvm_path_e path = UVM_DEFAULT_PATH, input uvm_reg_map map = null, input uvm_sequence_base parent = null, input int prior = -1, input uvm_object extension = null, input string fname = "", input int lineno = 0 )
模仿DUT的行為,通過前門或者后門方式讀取DUT中寄存器的值,並更新鏡像值,會產生總線transaction。
2.5 peek
virtual task poke( output uvm_status_e status, input uvm_reg_data_t value, input string kind = "", input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0 )
通過后門訪問方式讀取寄存器的值,不關心DUT的行為,即使寄存器的讀寫類型是不能讀,也可以將值讀出來。
對於read clear類型的field,peek讀操作不會clear。所以有的時候peek和read操作結果不一樣
2.6 poke
virtual task peek( output uvm_status_e status, output uvm_reg_data_t value, input string kind = "", input uvm_sequence_base parent = null, input uvm_object extension = null, input string fname = "", input int lineno = 0 )
通過后門訪問方式寫入寄存器的值,不關心DUT的行為,即使寄存器的讀寫類型是不能寫,也可以將值寫進去。
對於write clear類型的filed,poke操作不會clear,所以有的時候poke和write操作結果不一樣。