前一段時間,我寫了一篇有關如何處理UVM agent組件中的reset的文章。有人問了一個很好的問題:如何處理計分板上的reset?在本文中,我將與您分享我在驗證環境中處理reset的方式。
假設我們有一個帶有APB接口的DUT,用於訪問某些內部寄存器。
與在agent中處理reset一樣,在完整的驗證環境中,我嘗試在每個組件中實現handle_reset()函數,並且應從env組件中的一個線程最後調用所有這些函數。
驗證環境的簡化版本可能如下所示:
步驟1:處理model中的reset
model組件是環境中最複雜的組件。它包含寄存器塊以及用於建模DUT行爲的任何其他元素和線程。所有這些元素都需要reset。
class cfs_dut_model extends uvm_component;
//function for handling reset inside the model
virtual function void handle_reset(string kind = "HARD");
//kill and restart any ongoing threads
reg_block.reset(kind);
//clear here any other elements part of the model class
endfunction
endclass
步驟#2:在計分板上處理reset
在記分板上處理reset應該首先殺死並重新啓動任何正在進行的過程,然後重置model:
class cfs_dut_scoreboard extends uvm_component;
//function for handling reset inside the scoreboard
virtual function void handle_reset(string kind = "HARD");
//kill and restart any ongoing threads
model.reset(kind);
//clear here any other elements part of the scoreboard class
endfunction
endclass
步驟#3:處理覆蓋率收集器內的reset
最有可能在覆蓋率收集器內處理reset將意味着在reset時對DUT的內部狀態進行一些採樣,然後進行一些clear工作:
class cfs_dut_coverage extends uvm_component;
//function for handling reset inside the coverage
virtual function void handle_reset(string kind = "HARD");
//sample the state of the DUT at reset
//clear here any other elements part of the coverage class
endfunction
endclass
步驟#4:處理env中的reset
在環境中處理reset應該類似於在agent中處理reset的邏輯。
首先,我們需要有一個handle_reset()函數來進行實際的reset:
class cfs_dut_env extends uvm_component;
//function for handling reset inside the environment
virtual function void handle_reset(uvm_phase phase, string kind = "HARD");
coverage.handle_reset(kind);
scoreboard.handle_reset(kind);
//clear here any other elements part of the environment class
endfunction
endclass
接下來,我們需要一個實際上等待物理復位並調用handle_reset()函數的線程:
class cfs_dut_env extends uvm_component;
virtual task run_phase(uvm_phase phase);
forever begin
wait_reset_start();
handle_reset(phase, "HARD");
wait_reset_end();
end
endtask
endclass
在大多數情況下,此邏輯可以正常工作,但在極端情況下,此邏輯可能會崩潰。
在上述邏輯和本文的第1部分中,我們可以標識驗證環境的多個並行的獨立執行線程:
- 線程#1 – APB監視代理程序:用於收集APB事務的任務。該線程通常通過更新和檢查寄存器值來影響寄存器塊。
- 線程2 – APB代理:用於檢測reset的任務。該線程將僅影響APB agent的內部邏輯,並且將要執行的操作之一是停止線程#1並重新啓動它。有關詳細信息,請參閱本文第1部分中的步驟1。
- 線程#3 –環境:用於檢測reset的任務。該線程將影響DUT的模型(例如重置寄存器塊),重置coverage類等。
如果復位是異步的,並且從不與時鐘的上升沿同時激活,則一切正常,但是我們不能保證。
問題是,當所有線程都希望完全在同一仿真時間內採取某些措施時:
- 復位在時鐘的上升沿變爲有效
- 在APB上有寄存器訪問
因爲這些是並行線程,所以從驗證工程師的角度來看,它們的執行順序或多或少是隨機的。
因此,例如,如果按以下順序執行線程#3->#1->#2,則:
- 線程#3將清除模型,因此這意味着寄存器塊將被複位
- 數據將被線程#1寫入一些內部寄存器(如CTRL)中,因爲它收集了APB訪問
- 線程#2將復位APB agent並重新啓動線程#1,但爲時已晚,因爲錯誤數據已寫入CTRL寄存器模型中
有一個簡單的解決方法:我們擺脫了用於處理agent程序(#2)中的復位的線程,而處理了線程#3中的agent程序復位。
首先,我們需要阻止agent自行處理reset:
class cfs_dut_env extends uvm_component;
virtual function void end_of_elaboration_phase(uvm_phase phase);
apb_agent.agent_config.set_should_handle_reset(0);
//do the same for any other agent part of the environment
endtask
endclass
接下來,我們應該在env中以正確的順序處理reset代理的問題:
class cfs_dut_env extends uvm_component;
//function for handling reset inside the environment
virtual function void handle_reset(uvm_phase phase, string kind = "HARD");
apb_agent.handle_reset(phase, kind);
//do the same for any other agent part of the environment
coverage.handle_reset(kind);
scoreboard.handle_reset(kind);
//clear here any other elements part of the environment class
endfunction
endclass
這樣,始終可以正確reset驗證環境,因爲:
- 如果首先發生在線程3,然後線程1,則線程3將重新啓動線程1,因此沒有APB事務到達模型
- 如果首先發生在線程1,然後是線程3,則線程1將數據推送到寄存器塊模型中,但是線程3將立即將其清除。
可以將相同的邏輯應用於驗證環境的任意數量的agent程序部分。
基本思想是:從一個線程處理整個環境的復位,以便您可以控制復位組件的順序。
採用才reset處理方法的vip的例子:https://github.com/amiq-consulting/amiq_apb