Skip to content
VLSI Mentor

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

Azvya Education Pvt. Ltd.VLSI Mentor
wait.v
   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:

Azvya Education Pvt. Ltd.VLSI Mentor
wait-vs-event.v
   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.

Standards & specifications

Governing standard
IEEE Std 1364 (Verilog)(opens IEEE in a new tab)

Defines the Verilog language and its simulation semantics, including the event scheduling model. Synthesis support is defined by tools, not by this standard.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the Verilog HDL curriculum.