3.小白學uvm驗證 - phase機制和config_db機制


1.phase機制

  uvm 驗證環境通過 phase 機制,引入了一套自動化的運行流程,通過該機制我們可以清晰的了解 UVM 仿真階段的層次化,因為 verilog 中有阻塞和非阻塞賦值,相應的仿真平台中,也要實現 NBA 區域 和 Actice 區域,在不同的 phase 區域中做不同的事情,可以避免競爭關系導致的變量值得不確定性; 用戶只需要在需要添加用戶代碼的區別填充即可,降低了仿真平台的調試成本

  如下圖所示,這是 UVM 驗證環境中全部 phase,從上至下,依次順序執行。其中有些 phase 為 task 函數類型,另一些為 function 函數類型。

耗時 phase (圖中灰色部分-task)
  • run_phase 和其十二個子 phase,推薦使用 run_phase,在使用子 phase 時盡量不要和 run_phase 同時使用,混用是可能導致 phase 直接的跳轉環境混亂,但並不是混合使用一定會出現問題。其運行關系如下圖折疊代碼塊
run_phase 運行機制
fork
    begin
        run_phase();
    end
    begin
        pre_reset_phase();
        reset_phase();
        post_reset_phase();
        pre_configure_phase();
        configure_phase();
        post_configure_phase();
        pre_main_phase();
        main_phase();
        post_main_phase();
        pre_shutdown_phase();
        shutdown_phase();
        post_shutdown_phase();
    end
join

  稍微解釋一下上述代碼含義,fork-join 表示兩個 begin-end 是同時開始運行的,當 run_phase() 和 pre_reset_phase() 同時存在時,run_phase() 和 pre_reset_phase() 在同一個時刻點開始運行,在 run_phase() 和 pre_reset_phase() 兩個 phase 均運行結束以后,主 phase 才會繼續執行 extract_phase()。耗時的 phase 的運行是在 uvm_tree 中從下往上運行。

不耗時 phase (圖中白色部分-function)
  • 包含 build_phase()、connect_phase()、end_of_elaboartion_phase()、start_of_simulation_phase()、extract_phase()、check_phase()、report_phase()、final_phase();
  • 不耗時的幾個 phase 在 uvm_tree 中是從上往下執行的,比如說 build_phase,這個 phase 主要用來實例化各個組件環境,理論上為了 uvm_tree 的順利構建應該從上往下執行。 並不一定上述所有的 phase 都會用到,考慮個小問題,已經有了 9 主 phase,為什么還要引入 12 子phase 呢,這是為了有時候需要更加細化的進行一些 driver 工作,比如對 DUT 進行 reset 復位,如果我們在 reset_phase 進行了復位相關的操作,我們在運行到后續 phase 時,只需要 jump 到 reset_phase, 后續 phase 會依次重復執行依次,相當於對 DUT 實現了復位操作。
phase 機制-執行順序

  前面只提到 phase 的執行順序是從上而下執行,以 uvm-tree 的角度敘述則是,從樹頂到數葉自上而下執行,如下圖所示,uvm_top 是最先開始執行的,后續依次往下執行。

  似乎上述的執行過程又存在問題,下來我們來細說一下上述過程,首先執行的是 build_phase() ,該 phase 用於構建 uvm-tree 的結構,前面我們提到 uvm_component 組件類必須在 build_phase 中實例化,也是這個原因,因為 build_phase() 的主要用途就是實例化組件類,構建 tree; 不同層次所有組件build_phase() 從空間(uvm-tree)上從上而下執行從樹根到樹葉的全部組件類 build_phase(),而同層次的組件類則是按照 new/create 是自定的名字以字典序按照前后順序自動執行 build_phase()其他不耗時的 function phase 的執行過程則相反,比如先執行 driver 這層記得 connect_phase(), 再執行 agent 這一級的 connect_phase()

  耗時 phase 的執行和上述兩種又有一些區別,需要明確以下幾個方面

 a. 對於同一組件,其 run_phase() 和 pre_reset_phase() 屬於兩個不同的線程,他們同一個時刻點啟動, 但 12 個細分 phase 順序執行;
 b. 對於同一層級的組件,其 run_phase() 和 pre_reset_phase() 屬於兩個不同的線程,他們同一個時刻點先后啟動, 但 12 個細分 phase 順序執行;
 c. 對於不同層級別的 component 在下一級別啟動之后,才會啟動;
 d. run_phase() 和 post_shutdown_phase() 需要都執行結束才會進入 extra_phase() 中。

  耗時 phase 的執行過程可以理解為自下而上啟動,同時執行

  假設上圖中 drv component 其 main_phase() 在 0 時刻開始執行,需要100個時刻才能結束;scb component 其 main_phase() 也從在 0 時刻開始執行, 且需要耗時最長,假設需要200個時刻才能結束(其他組件的 main_phase()也包含耗時,但均未超過 scb 組件的耗時),整個驗證平台的 main_phase() 要在第200個時刻才能切換到 post_main_phase(),即 drv 在100時刻執行完畢后,不會馬上跳到 post_main_phase(),需要等到所有組件中耗時最長的 mian_phase() 執行結束后,在 200 時刻,進入 post_main_phase(),其啟動和執行的過程也是自下而上啟動,同時執行

2.config_db機制

  在 uvm_tree 樹中,越上層就越接近“用戶場景”,通常不同的場景公用一套 driver 和 monitor 函數,通過設置不同的參數,產生不同的場景驅動時序,假設我們的 uvm-tree 如下圖所示,上層組件 env 要給“樹葉”層的組件 drv 傳遞參數 pre_num,這個時候就需要用到 config_db 給我們傳遞信息。

config_db兩大函數-set() 和get()

  config_db 的主要用途就是進行全局參數的傳遞共享,主要包含 set() 和 get() 函數,其中 set()用於在 config 全局數據庫(config database)中創建一個條目(entries),當然前提是沒有數據庫中未包含該條目,如果已經存在,則更新它,get() 則用於從數據庫中取出最新的 entries

uvm_config_db #(T)::set(...)
uvm_config_db #(T)::get(...)
  注意點
    a.其中T,需要設置或者取出的 entries 的參數類型
    b.get() 必須在 set() 之后進行,通常 set() 一般在 build_phase()中進行,get() 一般在其他 phase 中,或者在以下級別的build_phase中完成。

  我們繼續上述話題,我們要從 env 中給 drv 傳遞 pre_num 參數, 中間跨過了中間組件 i_agt。以下是 set()函數的一種寫法:

uvm_config_db set 示例
function void my_env::build_phase();
    ... 
    int pre_num = 25;
    ...
    uvm_config_db#(int)::set(this,"env.i_agt.drv","pre_num",100)
    ...
endfuction

  上述代碼含義為,在組件 my_env 的 build_phase 中包含 pre_num = 25 的局部變量,同時通過 uvm_config_db 對 pre_num 進行設置,下面對立面的具體參數進行解釋如下:

int : T 的具體參數類型,該類型必須和第四個參數 100 ,的類型一致,否則會報錯;
this : 該參數必須為組件類型的指針, 當設置為 NULL 時,會默認 uvm_root 組件
"env.i_agt_drv": 欲設置參數的絕對路徑,其類型為字符串類型,這也是一個隱患,如果你拼寫錯了,你不僅無法取到該參數,而且編譯器還不報錯。
100: 為欲設置的參數值。

  第二個參數+第三個參數=目標參數的絕對路徑,以我個人的理解是,UVM在 全局 config_db 數據庫中,創建一個名字為 pre_num 的config_db 數據庫 entries,該條目的索引為“第二個參數+第三個參數組成的字符串”;第二個參數和第三個參數可以很靈活的設置,比如以下騷操作:

uvm_config_db set 示例
function void my_env::build_phase();
    ... 
    int pre_num = 25;
    ...
    uvm_config_db#(int)::set(null,"uvm_test_top.env.i_agt.drv","pre_num",100)
    ...
endfuction

  你也可以在 drv 組件中正確的取到 pre_num 參數值。大家似乎絕對還不透徹,可能在以后的使用過程中造成錯誤,那我再按照我的理解說一條“潛規則”,目標參數的絕對路徑對應的字符串的設置“規則”,在 get() 函數執行時,該字符串對應的各個組件均已經被實例化,且實例化名也字符串中對應的一致,你就可以 get() 到設置的參數。有一點忘了提了,uvm_config_db#(int)::set(null,"uvm_test_top.env.i_agt.drv","pre_num",100) 不會影響同名的參數的值,即在此次 set() 函數的執行不會將局部變量 pre_num 由 25 該成 100;

  既然已經完成 set 操作了,現在再來說說 get;在 dirver 中你可以通過以下代碼來取 pre_num 參數:

uvm_config_db get 示例
function void my_drv::build_phase();
    ... 
    int pre_num_A;
    ...
    uvm_config_db#(int)::get(this,"","pre_num",pre_num_A)
    ...
endfuction

  上述代碼的含義是,通過 get() 函數將 config_db 數據中,索引為 this ,條目名為 pre_num的值,取出來給 pre_num_A;因為在 my_drv 組件的 build_phase 執行時,字符串 uvm_test_top.env.i_agt.drv 中的各個組件均已經實例化,而且在 my_drv 中 this 就是表示 uvm_test_top.env.i_agt.drv 對應的組件(uvm-tree絕對路徑)。

config_db中一大坑-只 set 不 get的情況

  一般情況下是 set 和 get 成對出現,但是有個特殊情況是,只 set 不 get 值,也能完成變量信息的傳遞,下來來簡單說一下這個坑。假設 pre_num的 set() 還是如上述情況(情況一),而 drv 如下定義:

config_db 特殊示例
class my_driver extend uvm_driver;
    int pre_num;
`uvm_component_utils_begin(my_driver)
    `uvm_field_int(pre_num, UVM_ALL_ON)
`uvm_component_utils_end

function void my_drv::new(string name = "my_driver", uvm_component parent = null);
    ...
    super.new(name,phase);
   ...
endfuction
function void my_drv::build_phase();
    super.build_phase(phase);
    ...
endfuction

endclass

   通過上述代碼,就可以省去 get 操作,在上述代碼中,首先定義了一個和entries中同名的變量 pre_num ,第二通過 uvm_field_int 對 pre_num 變量進行注冊, 第三在 build_phase 中調用了 super.build_phase(),通過這操作者三步,你就可以省略 get()。但是我的建議,咱們還是老老實實的 get 省的給后續看你代碼的人造成困惑。

   最后再提一點,當有多個 set 對同變量進行設置時,get 會取到那個值,比如我們同時在 i_agt 和 uvm_test_top,中對 pre_num 設置(目標還是給 drv),這個情況 uvm 已經考慮過了,因為 uvm_test_top 離用戶進,所以它的權限最高,我們會取到 uvm_test_top 組件中設置到的值,即誰最權威,聽誰的;第二在同一個層次對一個變量 進行多次 set, 這個時候就看 進行 get 操作時,那個 set 操作的時間離得最短,即誰時間最近,聽誰的
   至於其他的什么內容,如 monitor 中 set 值,給 driver; 我奉勸一句,不要玩的太騷,小心走火。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM