官术网_书友最值得收藏!

  • UVM實戰
  • 張強編著
  • 6146字
  • 2019-01-01 00:58:04

2.2 只有driver的驗證平臺

driver是驗證平臺最基本的組件,是整個驗證平臺數據流的源泉。本節以一個簡單的DUT為例,說明一個只有driver的UVM驗證平臺是如何搭建的。

*2.2.1 最簡單的驗證平臺所有帶星號(*)的章節表示本節提供源代碼,可登錄華章網站(http://www.hzbook.com)獲取。

在本章中,假設有如下的DUT定義:

代碼清單 2-1

文件:src/ch2/dut/dut.sv(本書各章節中有大量源代碼。如果在“文件”關鍵字后有相應的文件名及路徑,表明此段代碼可以從本書的源碼包中找到。)
 1 module dut(clk,
 2           rst_n,
 3           rxd,
 4           rx_dv,
 5           txd,
 6           tx_en);
 7 input clk;
 8 input rst_n;
 9 input[7:0] rxd;
10 input rx_dv;
11 output [7:0] txd;
12 output tx_en;
1314 reg[7:0] txd;
15 reg tx_en;
1617 always @(posedge clk) begin
18    if(!rst_n) begin
19       txd <= 8'b0;
20       tx_en <= 1'b0;
21    end
22    else begin
23       txd <= rxd;
24       tx_en <= rx_dv;
25    end
26 end
27 endmodule

這個DUT的功能非常簡單,通過rxd接收數據,再通過txd發送出去。其中rx_dv是接收的數據有效指示,tx_en是發送的數據有效指示。本章中所有例子都是基于這個DUT。

UVM中的driver應該如何搭建?UVM是一個庫,在這個庫中,幾乎所有的東西都是使用類(class)來實現的。driver、monitor、reference model、scoreboard等組成部分都是類。類是像SystemVerilog這些面向對象編程語言中最偉大的發明之一,是面向對象的精髓所在。類有函數(function),另外還可以有任務(task),通過這些函數和任務可以完成driver的輸出激勵功能,完成monitor的監測功能,完成參考模型的計算功能,完成scoreboard的比較功能。類中可以有成員變量,這些成員變量可以控制類的行為,如控制driver的行為等。當要實現一個功能時,首先應該想到的是從UVM的某個類派生出一個新的類,在這個新的類中實現所期望的功能。所以,使用UVM的第一條原則是:驗證平臺中所有的組件應該派生自UVM中的類。

UVM驗證平臺中的driver應該派生自uvm_driver,一個簡單的driver如下例所示:

代碼清單 2-2

文件:src/ch2/section2.2/2.2.1/my_driver.sv
 3 class my_driver extends uvm_driver;
 4  5    function new(string name = "my_driver", uvm_component parent = null);
 6       super.new(name, parent);
 7    endfunction
 8    extern virtual task main_phase(uvm_phase phase);
 9 endclass
10 11 task my_driver::main_phase(uvm_phase phase);
12    top_tb.rxd <= 8'b0;
13    top_tb.rx_dv <= 1'b0;
14    while(!top_tb.rst_n)
15       @(posedge top_tb.clk);
16    for(int i = 0; i < 256; i++)begin
17       @(posedge top_tb.clk);
18       top_tb.rxd <= $urandom_range(0, 255);
19       top_tb.rx_dv <= 1'b1;
20       `uvm_info("my_driver", "data is drived", UVM_LOW)
21    end
22    @(posedge top_tb.clk);
23    top_tb.rx_dv <= 1'b0;
24 endtask

這個driver的功能非常簡單,只是向rxd上發送256個隨機數據,并將rx_dv信號置為高電平。當數據發送完畢后,將rx_dv信號置為低電平。在這個driver中,有兩點應該引起注意:

  • 所有派生自uvm_driver的類的new函數有兩個參數,一個是string類型的name,一個是uvm_component類型的parent。關于name參數,比較好理解,就是名字而已;至于parent則比較難以理解,讀者可暫且放在一邊,下文會有介紹。事實上,這兩個參數是由uvm_component要求的,每一個派生自uvm_component或其派生類的類在其new函數中要指明兩個參數:name和parent,這是uvm_component類的一大特征。而uvm_driver是一個派生自uvm_component的類,所以也會有這兩個參數。
  • driver所做的事情幾乎都在main_phase中完成。UVM由phase來管理驗證平臺的運行,這些phase統一以xxxx_phase來命名,且都有一個類型為uvm_phase、名字為phase的參數。main_phase是uvm_driver中預先定義好的一個任務。因此幾乎可以簡單地認為,實現一個driver等于實現其main_phase。

上述代碼中還出現了uvm_info宏。這個宏的功能與Verilog中display語句的功能類似,但是它比display語句更加強大。它有三個參數,第一個參數是字符串,用于把打印的信息歸類;第二個參數也是字符串,是具體需要打印的信息;第三個參數則是冗余級別。在驗證平臺中,某些信息是非常關鍵的,這樣的信息可以設置為UVM_LOW,而有些信息可有可無,就可以設置為UVM_HIGH,介于兩者之間的就是UVM_MEDIUM。UVM默認只顯示UVM_MEDIUM或者UVM_LOW的信息,本書3.4.1節會講述如何顯示UVM_ HIGH的信息。本節中uvm_info宏打印的結果如下:

UVM_INFO my_driver.sv(20) @ 48500000: drv [my_driver] data is drived

在uvm_info宏打印的結果中有如下幾項:

  • UVM_INFO關鍵字:表明這是一個uvm_info宏打印的結果。除了uvm_info宏外,還有uvm_error宏、uvm_warning宏,后文中將會介紹。
  • my_driver.sv(20):指明此條打印信息的來源,其中括號里的數字表示原始的uvm_info打印語句在my_driver.sv中的行號。
  • 48500000:表明此條信息的打印時間。
  • drv:這是driver在UVM樹中的路徑索引。UVM采用樹形結構,對于樹中任何一個結點,都有一個與其相應的字符串類型的路徑索引。路徑索引可以通過get_full_name函數來獲取,把下列代碼加入任何UVM樹的結點中就可以得知當前結點的路徑索引:

代碼清單 2-3

$display("the full name of current component is: %s", get_full_name());
  • [my_driver]:方括號中顯示的信息即調用uvm_info宏時傳遞的第一個參數。
  • data is drived:表明宏最終打印的信息。

可見,uvm_info宏非常強大,它包含了打印信息的物理文件來源、邏輯結點信息(在UVM樹中的路徑索引)、打印時間、對信息的分類組織及打印的信息。讀者在搭建驗證平臺時應該盡量使用uvm_info宏取代display語句。

定義my_driver后需要將其實例化。這里需要注意類的定義與類的實例化的區別。所謂類的定義,就是用編輯器寫下:

代碼清單 2-4

classs A;
…
endclass

而所謂類的實例化指的是通過new創造出A的一個實例。如:

代碼清單 2-5

A a_inst;
a_inst = new();

類的定義類似于在紙上寫下一紙條文,然后把這些條文通知給SystemVerilog的仿真器:驗證平臺可能會用到這樣的一個類,請做好準備工作。而類的實例化在于通過new()來通知SystemVerilog的仿真器:請創建一個A的實例。仿真器接到new的指令后,就會在內存中劃分一塊空間,在劃分前,會首先檢查是否已經預先定義過這個類,在已經定義過的情況下,按照定義中所指定的“條文”分配空間,并且把這塊空間的指針返回給a_inst,之后就可以通過a_inst來查看類中的各個成員變量,調用成員函數/任務等。對大部分的類來說,如果只定義而不實例化,是沒有任何意義的(這里的例外是一些靜態類,其成員變量都是靜態的,不實例化也可以正常使用。);而如果不定義就直接實例化,仿真器將會報錯。

對my_driver實例化并且最終搭建的驗證平臺如下:

代碼清單 2-6

文件:src/ch2/section2.2/2.2.1/top_tb.sv
1 `timescale 1ns/1ps
2 `include "uvm_macros.svh"
3  4 import uvm_pkg::*;
5 `include "my_driver.sv"
6  7 module top_tb;
8  9 reg clk;
10 reg rst_n;
11 reg[7:0] rxd;
12 reg rx_dv;
13 wire[7:0] txd;
14 wire tx_en;
15 16 dut my_dut(.clk(clk),
17            .rst_n(rst_n),
18            .rxd(rxd),
19            .rx_dv(rx_dv),
20            .txd(txd),
21            .tx_en(tx_en));
22 23 initial begin
24    my_driver drv;
25    drv = new("drv", null);
26    drv.main_phase(null);
27    $finish();
28 end
29 30 initial begin
31    clk = 0;
32    forever begin
33       #100 clk =~clk;
34    end
35 end
36 37 initial begin
38    rst_n = 1'b0;
39    #1000;
40    rst_n = 1'b1;
41 end
42 43 endmodule

第2行把uvm_macros.svh文件通過include語句包含進來。這是UVM中的一個文件,里面包含了眾多的宏定義,只需要包含一次。

第4行通過import語句將整個uvm_pkg導入驗證平臺中。只有導入了這個庫,編譯器在編譯my_driver.sv文件時才會認識其中的uvm_driver等類名。

第24和25行定義一個my_driver的實例并將其實例化。注意這里調用new函數時,其傳入的名字參數為drv,前文介紹uvm_info宏的打印信息時出現的代表路徑索引的drv就是在這里傳入的參數drv。另外傳入的parent參數為null,在真正的驗證平臺中,這個參數一般不是null,這里暫且使用null。

第26行顯式地調用my_driver的main_phase。在main_phase的聲明中,有一個uvm_ phase類型的參數phase,在真正的驗證平臺中,這個參數是不需要用戶理會的。本節的驗證平臺還算不上一個完整的UVM驗證平臺,所以暫且傳入null。

第27行調用finish函數結束整個仿真,這是一個Verilog中提供的函數。

運行這個例子,可以看到“data is drived”被輸出了256次。

*2.2.2 加入factory機制

上一節給出了一個只有driver、使用UVM搭建的驗證平臺。嚴格來說這根本就不算是UVM驗證平臺,因為UVM的特性幾乎一點都沒有用到。像上節中my_driver的實例化及drv.main_phase的顯式調用,即使不使用UVM,只使用簡單的SystemVerilog也可以完成。本節將會為讀者展示在初學者看來感覺最神奇的一點:自動創建一個類的實例并調用其中的函數(function)和任務(task)。

要使用這個功能,需要引入UVM的factory機制:

代碼清單 2-7

文件:src/ch2/section2.2/2.2.2/my_driver.sv
 3 class my_driver extends uvm_driver;
 4  5    `uvm_component_utils(my_driver)
 6    function new(string name = "my_driver", uvm_component parent = null);
 7       super.new(name, parent);
 8       `uvm_info("my_driver", "new is called", UVM_LOW);
 9    endfunction
10    extern virtual task main_phase(uvm_phase phase);
11 endclass
12 13 task my_driver::main_phase(uvm_phase phase);
14    `uvm_info("my_driver", "main_phase is called", UVM_LOW);
15    top_tb.rxd <= 8'b0;
16    top_tb.rx_dv <= 1'b0;
17    while(!top_tb.rst_n)
18       @(posedge top_tb.clk);
19    for(int i = 0; i < 256; i++)begin
20       @(posedge top_tb.clk);
21       top_tb.rxd <= $urandom_range(0, 255);
22       top_tb.rx_dv <= 1'b1;
23       `uvm_info("my_driver", "data is drived", UVM_LOW);
24    end
25    @(posedge top_tb.clk);
26    top_tb.rx_dv <= 1'b0;
27 endtask

factory機制的實現被集成在了一個宏中:uvm_component_utils。這個宏所做的事情非常多,其中之一就是將my_driver登記在UVM內部的一張表中,這張表是factory功能實現的基礎。只要在定義一個新的類時使用這個宏,就相當于把這個類注冊到了這張表中。那么factory機制到底是什么?這個宏還做了哪些事情呢?這些屬于UVM中的高級問題,本書會在后文一一展開。

在給driver中加入factory機制后,還需要對top_tb做一些改動:

代碼清單 2-8

文件:src/ch2/section2.2/2.2.2/top_tb.sv
 7 module top_tb;
 …
36 initial begin
37    run_test("my_driver");
38 end
39 40 endmodule

這里使用一個run_test語句替換掉了代碼清單2-6中第23到28行的my_driver實例化及main_phase的顯式調用。運行這個新的驗證平臺,會輸出如下語句:

new is called
main_phased is called

一個run_test語句會創建一個my_driver的實例,并且會自動調用my_driver的main_ phase。仔細觀察run_test語句,會發現傳遞給它的是一個字符串。UVM根據這個字符串創建了其所代表類的一個實例。如果沒有UVM,讀者自己能夠實現同樣的功能嗎?

根據類名創建一個類的實例,這是uvm_component_utils宏所帶來的效果,同時也是factory機制給讀者的最初印象。只有在類定義時聲明了這個宏,才能使用這個功能。所以從某種程度上來說,這個宏起到了注冊的作用。只有經過注冊的類,才能使用這個功能,否則根本不能使用。請記住一點:所有派生自uvm_component及其派生類的類都應該使用uvm_component_utils宏注冊。

除了根據一個字符串創建類的實例外,上述代碼中另外一個神奇的地方是main_phase被自動調用了。在UVM驗證平臺中,只要一個類使用uvm_component_utils注冊且此類被實例化了,那么這個類的main_phase就會自動被調用。這也就是為什么上一節中會強調實現一個driver等于實現其main_phase。所以,在driver中,最重要的就是實現main_phase。

上面的例子中,只輸出到“main_phase is called”。令人沮喪的是,根本沒有輸出“data is drived”,而按照預期,它應該輸出256次。關于這個問題,牽涉UVM的objection機制。

*2.2.3 加入objection機制

在上一節中,雖然輸出了“main_phase is called”,但是“data is drived”并沒有輸出。而main_phase是一個完整的任務,沒有理由只執行第一句,而后面的代碼不執行。看上去似乎main_phase在執行的過程中被外力“殺死”了,事實上也確實如此。

UVM中通過objection機制來控制驗證平臺的關閉。細心的讀者可能發現,在上節的例子中,并沒有如2.2.1節所示顯式地調用finish語句來結束仿真。但是在運行上節例子時,仿真平臺確實關閉了。在每個phase中,UVM會檢查是否有objection被提起(raise_ objection),如果有,那么等待這個objection被撤銷(drop_objection)后停止仿真;如果沒有,則馬上結束當前phase

加入了objection機制的driver如下所示:

代碼清單 2-9

文件:src/ch2/section2.2/2.2.3/my_driver.sv
13 task my_driver::main_phase(uvm_phase phase);
14   phase.raise_objection(this);
15   `uvm_info("my_driver", "main_phase is called", UVM_LOW);
16   top_tb.rxd <= 8'b0;
17   top_tb.rx_dv <= 1'b0;
18   while(!top_tb.rst_n)
19     @(posedge top_tb.clk);
20   for(int i = 0; i < 256; i++)begin
21     @(posedge top_tb.clk);
22     top_tb.rxd <= $urandom_range(0, 255);
23     top_tb.rx_dv <= 1'b1;
24     `uvm_info("my_driver", "data is drived", UVM_LOW);
25   end
26   @(posedge top_tb.clk);
27   top_tb.rx_dv <= 1'b0;
28   phase.drop_objection(this);
29 endtask

在開始學習時,讀者可以簡單地將drop_objection語句當成是finish函數的替代者,只是在drop_objection語句之前必須先調用raise_objection語句,raise_objection和drop_ objection總是成對出現。加入objection機制后再運行驗證平臺,可以發現“data is drived”按照預期輸出了256次。

raise_objection語句必須在main_phase中第一個消耗仿真時間(所謂仿真時間,是指$time函數打印出的時間。與之相對的還有實際仿真中所消耗的CPU時間,通常說一個測試用例的運行時間即指CPU時間,為了與仿真時間相區分,本書統一把這種時間稱為運行時間。)的語句之前。如$display語句是不消耗仿真時間的,這些語句可以放在raise_objection之前,但是類似@(posedge top.clk)等語句是要消耗仿真時間的。按照如下的方式使用raise_objection是無法起到作用的:

代碼清單 2-10

task my_driver::main_phase(uvm_phase phase);
   @(posedge top_tb.clk);
   phase.raise_objection(this);
   `uvm_info("my_driver", "main_phase is called", UVM_LOW);
   top_tb.rxd <= 8'b0;
   top_tb.rx_dv <= 1'b0;
   while(!top_tb.rst_n)
      @(posedge top_tb.clk);
   for(int i = 0; i < 256; i++)begin
      @(posedge top_tb.clk);
      top_tb.rxd <= $urandom_range(0, 255);
      top_tb.rx_dv <= 1'b1;
      `uvm_info("my_driver", "data is drived", UVM_LOW);
   end
   @(posedge top_tb.clk);
   top_tb.rx_dv <= 1'b0;
   phase.drop_objection(this);
endtask

*2.2.4 加入virtual interface

在前幾節的例子中,driver中等待時鐘事件(@posedge top.clk)、給DUT中輸入端口賦值(top.rx_dv<= 1'b1)都是使用絕對路徑,絕對路徑的使用大大減弱了驗證平臺的可移植性。一個最簡單的例子就是假如clk信號的層次從top.clk變成了top.clk_inst.clk,那么就需要對driver中的相關代碼做大量修改。因此,從根本上來說,應該盡量杜絕在驗證平臺中使用絕對路徑。

避免絕對路徑的一個方法是使用宏:

代碼清單 2-11

`define TOP top_tb
task my_driver::main_phase(uvm_phase phase);
   phase.raise_objection(this);
   `uvm_info("my_driver", "main_phase is called", UVM_LOW);
   `TOP.rxd <= 8'b0;
   `TOP.rx_dv <= 1'b0;
   while(!`TOP.rst_n)
      @(posedge `TOP.clk);
   for(int i = 0; i < 256; i++)begin
      @(posedge `TOP.clk);
      `TOP.rxd <= $urandom_range(0, 255);
      `TOP.rx_dv <= 1'b1;
      `uvm_info("my_driver", "data is drived", UVM_LOW);
   end
   @(posedge `TOP.clk);
   `TOP.rx_dv <= 1'b0;
   phase.drop_objection(this);
endtask

這樣,當路徑修改時,只需要修改宏的定義即可。但是假如clk的路徑變為了top_ tb.clk_inst.clk,而rst_n的路徑變為了top_tb.rst_inst.rst_n,那么單純地修改宏定義是無法起到作用的。

避免絕對路徑的另外一種方式是使用interface。在SystemVerilog中使用interface來連接驗證平臺與DUT的端口。interface的定義比較簡單:

代碼清單 2-12

文件:src/ch2/section2.2/2.2.4/my_if.sv
4 interface my_if(input clk, input rst_n);
5 6   logic [7:0] data;
7   logic valid;
8 endinterface

定義了interface后,在top_tb中實例化DUT時,就可以直接使用:

代碼清單 2-13

文件:src/ch2/section2.2/2.2.4/top_tb.sv
17 my_if input_if(clk, rst_n);
18 my_if output_if(clk, rst_n);
19 20 dut my_dut(.clk(clk),
21            .rst_n(rst_n),
22            .rxd(input_if.data),
23            .rx_dv(input_if.valid),
24            .txd(output_if.data),
25            .tx_en(output_if.valid));

那么如何在driver中使用interface呢?一種想法是在driver中聲明如下語句,然后再通過賦值的形式將top_tb中的input_if傳遞給它:

代碼清單 2-14

class my_driver extends uvm_driver;
  my_if  drv_if;
  …
endclass

讀者可以試一下,這樣的使用方式是會報語法錯誤的,因為my_driver是一個類,在類中不能使用上述方式聲明一個interface,只有在類似top_tb這樣的模塊(module)中才可以。在類中使用的是virtual interface

代碼清單 2-15

文件:src/ch2/section2.2/2.2.4/my_driver.sv
3 class my_driver extends uvm_driver;
4 5   virtual my_if vif;

在聲明了vif后,就可以在main_phase中使用如下方式驅動其中的信號:

代碼清單 2-16

文件:src/ch2/section2.2/2.2.4/my_driver.sv
23 task my_driver::main_phase(uvm_phase phase);
24    phase.raise_objection(this);
25    `uvm_info("my_driver", "main_phase is called", UVM_LOW);
26    vif.data <= 8'b0;
27    vif.valid <= 1'b0;
28    while(!vif.rst_n)
29       @(posedge vif.clk);
30    for(int i = 0; i < 256; i++)begin
31       @(posedge vif.clk);
32       vif.data <= $urandom_range(0, 255);
33       vif.valid <= 1'b1;
34       `uvm_info("my_driver", "data is drived", UVM_LOW);
35    end
36    @(posedge vif.clk);
37    vif.valid <= 1'b0;
38    phase.drop_objection(this);
39 endtask

可以清楚看到,代碼中的絕對路徑已經消除了,大大提高了代碼的可移植性和可重用性。

剩下的最后一個問題就是,如何把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操作:

代碼清單 2-17

文件:src/ch2/section2.2/2.2.4/top_tb.sv
44 initial begin
45   uvm_config_db#(virtual my_if)::set(null,"uvm_test_top", "vif", input_if);
46 end

在my_driver中,執行get操作:

代碼清單 2-18

文件:src/ch2/section2.2/2.2.4/my_driver.sv
13   virtual function void build_phase(uvm_phase phase);
14     super.build_phase(phase);
15     `uvm_info("my_driver", "build_phase is called", UVM_LOW);
16     if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
17        `uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
18   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的實例。讀者可以通過把代碼清單2-3中的語句插入my_driver(build_phase或者main_phase)中來驗證。

無論傳遞給run_test的參數是什么,創建的實例的名字都為uvm_test_top。由于set操作的目標是my_driver,所以set函數的第二個參數就是uvm_test_top。set函數的第一個參數null以及get函數的第一和第二個參數可以暫時放在一邊,后文會詳細說明。

set函數與get函數讓人疑惑的另外一點是其古怪的寫法。使用雙冒號是因為這兩個函數都是靜態函數,而uvm_config_db#(virtual my_if)則是一個參數化的類,其參數就是要寄信的類型,這里是virtual my_if。假如要向my_driver的var變量傳遞一個int類型的數據,那么可以使用如下方式:

代碼清單 2-19

initial begin
   uvm_config_db#(int)::set(null, "uvm_test_top", "var", 100);
end

而在my_driver中應該使用如下方式:

代碼清單 2-20

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中這么做:

代碼清單 2-21

initial begin
   uvm_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中這么做:

代碼清單 2-22

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
主站蜘蛛池模板: 体育| 尼玛县| 古交市| 邯郸县| 牙克石市| 尚志市| 溆浦县| 拉萨市| 花莲县| 铜川市| 元阳县| 浦北县| 论坛| 长治县| 喀喇| 遵义县| 盈江县| 吴忠市| 温州市| 清徐县| 利辛县| 建德市| 望谟县| 洪洞县| 江西省| 礼泉县| 长丰县| 湛江市| 阜新| 新竹县| 邹平县| 仁化县| 贵德县| 安泽县| 高邮市| 东明县| 于都县| 封丘县| 汝阳县| 温宿县| 视频|