Skip to content

Verilog · Chapter 14.4.3 · Behavioural Modeling

Level-Sensitive Timing Controls in Verilog — The wait Statement

The wait statement is Verilog's level-sensitive timing control. It blocks a procedural statement until its condition becomes true. Unlike an event control, which fires on a change such as an edge or transition, wait is sensitive to a level. If the condition is already true, execution proceeds immediately; otherwise it suspends until the condition holds. This is a simulation and testbench construct, not something you synthesize, because there is no real hardware that simply blocks until a condition is met. In practice wait is used for testbench synchronization, such as waiting for a handshake, a ready flag, or a done signal before continuing, and it never belongs in design logic. This lesson drills the level-sensitive semantics, how wait differs from the event control, and its common testbench uses.

Foundation10 min readVerilogwaitLevel SensitiveTestbenchSynchronization

Chapter 14 · Section 14.4.3 · Behavioural Modeling

1. The Engineering Problem

A testbench often needs to wait until something is ready — a ready flag, a done signal, a buffer non-empty — before proceeding. The wait statement does this, with one defining property:

wait(condition) blocks until the condition is true (level-sensitive) — proceeding immediately if it is already true. It is a simulation/testbench tool, not synthesizable.

This page drills wait and how it differs from the @ event control.

2. Mental Model — wait Blocks Until a Level Is True

3. The wait Statement

wait.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   wait(ready);                    // block until ready is 1
   data = bus;                     // then proceed
 
   wait(count == 8) $display("count reached 8");
 
   // wait for a handshake in a testbench:
   send_request();
   wait(ack);                      // block until the DUT acknowledges
   send_request_done();
  • wait(condition) suspends until condition evaluates true; if already true, no suspension.
  • It is commonly followed by a statement to run once the condition holds (wait(ready) data = bus;).
  • Used in testbenches to synchronize on DUT signals — wait for a ready, an ack, a done — without polling.

4. wait vs @ — Level vs Change

The key distinction:

wait-vs-event.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   wait(ready);     // LEVEL: proceeds as soon as ready IS 1 (now or later)
   @(ready);        // CHANGE: waits for ready to CHANGE (even 1→0); not "is 1"
   @(posedge ready);// EDGE: waits for ready to go 0→1 specifically
  • wait(ready) cares about the level — it proceeds the moment ready is (or becomes) 1.
  • @(ready) cares about a change — it waits for any transition of ready, regardless of the resulting value.
  • @(posedge ready) waits specifically for a rising edge.

Use wait when you want "proceed once this condition holds"; use @ when you want "fire on this change/edge." (@ is the synthesizable one; wait is testbench-only.)

Visual A — wait (level) vs @ (change)

wait vs @

data flow
wait vs @wait(c)level: proceeds when cIS true@(c)change: waits for c toCHANGE@(posedge c)edge: waits for c togo 0→1
wait is level-sensitive — it proceeds as soon as the condition is (or becomes) true, with no wait if already true. @ is change-sensitive — it waits for a transition. wait is a testbench synchronization tool; @ (especially the edge form) is the synthesizable trigger of hardware.

5. Common Mistakes

  1. wait in synthesizable design — not synthesizable; testbench-only (§2, DebugLab 1).
  2. Confusing wait(c) with @(c) — level (is true) vs change (transitions) (§4).
  3. wait on a condition that never becomes true — blocks forever (a testbench hang; pair with a watchdog, 8.5).

6. Debugging Lab

One wait debug post-mortem

Pitfall — wait in synthesizable design logic
Buggy Code
module gate (input clk, ready, d, output reg q);
  // Intent: capture d only when ready. But 'wait' is not synthesizable.
  always @(posedge clk) begin
      wait(ready);               // BUG: wait in design logic
      q <= d;
  end
endmodule

// 'wait' blocks a process until a condition holds — a simulation behaviour
// with no hardware equivalent. Synthesis rejects it. The intended
// 'capture d only when ready' is just a conditional (if), not a wait.
Symptom

A design module using 'wait' inside an always block fails to synthesize with an error about a non-synthesizable construct, even though the intent (gate the capture on 'ready') is simple.

Root Cause

'wait' is a level-sensitive blocking construct — it suspends a process until a condition is true — which is a simulation behaviour with no hardware mapping, so it is not synthesizable. The design intent here is 'capture d on the clock edge only when ready is high,' which is an ordinary conditional (if (ready)), not a blocking wait. 'wait' belongs in testbench synchronization, not design.

The fix is to use an 'if' to gate the capture, the synthesizable way to make a register conditional.

Fix
module gate (input clk, ready, d, output reg q);
  always @(posedge clk)
      if (ready) q <= d;         // conditional capture (synthesizable)
endmodule

// An if gates the register on 'ready' each clock edge. 'wait' is for
// testbenches; design uses if/case to make logic conditional.

7. Interview Q&A

8. Exercises

Exercise 1 — wait vs @

State the difference between wait(ready), @(ready), and @(posedge ready).

Exercise 2 — Testbench sync

Write a testbench fragment that sends a request, then waits for ack before continuing.

Exercise 3 — Replace wait in design

Rewrite always @(posedge clk) begin wait(en); q <= d; end as synthesizable design logic.

9. Summary

The wait statement is the level-sensitive timing control:

  • wait(condition) blocks until the condition is true (level-sensitive); proceeds immediately if already true.
  • vs @wait is level (is true), @ is change (transitions).
  • Simulation-only — testbench synchronization (ready/ack/done); not synthesizable.
  • In design, use if to make logic conditional, not wait.

The last timing sub-topic combines techniques: Chapter 14.4.4 Advanced Timing Techniques covers intra-assignment delays, named events, and combining timing controls — the patterns used in sophisticated testbenches.