前言
前文提要:
【芯片前端】一鍵生成簡易版本定向RTL驗證環境的腳本——auto_verification_rtl腳本_尼德蘭的喵的博客-CSDN博客
【芯片前端】可能是定向驗證的巔峰之作——auto_testbench_autotestbench_尼德蘭的喵的博客-CSDN博客
工具路徑:
auto_testbench: 用于自動生成verilog rtl的定向用例仿真平臺的腳本
在上次完成自詡為“定向驗證的巔峰之作”之后,我覺得這個工具應該是寫到頭了,不過最近的實踐中我發現,對于auto_testbench的主要應用場景——CBB與UT的驗證而言,如果能不依賴于方法學進行一些簡單預期和比對,還是可以大幅收斂debug時間的。
本次升級針對握手接口(因為好久沒寫其他類型接口了),腳本的功能概述為:
- 對于握手接口單輸出的模塊,會進行符合協議的輸入隨機,會自動生成采樣與比對task,而根據輸入生成預期的task需要手動填充;
- 對于不滿足單輸出的其他握手接口模塊,會進行符合協議的輸入隨機,此時如果想要進行比對需要對環境進行比較大的改動;
- 對于其他接口模塊,會生成整套驗證環境,對接口進行初始化和隨機驅動;
- 如果不進行仿真只想編譯模塊,在tb.f中注釋掉testbench.sv路徑然后在sim路徑執行make cmp;
其他優化包括:
- 優化了生成的tb.f文件;
- 修正了模塊中有注釋是可能誤讀的問題;
- 美化和對齊了一下生成文件;
效果親測
作為一個負責人的工具發布者,發布前我先親自驗證了一下這個工具的正確性,于是翻出來了去年寫的一個cbb bypass_fifo進行了下驗證,然后發現這個cbb有BUG!不過放心,我相信這個cbb是沒有在工程中使用的。
bypass_fifo的功能是這樣,對于輸入的data,如果power為1則正常輸出,如果為0則丟棄。這個cbb聽起來很奇怪不過其實他是另外一個cbb的一部分(一對多的場景,每個數據可能有不同的通道需要)。那么看下出錯的log:
對著log找到波形的錯誤處:
然后分析下問題不是出現在'h57eadcc1這個數身上,而是出現在前一個數'hb985d7ad,RTL出口沒有就把valid和數變了!奇怪的是對于類似的場景,其他的數據在出口時序就很正確:
那么這個問題如果通過波形是否能發現呢?不是太容易:
因此,這個工具的新功能我初步認為是有效的。
使用說明
就以bypass_fifo的驗證環境生成為例,看一下如何使用。
第一步還是切換到bypass_fifo的路徑,執行:
auto_testbench -f bypass_fifo.v
#如果沒有設置全局路徑,請完整輸入auto_testbench的腳本路徑
打印信息為:
##====================================================================##
Gen over! please cd ./bypass_fifo_verification/sim
You need modify ./bypass_fifo_verification/top/testbench.svlike cp ./bypass_fifo_verification_bak/top/testbench.sv ./bypass_fifo_verification/top/
You need modify ./bypass_fifo_verification/cfg/tb.flike cp ./bypass_fifo_verification_bak/cfg/tb.f ./bypass_fifo_verification/cfg/
##====================================================================##
這里說明一下,我的本意是如果已經有bypass_fifo_verification目錄了,就把bypass_fifo_verification重命名為bypass_fifo_verification_bak,不過吧腳本寫的好像是有點問題導致這個功能時靈時不靈。
第二步,切換到bypass_fifo_verification/cfg路徑,打開tb.f文件,并按照需求修改:
+libext+.v
-y /home/ICer/gitee_path/auto_testbench/src/../ver/bypass_fifo_pkg.sv
/home/ICer/gitee_path/auto_testbench/src/bypass_fifo.v
../top/testbench.sv
第三步,切換到bypass_fifo_verification/ver路徑,檢查bypass_fifo_pkg.sv是否符合預期:
package bypass_fifo_pkg;parameter ERROR_DEBUG_CNT = 5;parameter DEPTH = 8;parameter WIDTH = 128;int error_cnt = 0;bit check_en = 0;typedef struct{bit [WIDTH -1:0] data_in;bit data_in_power;} data_in_valid_struct;data_in_valid_struct data_in_valid_bus_q[$];typedef struct{bit [WIDTH -1:0] data_out;} data_out_valid_struct;data_out_valid_struct rm_q[$];data_out_valid_struct data_out_valid_bus_q[$];endpackage
重點說bypass_fifo_pkg文件,在這個文檔中腳本根據每個valid信號的名字“推測”其它信號是否為該valid“管轄”的信號,并將結果按valid分組為struct結構。然后順便把每個數據結構的隊列進行聲明,如果是輸出的valid,那么同時聲明reference model的預期隊列。因此如果有多路valid輸出握手的話,這里的rm聲明會重復,需要手動修改。
ERROR_DEBUG_CNT表示發生錯誤的次數,check_en表示是否進行自動比對默認為0,需要進行比對時手動將這個值改為1。
第四步,切換到bypass_fifo_verification/top路徑,打開testbench.sv文件,還是如此的賞心悅目:
其他部分之前都講過,只需說明下新增的auto_verification部分即可。展開這部分可以看到如下代碼:
task in_queue_gain();while(1)begin@(negedge clk);if(data_in_valid && data_in_ready)begindata_in_valid_struct data_in_valid_dat;data_in_valid_dat.data_in = data_in;data_in_valid_dat.data_in_power = data_in_power;data_in_valid_bus_q.push_back(data_in_valid_dat);end//if-end end//while-end
endtask: in_queue_gain
對輸入進行采樣,如果有多路輸入,會在這個task里均進行采樣;
task out_queue_gain();while(1)begin@(negedge clk);if(data_out_valid && data_out_ready)begindata_out_valid_struct data_out_valid_dat;data_out_valid_dat.data_out = data_out;data_out_valid_bus_q.push_back(data_out_valid_dat);end//if-end end//while-end
endtask: out_queue_gain
對輸出進行采樣,如果有多路輸出,會在這個task里均進行采樣;
task rm_queue_gain();data_in_valid_struct data_in_valid_dat;data_out_valid_struct data_out_valid_dat;//while(1)begin//wait(data_in_valid_bus_q.size > 0);//data_in_valid_dat = data_in_valid_bus_q.pop_front();//rm_q.push_back(data_out_valid_dat);//end
endtask: rm_queue_gain
rm_queue_gain是一個空殼task,用于產生預期,里面預置了數據類型和隊列操作方法;
task queue_check();while(1)begindata_out_valid_struct rm_data;data_out_valid_struct dual_data;wait(data_out_valid_bus_q.size() > 0);dual_data = data_out_valid_bus_q.pop_front();if(rm_q.size() == 0) begin$display("dual_data = %0p, rm_queue.size = 0", dual_data);error_cnt += 1;endelse beginrm_data = rm_q.pop_front();if(dual_data != rm_data)beginerror_cnt += 1;$display("dual_data(%0p) != rm_data(%0p) at %t", dual_data, rm_data, $realtime);endelse begin//$display("dual_data(%0p) == rm_data(%0p) at %t", dual_data, rm_data, $realtime);endendif(error_cnt >= ERROR_DEBUG_CNT) begin$display("Check Error!!!");$finish;endend
endtask: queue_check
對rm_q[$]和RTL輸出接口queue[$]進行自動比對,同樣需要注意,如果有多路進行輸出,這里只會比對其中一路;
代碼的最后是固定的initial函數:
initial beginforkin_queue_gain();out_queue_gain();rm_queue_gain();if(check_en == 1) queue_check();join_none
end
然后是關鍵點,根據bypass_fifo的功能對rm_queue_gain task進行改寫,完成簡單的功能預期:
task rm_queue_gain();data_in_valid_struct data_in_valid_dat;data_out_valid_struct data_out_valid_dat;while(1)beginwait(data_in_valid_bus_q.size > 0);data_in_valid_dat = data_in_valid_bus_q.pop_front();if(data_in_valid_dat.data_in_power == 1)begindata_out_valid_dat.data_out = data_in_valid_dat.data_in;rm_q.push_back(data_out_valid_dat);endend
endtask: rm_queue_gain
至此CBB的簡單驗證環境就完成了。
切換到auto_verification/sim目錄,執行:
make run wave=on
之后根據仿真結果和波形進行debug。