1. 前言
在數位電路設計與FPGA開發領域中廣泛使用的硬體描述語言 Verilog。其中的「wait 敘述」是一個重要的語法,它能在特定條件成立之前暫停處理,對於靈活的模擬控制與測試平台(testbench)的撰寫非常有幫助。
Verilog 的 wait 敘述雖然語法簡單,但具有強大的表達能力,常用於等待訊號的上升沿或特定事件的發生。然而,若使用方式或注意事項掌握不當,也可能導致意料之外的行為。正確理解與活用 wait 敘述,能直接提升設計品質與驗證效率。
本文將針對 Verilog 的 wait 敘述進行徹底解析,從基礎語法到實際使用方法,再到 testbench 中的應用範例與避免問題的技巧,並以淺顯易懂的方式介紹,讓初學者與日常從事設計與驗證的工程師都能受益。
熟練運用 Verilog 的 wait 敘述,可以讓電路模擬的效率大幅提升。透過本文,讓我們一起掌握 wait 敘述的核心與應用能力。
2. wait 敘述的基本語法與運作原理
在 Verilog 中,wait 敘述是一種控制語法,用於模擬時「希望在某個條件成立前暫停處理」的情況。最基本的寫法如下:
wait (條件式);
在這個語法中,指定的條件式在變為真(true)之前,後續處理不會被執行。一旦條件成立,程式就會繼續執行 wait 之後的敘述。
2.1 基本用法
wait 敘述主要用於 always 區塊 或 initial 區塊 中。例如,希望在訊號 ready
變為 1 之前暫停處理,可以這樣寫:
wait (ready == 1'b1);
在這種情況下,程式會停在 wait 敘述,直到 ready
變成 1 時才繼續往下執行。條件式中也可以使用邏輯運算子或多個訊號的組合。
2.2 與其他控制敘述的差異
Verilog 中還有 if 敘述、while 敘述、forever 敘述等控制結構,但 wait 的行為有所不同:
- if 敘述:只判斷一次條件,若成立才執行。
- while 敘述:在條件成立期間重複執行。
- wait 敘述:會「持續等待直到條件成立」,並且僅在條件滿足的那一刻繼續後續處理。
2.3 適用的情境
wait 敘述常用於需要等待特定事件或訊號狀態的場合。例如,輸入訊號的上升緣、模組初始化完成、testbench 中等待外部條件成立等,都是模擬中進行「時序控制」的常見技巧。
3. wait 敘述的適用與限制
wait 敘述雖然是 Verilog 中靈活的模擬控制工具,但並非所有地方都能使用。以下整理出適用場合與應避免的場合。
3.1 可以使用 wait 的情境
wait 敘述主要用於初始化或模擬控制目的的區塊中,例如:
- initial 區塊
- 常用於模擬開始時等待特定條件或事件發生,例如初始化程序。
- always 區塊
- 根據訊號變化逐步推進處理時,可以作為條件等待使用。
範例:
initial begin
wait (reset_n == 1'b1); // 等待 reset 解除
// 初始處理
end
always begin
wait (data_valid); // 等待資料有效
// 資料處理
end
3.2 不適合或禁止使用的情境
雖然 wait 很方便,但並非所有位置都能使用。以下情境應避免:
- 程序區塊外(例如模組本體直下或 assign 敘述)禁止使用
wait 必須放在 initial 區塊或 always 區塊等「程序化描述」中。 - RTL 合成(硬體合成)設計中原則上不建議使用
wait 是模擬專用語法,一般邏輯合成工具不支援。 - 因此,在 FPGA 或 ASIC 的合成設計中應避免使用。
3.3 與 VHDL 的 wait 敘述差異
另一種硬體描述語言 VHDL 也有 wait 敘述,但與 Verilog 的用法不同。
在 VHDL 中,有「wait until」或「wait for」等多種形式,自由度更高;而 Verilog 僅限於 wait(條件),主要用於等待訊號狀態改變。
4. 常見的使用模式與範例
Verilog 的 wait 敘述能在「特定條件成立前暫停處理」,因此被廣泛應用於多種場景。以下介紹常見模式與代表性範例。
理解這些用法後,對 wait 敘述的印象將更為具體。
4.1 等待時脈邊緣或訊號轉換
典型的情境是「等待訊號變為 1」或「等待 reset 訊號解除」等。也就是等待訊號的上升/下降。
initial begin
// 等待 reset 解除
wait (reset_n == 1'b1);
// 從這裡開始寫初始化處理
end
always begin
// 等待 data_valid 訊號
wait (data_valid == 1'b1);
// 當 data_valid 為 1 時進行處理
end
4.2 複數條件或邏輯運算的等待
wait 的條件式可以包含邏輯運算,因此能指定多個訊號的組合條件。
wait ((ready == 1'b1) && (start == 1'b1));
透過 AND / OR 運算,可以實現更複雜的時序控制。
4.3 等待事件發生(例:訊號變化/上升緣)
當需要「在特定訊號變化後才動作」時,wait 也很方便。
不過若僅需偵測「值的改變」,通常會與事件控制符(@)或 always 敘述搭配。
wait (enable == 1'b1);
4.4 監控旗標或狀態的等待
在 testbench 中,經常需要等待外部旗標或模組狀態變化完成後再繼續。
wait (send_done == 1'b1);
4.5 實用情境範例
- 等待固定次數的時脈:可透過計數器搭配事件控制實現。
integer i;
for (i = 0; i < 10; i = i + 1) begin
@(posedge clk); // 等待時脈上升沿 10 次
end
※這不是單獨的 wait,而是與事件控制搭配的範例。
5. 在 Testbench 中活用 wait 的技巧
在 Verilog 建立 testbench 時,wait 敘述是控制模擬流程的強力工具。由於 testbench 常需要等待裝置外部輸入或特定事件,因此 wait 的應用幾乎不可或缺。以下介紹常見的使用範例。
5.1 等待初始 reset 解除
許多電路設計一開始都會先進行 reset,因此在 reset 解除後才進行下一步驗證是基本流程。利用 wait 可以簡單實現。
initial begin
// 等待 reset 訊號解除
wait (reset_n == 1'b1);
// 接著投入測試資料或開始動作驗證
end
5.2 等待訊號上升/下降
在 testbench 中,常需要等待「資料有效訊號」或「旗標訊號」的上升或下降,再適時送入資料。
wait (data_valid == 1'b1);
// 驗證輸出資料
wait (busy == 1'b0);
5.3 通訊協定的握手等待
在序列通訊或 handshake 訊號等場合,常有多個事件連續發生,wait 敘述能簡潔描述。例如「等待傳送完成旗標為 1」:
wait (tx_done == 1'b1);
5.4 Testbench 中使用 wait 的注意事項
在 testbench 使用 wait 時,需留意條件永遠不成立的風險。若條件一直不滿足,模擬會卡住。建議搭配timeout 機制或異常提示使用。
initial begin
integer timeout;
timeout = 0;
while (reset_n != 1'b1 && timeout < 1000) begin
#1; // 每次延遲一個時間單位
timeout = timeout + 1;
end
if (timeout == 1000)
$display("Error: reset_n 未被解除");
end
如此一來,即使條件未達成,也能安全結束模擬並輸出錯誤訊息。
6. 常見錯誤與除錯技巧
wait 敘述雖然實用,但若使用不當可能造成模擬異常。本章介紹常見問題與對策。
6.1 進入無限等待
最典型的問題是條件永遠不成立,模擬無限卡住。例如初始化錯誤、訊號未正確變化、設計失誤等。
解決方法:
- 確認等待的訊號是否真的會在模擬中變化
- 在 testbench 明確設定初值或切換模式
- 加入 timeout,避免永遠停滯
integer timeout;
timeout = 0;
while (flag != 1'b1 && timeout < 1000) begin
#1;
timeout = timeout + 1;
end
if (timeout == 1000)
$display("Error: flag 未變為 1");
6.2 條件式書寫錯誤
若在 wait 條件式誤寫錯誤值或邏輯,會導致行為與預期不同。特別是複數條件組合時更要小心。
解決方法:
- 檢查括號與運算子是否正確
- 透過 $display 印出訊號值確認狀態
6.3 競賽條件與非預期的模擬進程
當 wait 與其他事件控制(如 @
或 always)混合使用時,可能因訊號變化時序造成執行順序非預期。
解決方法:
- 明確規劃訊號觸發點(posedge / negedge 等)
- 必要時與事件控制或 #delay 搭配使用
6.4 除錯的小技巧
- 使用 $display
在 wait 前後輸出變數與時間,確認停在哪裡 - 檢查條件成立瞬間
在條件成立時輸出 log,確認跳出點 - 由簡單情境開始測試
先確認單一訊號等待是否正常,再加入複雜條件
掌握這些技巧,可提升模擬的穩定性與除錯效率。
7. 提升模擬效率的技巧
在 Verilog 模擬中,若能將 wait 與其他控制手法靈活搭配,就能大幅提升驗證效率。本章介紹幾種以 wait 為核心的效率提升技巧。
7.1 wait 與 #delay(延遲敘述)的差異與取捨
wait 與 #delay
都能「等待」,但使用情境不同:
- wait 敘述:等待特定條件(如訊號值或狀態)成立
範例:wait (ready == 1'b1);
- #delay 敘述:純粹延遲指定時間
範例:#10; // 等待 10 個時間單位
效率提升要點:
- 條件事件驅動 → 用 wait
- 單純時間延遲 → 用 #delay
- 正確取捨能避免不必要的迴圈或計算,加快模擬速度。

7.2 模擬加速的實際作法
- 避免不必要的迴圈與冗長等待
設計時需確認條件會改變,避免無限等待。 - 利用旗標(flag)進行有效等待
透過狀態轉移或完成通知的旗標訊號,能讓模擬更簡潔。
wait (done_flag == 1'b1);
7.3 善用 finish_flag 與 timeout
為避免模擬意外停住,testbench 常加入 finish_flag 或 timeout 機制。
wait (finish_flag == 1'b1);
$finish;
若搭配 timeout,即使模擬超時也能自動結束,避免浪費時間。
7.4 與事件驅動搭配
wait 可以與 @
事件控制或 fork/join
並行結構結合,形成更靈活的驗證手法。
fork
wait (signal_a == 1'b1);
wait (signal_b == 1'b1);
join
這樣可以同時監控多個事件,減少遺漏,提升驗證效率。
有效率的模擬設計,能直接影響專案的開發速度與品質。
8. 與 SystemVerilog 及其他語言比較
Verilog 的 wait 敘述雖然簡單,但近年來 SystemVerilog 與 VHDL 等語言提供更多強化功能。本章比較各語言差異。
8.1 SystemVerilog 的擴充
SystemVerilog 作為 Verilog 的上位相容,對 wait 加入了幾個強化功能:
- wait fork/join:等待多個並行程序完成
例:fork ... join wait fork;
- wait order:可指定多個條件需依序成立(部分工具支援)
- event / semaphore 搭配:可靈活等待使用者自訂事件或同步控制
8.2 Verilog 與 VHDL 的差異
- VHDL 的 wait:語法多樣,如
wait until (條件);
、wait for 100 ns;
- Verilog 的 wait:僅有
wait (條件);
,時間等待需用#delay
或@(posedge clk)
總結: VHDL 的 wait 本身涵蓋多功能,而 Verilog 則需搭配其他語法組合使用。
8.3 與其他控制流程比較
Verilog 除了 wait,還有 if
、while
、forever
、@
等控制結構。
wait 專注於「條件成立前暫停」,若與其他控制敘述搭配,能更精準實現時序控制。
9. 透過圖解與波形理解 wait
要直觀理解 wait,利用時序圖或波形圖非常有效。以下用範例示意。
9.1 基本動作示意
例如等待「reset_n 變為 1」:
initial begin
wait (reset_n == 1'b1);
// 後續處理
end
Time | 0 | 10 | 20 | 30 | 40 | 50 | ...
reset_n 0 0 1 1 1 1
<---wait---> |----→ 開始後續處理
9.2 訊號上升/事件偵測
always begin
wait (data_valid == 1'b1);
// 資料處理
end
Time | 0 | 10 | 20 | 30 | 40 | 50 | ...
data_valid 0 0 0 1 0 1
<---wait---> |---開始處理
9.3 複數條件等待
wait ((ready == 1'b1) && (start == 1'b1));
Time | ... | 40 | 50 | 60 | 70 | ...
ready 0 1 1 1
start 0 0 1 1
<-----wait------>| 後續開始(ready 與 start 同為 1)
9.4 狀態轉移與 Testbench 範例
在 testbench 中,常會根據狀態與事件變化進行驗證。利用波形圖可直觀檢視 wait 的動作,幫助理解複雜時序。
10. 常見問題(FAQ)
以下整理了在使用 Verilog wait 敘述時,經常遇到的疑問與實務困擾,以 Q&A 形式解答。
Q1. wait 與 #delay(延遲)有何不同?
A. wait 是「等待條件成立才繼續執行」,而 #delay 是「單純等待指定時間」。
wait 適合用於事件或訊號觸發,#delay 則適合用於時間控制。
Q2. wait 可以用在 always 區塊嗎?
A. 可以。在 always 區塊中可用來等待特定訊號或事件。但注意:若是合成用的 always 區塊,原則上不建議使用,因為 wait 僅適用於模擬。
Q3. wait 可以在硬體合成(FPGA/ASIC)中使用嗎?
A. 不行。wait 是模擬專用語法,大多數合成工具不支援,因此不應出現在 RTL 合成設計中。
Q4. 為什麼 wait 沒有動作/無法跳出?
A. 最常見原因是「等待的訊號未如預期變化」。建議檢查波形或用 $display 輸出訊號值,並加入 timeout 機制避免死等。
Q5. VHDL 的 wait 與 Verilog 的 wait 有什麼差異?
A. VHDL 的 wait 形式多樣(如 wait until、wait for),控制自由度較高;Verilog 的 wait 僅限於「等待條件成立」,時間等待則需搭配 #delay 或 @ 事件控制。
Q6. 事件控制(@)與 wait 的差異是?
A. @
是在特定事件(如正緣或負緣)發生時觸發處理;wait 則是持續判斷條件是否成立,一旦條件為真才繼續。
例:@(posedge clk)
與 wait(clk == 1)
看似類似,但前者針對邊緣事件,後者針對邏輯條件。
Q7. 模擬停住不動怎麼辦?
A. 多半是等待條件永遠不成立。需檢查初始值與訊號變化,並加入 timeout 防護。
Q8. 可以在條件中使用多個訊號嗎?
A. 可以。可用 AND(&&)或 OR(||)等邏輯運算子組合。
例:wait((ready == 1'b1) && (start == 1'b1));
11. 總結與延伸閱讀
本文從基礎到應用,完整介紹了 Verilog wait 敘述。以下整理重點:
11.1 重點整理
- wait 是 Verilog 中用來「等待條件成立」的控制語法,常用於 testbench 與模擬控制。
- 基本語法:
wait (條件);
可搭配單一或多重條件。 - 常見應用: 等待 reset 解除、訊號變化、資料傳輸完成等。
- 僅限模擬使用:不適合出現在 RTL 合成設計。
- 需防範錯誤: 無限等待、條件式誤寫、競賽條件等問題。
- 可與其他控制語法搭配(如 @、#delay、fork/join),打造更靈活的驗證流程。
- 了解 SystemVerilog 與 VHDL 的差異,有助於跨語言設計與驗證。
正確理解與運用 wait 敘述,不僅能提升模擬效率,也能大幅改善設計品質。希望本文能幫助您在實務設計與驗證工作中更熟練掌握 Verilog。
本篇「Verilog wait 敘述徹底解析」到此結束,若想進一步學習,建議閱讀更多相關的測試平台設計與模擬技巧文章。