1. 程式人生 > >SV元件實現篇之七(終):測試環境的報告規範

SV元件實現篇之七(終):測試環境的報告規範

本文轉自:http://www.eetop.cn/blog/html/28/1561828-2316832.html

文章結構:

  • 通過一種標準化的方式列印資訊
  • 過濾(重要級別)資訊
  • 列印通道

在之前的介紹中,讀者從四位verifier的驗證元件實現中懂得了通過類和封裝和資料隨機化來實現stimulator、monitor和checker,而在這三個元件中間的資訊輸出也是無時不在的。伴隨著驗證元件的增多(橫向的)和驗證層次的加深(縱向的),驗證環境對於資訊報告的要求也趨於規範。為什麼會有這樣的要求呢?讀者可以試想一下這幾種場景:

  1. 伴隨著元件的增多,任何的元件都有可能打印出來資訊,當然同一組件的不同例化物件也會打印出來資訊。那麼,我們需要區分的是,這些打印出來的資訊從什麼元件、什麼物件中打印出來,即這是關於標準化的資訊列印方法,打印出來的資訊需要包含“出處”和“內容”。
  2. 在一開始驗證環境需要除錯時,除了直接設定斷點進行單步除錯激勵的產生、協議的握手之外,更直觀的方式就是插入一些“瑣碎”的列印資訊來告訴verifier程式碼執行過的痕跡。而到了後期,一旦stimulator的激勵穩定之後,這些原來用於除錯的列印資訊則變得不那麼重要了,甚至有一點“多餘”,這時候,我們反而需要關閉這些繁瑣的資訊,只需要保留一些重要的資訊。那麼從一個例子來看,不同資訊之間需要有一個重要的區分,即資訊的重要級別(severity level)。
  3. 資訊之間的區別除了重要級別之外,另外一個常見的就是資訊種類,這會包括有資訊型別(info)、警告型別(warning)、錯誤型別(error)以及致命型別(fatal)。針對這些不同的種類,我們可以設定相應的處理方式,除了info型別一般只用來列印之外,warning型別和error型別可以額外設定為讓模擬停止,而fatal型別則應該讓模擬結束。
  4. 資訊除了可以列印到模擬視窗之外,還可以列印到文本里。這使得驗證的資訊可以同其它模擬資訊最直接的區別開來,便於資訊的瀏覽和查詢。所以,關於報告資訊的列印通道是也是報告規範化的一項要求。

 

我們接下來,就上面關於驗證環境報告標準化的要求推出一個簡短易用的庫來封裝這些報告要求,並且可以通過在呼叫這些報告方法時,配置好資訊的出處、種類和重要級別,同時也可以針對不同種類資訊作出不同的處理方式。

 

資訊報告庫的例碼

下面這個包report_pkg是一個簡易的報告標準化庫,除了定義跟資訊型別和重要級別相關的列舉型別之外,就提供了一個封裝好的報告資訊函式rpt_msg()。這個函式的幾個引數分別是,報告資訊來源string s,報告資訊內容string i,報告型別report r,資訊重要級別severity_t s以及採取的動作action_t a。在呼叫該函式時,除了需要顯式傳遞資訊來源和資訊內容之外,剩餘的三個引數可以使用預設值,即預設資訊種類是INFO,重要級別是LOW,採取的行動是列印資訊到螢幕和文字中。另外還提供了一個擦鞋報告文字的小函式clean_log()。在這個report_pkg中,變數severity_t svrt和string logname被定義為靜態變數,是為了以後可以更好地控制過濾資訊的重要級別,和資訊報告的檔名稱。

package report_pkg;
typedef enum {INFO, WARNING, ERROR, FATAL} report_t;
typedef enum {LOW, MEDIUM, HIGH, TOP} severity_t;
typedef enum {LOG, STOP, EXIT} action_t;

static severity_t svrt = LOW;
static string logname = "report.log";

function void rpt_msg(string src, string i, report_t r=INFO, severity_t s=LOW, action_t a=LOG);
integer logf;
string msg;
if(s >= svrt) begin
msg = $sformatf("@%0t [%s] %s : %s", $time, r, src, i);
logf = $fopen(logname, "a+");
$display(msg);
$fwrite(logf, $sformatf("%s\n", msg));
$fclose(logf);
if(a == STOP) begin
$stop();
end
else if(a == EXIT) begin
$finish();
end
end
endfunction

function void clean_log();
integer logf;
logf = $fopen(logname, "w");
$fclose(logf);
endfunction
endpackage

 

實際使用場景

在擁有了一個資訊標準化的包之外,我們模擬了一個簡單的層次化驗證場景來說明有了這樣一個資訊標準化庫之後帶來的好處。下面的程式碼是一個模擬化的stimulator、monitor、checker、environment和tb。這些程式碼的共同地方在於它們都呼叫了report_pkg包中的報告方法rpt_msg。

class rpt_stm; // stimulator定義
string id;
function new(string name = "rpt_stm");
id = name;
rpt_msg(id, "build phase");
endfunction
task run();
int i=1;
rpt_msg(id, "run phase");
forever begin
#100;
rpt_msg(id, $sformatf("NO.%0d trans generated!",i));
i++;
end
endtask
endclass

class rpt_mon; // monitor定義
string id;
function new(string name = "rpt_mon");
id = name;
rpt_msg(id, "build phase");
endfunction
task run();
int i=1;
rpt_msg(id, "run phase");
#30;
forever begin
#80;
rpt_msg(id, $sformatf("NO.%0d input trans monitored!",i));
#20;
rpt_msg(id, $sformatf("NO.%0d ouput trans monitored!",i));
i++;
end
endtask
endclass

class rpt_chk; // checker定義
string id;
function new(string name = "rpt_chk");
id = name;
rpt_msg(id, "build phase");
endfunction
task run();
int i=1;
bit cmp;
rpt_msg(id, "run phase");
#40;
forever begin
#100;
std::randomize(cmp) with {cmp dist {1 :=3, 0:= 1};};
if(cmp)
rpt_msg(id, $sformatf("NO.%0d trans was compared with success",i), , HIGH);
else
rpt_msg(id, $sformatf("NO.%0d trans was compared with failure",i), ERROR, HIGH, STOP);
i++;
end
endtask
endclass

class rpt_env; // environment定義
string id;
rpt_stm stm;
rpt_mon mon;
rpt_chk chk;

function new(string name = "rpt_env");
id = name;
rpt_msg(id, "build phase");
stm = new("stm");
mon = new("mon");
chk = new("chk");
endfunction

task run();
rpt_msg(id, "run phase");
fork
stm.run();
mon.run();
chk.run();
join_none
endtask
endclass

module rpt_tb; // testbench定義
rpt_env env;
initial begin: build
rpt_msg("tb", "build phase");
env = new("env");
clean_log();
end
initial begin: run
#0;
rpt_msg("tb", "run phase");
env.run();
end

endmodule

 

這個testbench的結構也很簡單,即在testbench中例化了一個軟體頂層環境元件rpt_env,而在該頂層環境rpt_env中又進一步例化了三個必要的元件rpt_stm、rpt_mon和rpt_chk。上面這段模擬驗證環境的程式碼中,每個元件都使用了標準化報告函式rpt_msg,因此在模擬開始後,打印出的結果如下:


 

# @0 [INFO] tb : build phase
# @0 [INFO] env : build phase
# @0 [INFO] stm : build phase
# @0 [INFO] mon : build phase
# @0 [INFO] chk : build phase
# @0 [INFO] tb : run phase
# @0 [INFO] env : run phase
# @0 [INFO] stm : run phase
# @0 [INFO] mon : run phase
# @0 [INFO] chk : run phase
# @100 [INFO] stm : NO.1 trans generated!
# @110 [INFO] mon : NO.1 input trans monitored!
# @130 [INFO] mon : NO.1 ouput trans monitored!
# @140 [INFO] chk : NO.1 trans was compared with success
# @200 [INFO] stm : NO.2 trans generated!
# @210 [INFO] mon : NO.2 input trans monitored!
# @230 [INFO] mon : NO.2 ouput trans monitored!
# @240 [INFO] chk : NO.2 trans was compared with success
# @300 [INFO] stm : NO.3 trans generated!
# @310 [INFO] mon : NO.3 input trans monitored!
# @330 [INFO] mon : NO.3 ouput trans monitored!
# @340 [INFO] chk : NO.3 trans was compared with success
# @400 [INFO] stm : NO.4 trans generated!
# @410 [INFO] mon : NO.4 input trans monitored!
# @430 [INFO] mon : NO.4 ouput trans monitored!
# @440 [ERROR] chk : NO.4 trans was compared with failure

從上面的報告結果可以看出:

  • 在模擬一開始,軟體環境(驗證部分)的建立(build)是自頂向下的,而執行(run)也是自頂向下的。
  • 在特定的時間點,所有元件都可以通過rpt_msg()函式打印出來包含資訊源和資訊內容的報告。
  • 在可能出現錯誤的語句分支,可以打印出錯誤資訊,並且告知模擬器停止。例如rpt_chk在比較發生錯誤之後,可以打印出ERROR型別的資訊,並且讓模擬暫停。

 

上面的輸出結果是在模擬器的視窗中輸出的,同時這些資訊也一併列印到報告日誌report.log中了。從輸出結果的最後一行顯示中可以發現,rpt_chk比較資料發生錯誤,因此報告了ERROR資訊,同時讓模擬停止,以便於verifier可以在發生錯誤的時間點附近除錯資料比較的錯誤原因。

 

正如本文一開始談到的,通過這個精簡的規範報告包report_pkg,可以滿足日常報告的基本需求即:

  • 資訊包括報告出處和內容。
  • 具備資訊型別。
  • 具備資訊重要級別。
  • 有可控的模擬器行為和列印通道。

 

我們可以再進一步考慮實際中關於資訊重要級別的一個應用,即伴隨著環境的穩定性,我們只需要一些重要的資訊,而捨棄一些關於驗證結構搭建、執行順序和細節的報告。那麼,我們可以在頂層rpt_tb中的build階段做出簡單配置就可以對報告的內容做出過濾:

module rpt_tb;
rpt_env env;
initial begin: build
report_pkg::svrt = HIGH; // 修改可以列印的最低資訊重要級別
report_pkg::logname = "test.log"; // 設定列印的報告日誌名稱
rpt_msg("tb", "build phase");
env = new("env");
clean_log();
end

initial begin: run
#0
rpt_msg("tb", "run phase");
env.run();
end
endmodule

 

在rpt_tb的build階段,我們首先修改report_pkg的兩個靜態變數svrt和logname,這樣可以過濾一些低級別的資訊,同時也可以重定向報告日誌的輸出檔案。於是,在模擬器和新的報告日誌test.log中,只出現了在HIGH級別以上的重要資訊:

# @140 [INFO] chk : NO.1 trans was compared with success
# @240 [INFO] chk : NO.2 trans was compared with success
# @340 [INFO] chk : NO.3 trans was compared with success
# @440 [ERROR] chk : NO.4 trans was compared with failure

 

通過上面的精簡庫report_pkg,使用者可以小窺到讓報告標準化的魅力,而伴隨著方法學的發展和驗證環境的結構性和複雜性,UVM方法學自身提供的報告機制會更加充分(體量也更龐大一點)。同時,通過這個例子可以得到另外的提示,即在簡單的SV驗證元件實現過程中,我們可以考慮將日常用到的公共方法加以標準化,做成一些可以共享的公共庫,在公司內部甚至驗證行業大的生態中形成開源的公共庫,這也是軟體世界中常見的快速構建上層結構、避免“重複製造輪子”的有益做法。