systemverilog 內容龐雜,需要不停的花時間,不停的思考與練習。保持謙虛不急不躁的心態,穩步學習。路漫漫其修遠兮,吾將上下而求索。
實際硬件中,時序邏輯通過時鍾沿激活,組合邏輯的輸出則隨着輸入的變化而變化。在測試平台的環境里,大多數語句塊被模擬成事務處理器,並運行在各自的線程里。
Systemverilog 每個線程總是會跟相鄰的線程通信。這里涉及到測試平台組成問題。環境類需要知道發生器什么時候完成任務,以便及時終止測試平台中還在運行的線程。這個過程需要用線程間通信IPC來完成。
常見的線程通信有:event,wait,Systemverilog mailbox,Systemverilog semaphone。
注意:在systemverilog中 線程thread,進程process是一個東西
一:線程的使用
systemverilog在verilog基礎上擴展兩種線程:
fork
...
join
fork
...
join_none
fork
...
join_any
測試平台通過已有的結構來實現線程間的通信,同步以及對線程 的控制。
下面列舉systemverilog for verification的代碼進一步說明用法加深理解
fork_join:
VCS運行結果:
記得我第一次做這個example時,人是暈的,下面來重新理一理:
begin....end是順序執行,從上至下執行,如果帶延時肯定按照延時來
fork...join是並行執行,只有當fork塊的代碼全部執行完畢,才會往下走。
fork...begin...end...join 帶延時這個問題,即便join后面的內容發生時間再前,同樣也不會執行。
-----------------------------------------分割線----------------------------------------------
fork...join_none:產生線程
fork...join_none在調度其塊內語句時,父線程繼續執行。代碼與fork...join一致
注意:fork...join_none后面那一條語句執行早於塊內任何一條語句。
-----------------------------------------分割線----------------------------------------------
fork...join_any:實現線程同步
fork...join_any 第一個語句完成后,父線程才繼續執行,其他停頓的線程也繼續。代碼與fork...join一致
fork...join_any的代碼中display("after join_any")完成於並發塊內第一個語句之后。
-----------------------------------------分割線----------------------------------------------
二:動態線程:使用fork_join_none 可以開啟一個線程,比如隨機事務發生器的代碼。使用fork...join_none可以使代碼不發生阻塞
綠皮書183示例代碼:
class Gen_drive
task run(int n);
Packet p;
fork
repeat(n)begin
p = new();
assert(p.randomzie());
transmit(p);
end
join_none;
endtask
task trnansmit(input Packet p);
...
endtask
endclass
Gen_drive gen;
initial beign
gen = new();
gen.run(10);
...
end
以上代碼並不是在new()函數中啟動的,構造函數只用來對數值進行初始化,並不啟動任何線程,把構造函數同真正進行事務處理的代碼分開,允許在開始執行事務處理代碼之前修改任何變量,這樣,就可以引入錯誤檢測,修改缺省值或變更代碼的行為。
任務run通過fork..join_none塊啟動了一個線程,用於具體事務處理,該線程不是在父類中啟動,而是run之后產生的。
在動態線程中,任務被調用,就可以產生一個線程總線以獲取匹配的事務地址。在並發線程中務必使用自動變量來保存數值。
錯誤示例:
program mo_auto;
initial begin
for(int j = 0;j < 3;j ++)
fork
$write(j);
join_none
#0 $display("\n");
end
endprogram