Skip to content

VHDL · Chapter 5.8 · Sequential Statements & Processes

The wait Statement

A process needs a way to suspend, and there are exactly two, a sensitivity list or wait statements. The wait form is the more flexible one, because it lets a process pause partway through its body, which is what testbenches need to sequence stimulus over time. It comes in four shapes, waiting until a condition, waiting for a time, waiting on a list of signals, and a plain unconditional wait. A process uses a sensitivity list or wait, never both. Most uses are in testbenches, where waiting for a time advances simulation, but one form that waits until a rising clock edge is a fully synthesizable way to describe a register without a sensitivity list. This lesson covers all four forms, which are synthesizable, and how wait drives stimulus.

Foundation14 min readVHDLwaitSuspensionTestbenchClockingSequential

1. Engineering intuition — pause the process on purpose

A sensitivity-list process always runs its whole body and then sleeps. Sometimes you want finer control: run a few statements, pause until a condition or a time, then continue. That is what wait gives — explicit suspension points inside the body. In a testbench this is exactly how you write a script: drive these inputs, wait 10 ns, drive those, wait for a response. In synthesizable RTL one specific wait form expresses a clocked register. Either way, wait is "suspend here until the stated event."

2. Formal explanation — the four forms, and the one rule

wait_forms.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
wait until clk = '1' and clk'event;   -- (or rising_edge(clk)) suspend until the condition becomes true
wait for 10 ns;                        -- suspend for a fixed simulation time (SIM ONLY)
wait on a, b;                          -- suspend until any listed signal changes (like a sensitivity list)
wait;                                  -- suspend forever (e.g. end of a testbench stimulus process)

A process that uses wait has no sensitivity list — the two mechanisms are mutually exclusive. wait until resumes when its condition becomes true; wait for resumes after a fixed time (a simulation construct — not synthesizable); wait on resumes on a signal change (equivalent to a sensitivity list, but mid-body); plain wait never resumes. The synthesizable subset is essentially wait until rising_edge(clk) at the top of a process — everything time-based is for simulation.

3. Production RTL & testbench — register and stimulus

wait_patterns.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
 
-- (A) SYNTHESIZABLE register via wait — equivalent to a clocked sensitivity-list process.
reg : process
begin
  wait until rising_edge(clk);     -- suspend until the edge; resumes each rising clk
  q <= d;                          -- captured on the edge → a flip-flop
end process;
 
-- (B) TESTBENCH clock generation (wait for → simulation time).
clk_gen : process
begin
  clk <= '0'; wait for 5 ns;
  clk <= '1'; wait for 5 ns;       -- a 10 ns period clock; loops forever
end process;
 
-- (C) TESTBENCH stimulus sequence (drive, wait, check).
stim : process
begin
  rst <= '1'; wait for 20 ns;      -- assert reset for 20 ns
  rst <= '0'; wait until rising_edge(clk);
  din <= x"A5"; wait until rising_edge(clk);
  -- ... checks ...
  wait;                            -- stop this process for the rest of the run
end process;

What hardware does this become? (A) a register — wait until rising_edge(clk) is synthesizable and identical in effect to process(clk) ... if rising_edge(clk). (B) and (C) are not hardware — they are testbench code: wait for advances simulated time to generate a clock and sequence stimulus, and the final plain wait parks the stimulus process once it is done.

4. Hardware / simulation interpretation — suspension points

wait statements as mid-body suspension points in a processnext wait / loopRun statementsuntil the first waitwait (until / for /on)suspend hereEvent occurscondition true / timeelapsed / signal changedResume + continueto the next wait (or loop)12
A wait statement is a suspension point inside the process body. Execution runs to a wait, suspends until the wait's event (a condition becomes true, a time elapses, or a listed signal changes), then resumes from that point and continues to the next wait (or loops). This lets a process pause partway through — the key to sequencing testbench stimulus over time. A sensitivity-list process, by contrast, always runs its whole body then suspends at the end; a process uses one mechanism or the other.
sensitivity list equivalent to a wait-on at the bottom of the bodyprocess (a, b)re-run body on a/b changeequivalentsame triggeringprocess ... wait ona, b;run body, then suspend ona/b12
Sensitivity list versus wait: two equivalent ways to trigger a process. A process with a sensitivity list (a, b) re-runs its whole body whenever a or b changes. The equivalent wait form runs the body then 'wait on a, b' at the bottom. For clocked logic, 'process(clk) ... if rising_edge(clk)' equals 'process ... wait until rising_edge(clk)'. The two mechanisms are mutually exclusive within one process.

wait until rising_edge(clk): q captures d each edge (a register)

8 cycles
wait until rising_edge(clk): q captures d each edge (a register)rising edge: wait resumes → q <= drising edge: wait resu…q follows d one clock later — a flip-flopq follows d one clock …clkd44991166q04499116t0t1t2t3t4t5t6t7
A process whose only suspension is 'wait until rising_edge(clk)' behaves exactly like a clocked sensitivity-list process: q captures d on each rising edge and holds otherwise. This is the one synthesizable wait idiom; the time-based forms (wait for) are simulation-only.

5. Synthesizer interpretation — only edge-waits map to hardware

Synthesis accepts essentially one wait form: a wait until rising_edge(clk) (or the explicit clk'event and clk = '1') used to describe a register, equivalent to the clocked sensitivity-list process. Every time-based form — wait for, and any wait whose resumption depends on elapsed time — is not synthesizable, because gates have no notion of "wait 10 ns." Those forms live in testbenches and behavioural models. So in design code use wait until rising_edge(clk) (or the sensitivity-list equivalent) and keep wait for strictly in verification code.

6. Debugging example — wait for in synthesizable RTL

Expected: a delay in the design. Observed: synthesis rejects the code (or ignores the delay), and the design behaves differently from RTL simulation. Root cause: a wait for <time> (or a time-based wait) was used in synthesizable RTL to model a delay; synthesis cannot realise wall-clock time, so the construct is unsynthesizable or dropped. Fix: express real timing with a clocked process and a counter (count clock cycles), not wait for; reserve wait for for testbenches. Engineering takeaway: if a wait depends on time rather than a clock edge, it is simulation-only — real delays come from clocked logic, never from wait for.

wait_for_in_rtl.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- WRONG (RTL): wait for is not synthesizable; cannot model a hardware delay.
-- process begin pulse <= '1'; wait for 100 ns; pulse <= '0'; wait; end process;
-- RIGHT (RTL): count clock cycles for a timed pulse.
process (clk) begin
  if rising_edge(clk) then
    if cnt = TICKS-1 then pulse <= '0'; cnt <= (others => '0');
    else                  cnt <= cnt + 1; end if;
  end if;
end process;

7. Common mistakes & what to watch for

  • wait for in synthesizable RTL. Not synthesizable; use a clocked counter for timed behaviour.
  • A sensitivity list and wait in the same process. Illegal — choose one triggering mechanism.
  • A wait that never resumes. A wait until on a condition that never becomes true (or a plain wait) hangs that process; intended only to park a finished testbench process.
  • Forgetting the process suspends at the wait. Statements after a wait do not run until it resumes; ordering matters for stimulus.
  • Using wait for design when a sensitivity list is clearer. For most RTL the sensitivity-list style is conventional; reserve wait for the edge idiom and testbenches.

8. Engineering insight

wait is the process's explicit suspend, and its real power is sequencing over time — which is why it dominates testbenches: drive, wait, check, repeat. In design code its role is narrow but important: wait until rising_edge(clk) is a clean, synthesizable register description, fully equivalent to the clocked sensitivity-list process. The discipline is simply to keep the time-based forms (wait for) on the verification side of the line, because hardware has no clock but the one you give it. Knowing which wait synthesizes and which does not keeps your RTL and testbench responsibilities clearly separated.

9. Summary

The wait statement suspends a process explicitly and comes in four forms: wait until <condition>, wait for <time>, wait on <signals>, and plain wait. A process uses a sensitivity list or wait, never both. wait until rising_edge(clk) is the one synthesizable idiom (a register); wait for and other time-based waits are simulation/testbench only. wait is the backbone of testbench stimulus sequencing.

10. Learning continuity

You have now seen both ways a process is triggered (sensitivity list and wait) and how its body is structured (if, case, loops, variables). The module closes by returning to the assignment at the heart of it all: Sequential Signal Assignment and Last-Assignment-Wins — how <= inside a process schedules, why multiple assignments resolve to the last one, and how the default-then-override idiom delivers latch-free logic — tying every construct back to the execution model from the anchor.