(1)定義interface
interface my_if(input clk, input rst_n);logic [7:0] data;logic valid;endinterface
(2)在tb中使用interface
????????定義了interface后,在top_tb中實例化DUT時,就可以直接使用。
????????先實例化interface
my_if input_if(clk, rst_n);my_if output_if(clk, rst_n);
? ? ? ? 將interface與dut綁定
dut my_dut(.clk(clk),.rst_n(rst_n),.rxd(input_if.data),.rx_dv(input_if.valid),.txd(output_if.data),.tx_en(output_if.valid));
(3)在driver中使用interface
????????不能在class中直接例化interface,向下面的代碼是錯誤的:
class my_driver extends uvm_driver;
my_if drv_if;
…
endclass
????????在類中使用的是virtual interface。如下面的代碼所示:
class my_driver extends uvm_driver;virtual my_if vif;...
endclass
????????在聲明了vif后,就可以在main_phase中使用如下方式驅動其中的信號:
task my_driver::main_phase(uvm_phase phase);phase.raise_objection(this);`uvm_info("my_driver", "main_phase is called", UVM_LOW);vif.data <= 8'b0; vif.valid <= 1'b0;while(!vif.rst_n)@(posedge vif.clk);for(int i = 0; i < 256; i++)begin@(posedge vif.clk);vif.data <= $urandom_range(0, 255);vif.valid <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge vif.clk);vif.valid <= 1'b0;phase.drop_objection(this);
endtask
(4)把top_tb中的input_if和my_driver中的vif對應起來
????????最簡單的方法莫過于直接賦值。此時一 個新的問題又擺在了面前:在top_tb中,通過run_test語句建立了一個my_driver的實例,但是應該如何引用這個實例呢?不可能像 引用my_dut那樣直接引用my_driver中的變量:top_tb.my_dut.xxx是可以的,但是top_tb.my_driver.xxx是不可以的。這個問題的終極 原因在于UVM通過run_test語句實例化了一個脫離了top_tb層次結構的實例,建立了一個新的層次結構。
????????對于這種脫離了top_tb層次結構,同時又期望在top_tb中對其進行某些操作的實例,UVM引進了config_db機制。在config_db機 制中,分為set和get兩步操作。所謂set操作,讀者可以簡單地理解成是“寄信”,而get則相當于是“收信”。在top_tb中執行set操作:
initial beginuvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input_if);
end
????????在my_driver中,執行get操作:
virtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("my_driver", "build_phase is called", UVM_LOW);if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")endfunction
????????這里引入了build_phase。與main_phase一樣,build_phase也是UVM中內建的一個phase。當UVM啟動后,會自動執行 build_phase。build_phase在new函數之后main_phase之前執行。在build_phase中主要通過config_db的set和get操作來傳遞一些數據, 以及實例化成員變量等。需要注意的是,這里需要加入super.build_phase語句,因為在其父類的build_phase中執行了一些必要的操 作,這里必須顯式地調用并執行它。build_phase與main_phase不同的一點在于,build_phase是一個函數phase,而main_phase是一個 任務phase,build_phase是不消耗仿真時間的。build_phase總是在仿真時間($time函數打印出的時間)為0時執行。
????????在build_phase中出現了uvm_fatal宏,uvm_fatal宏是一個類似于uvm_info的宏,但是它只有兩個參數,這兩個參數與uvm_info宏 的前兩個參數的意義完全一樣。與uvm_info宏不同的是,當它打印第二個參數所示的信息后,會直接調用Verilog的finish函數來結 束仿真。uvm_fatal的出現表示驗證平臺出現了重大問題而無法繼續下去,必須停止仿真并做相應的檢查。所以對于uvm_fatal來 說,uvm_info中出現的第三個參數的冗余度級別是完全沒有意義的,只要是uvm_fatal打印的信息,就一定是非常關鍵的,所以無 需設置第三個參數。
????????config_db的set和get函數都有四個參數,這兩個函數的第三個參數必須完全一致。set函數的第四個參數表示要將哪個interface 通過config_db傳遞給my_driver,get函數的第四個參數表示把得到的interface傳遞給哪個my_driver的成員變量。set函數的第二個參 數表示的是路徑索引,即在2.2.1節介紹uvm_info宏時提及的路徑索引。在top_tb中通過run_test創建了一個my_driver的實例,那么 這個實例的名字是什么呢?答案是uvm_test_top:UVM通過run_test語句創建一個名字為uvm_test_top的實例。
????????無論傳遞給run_test的參數是什么,創建的實例的名字都為uvm_test_top。由于set操作的目標是my_driver,所以set函數的第二 個參數就是uvm_test_top。
????????set函數與get函數使用雙冒號是因為這兩個函數都是靜態函數,而 uvm_config_db#(virtual my_if)則是一個參數化的類,其參數就是要寄信的類型,這里是virtual my_if。
(5)通過config_db機 制向變量傳遞值
????????假如要向my_driver的var變 量傳遞一個int類型的數據,那么可以使用如下方式:
initial begin
uvm_config_db#(int)::set(null, "uvm_test_top", "var", 100);
end
????????而在my_driver中應該使用如下方式:
class my_driver extends uvm_driver;int var;virtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("my_driver", "build_phase is called", UVM_LOW);if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")if(!uvm_config_db#(int)::get(this, "", "var", var))`uvm_fatal("my_driver", "var must be set!!!")
endfunction
????????從這里可以看出,可以向my_driver中“寄”許多信。上文列舉的兩個例子是top_tb向my_driver傳遞了兩個不同類型的數據,其 實也可以傳遞相同類型的不同數據。假如my_driver中需要兩個my_if,那么可以在top_tb中這么做:
initial beginuvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input_if);uvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif2", output_if);
end
????????在my_driver中這么做:
virtual my_if vif;
virtual my_if vif2;virtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("my_driver", "build_phase is called", UVM_LOW);if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")if(!uvm_config_db#(virtual my_if)::get(this, "", "vif2", vif2))`uvm_fatal("my_driver", "virtual interface must be set for vif2!!!")
endfunction
???????????????注意:set和get函數,這兩個函數的第三個參數必須完全一致
參考:UVM實戰
?