前言
副標題 —— 驗證環境中bus.mon.sig與@bus.mon同時使用的反面案例哈哈哈。這個bug是在是過于經典了所以每過一段時間我就會拿出來跟人聊聊,要是沒有這個的激勵,我一定不會走上記錄bug的道路的。
事故現場
先來還原出錯的場景。代碼示意如下,驗證環境構建于module中,這段代碼的本意是希望對齊rtl的時鐘沿,因此在wait到bus.mon.vld(bus是interface,mon是clocking block)后@時鐘,之后從隊列中取數進行處理,下面的代碼我將取數調整成打印信息,本質都是執行一個操作:
initial begin
forever begin
wait (bus.mon.vld == 1'b1);
@bus.mon;
$display("%t, pop_front this cyc", $realtime);
end
end
此時RTL的波形如下,vld信號置起一拍:
當時出現的錯誤是,發現只有一拍的valid信號,但是卻發生了兩次取值行為,且發生在兩拍,那么對應打印行為就是說發生了兩次打印且在不同時刻:
2010.000ns, pop_front this cyc
2020.000ns, pop_front this cyc
為了進一步確定行為,在wait和@之后分別加入打印:
initial begin
forever begin
wait (bus.mon.vld == 1'b1);
$display("%t, wait dao le!", $realtime);
@bus.mon;
$display("%t, pop_front this cyc", $realtime);
end
end
打印結果為:
2010.000ns, wait dao le!
2010.000ns, pop_front this cyc
2010.000ns, wait dao le!
2020.000ns, pop_front this cyc
可以確定在2010ns時刻wait生效了2次,事故現場還原結束。
事故分析
明確下,這個現象是不符合代碼本意的,本意應該是一拍有效取一個數據出來,那么接下來具體分析下為什么是這種現象,由本靈魂畫手把波形畫一下!
順便在把time slot的圖搬出來對著看,因為環境搭建并啟動于于module中,只需要module regions的就夠了:
那么在2010ns時間點,進程上在做哪些事呢?
1.2010ns ts之前的1ps(interface中設置的skew)采樣rtl vld信號為1,在active-observed之間bus.mon.vld值跳變為1;
2.時鐘bus.mon在observed域跳變為1;對應的時序結構如下圖,那么也就不難發現為什么wait會判定成功2次了:
時間線也就理清楚了:
*2010ns, bus.mon.vld跳變為1 -->
*wait(bus.mon.vld)在observed之前生效 -->
*@bus.mon成功(observed域)-->
*執行環境語句,不消耗時間,forever回wait語句 -->
*wait(bus.mon.vld)再次成功,此時仍為2010ns -->
*@bus.mon不成功(關于@和wait的區別請查詢綠皮書吧),該進程等待在這里,等下一次bus.mon上升沿-->
- 時間推進到2020ns,@bus.mon成功,再一次執行下面的語句。
責任劃分
該波形是符合systemVerilog仿真規則的,但是不符合本人意圖,最好就別這么搞。乖乖的@bus.mon (if bus,mon.vld) 是最安全的。
-
RTL
+關注
關注
1文章
385瀏覽量
59706 -
VLD
+關注
關注
0文章
2瀏覽量
7172
發布評論請先 登錄
相關推薦
評論