Skip to content

VHDL · Chapter 5.4 · Sequential Statements & Processes

The if Statement

Inside a process, the if, elsif, and else statement is how you make decisions, and like its concurrent cousin it is a priority construct. The branches are tested top to bottom and the first true one wins. That priority is real hardware, so the order you write the branches is genuine precedence. Building on the process execution model, an if becomes a priority multiplexer for combinational logic or a conditional register update for clocked logic, and the rising-edge clock guard is simply an if wrapped around a register. This lesson covers the priority structure, the rule that a combinational if must assign every output on every path or it infers a latch, and when to reach for if versus a case statement for a balanced decode of one value.

Foundation14 min readVHDLif statementPriority MuxLatchRegistersSequential

1. Engineering intuition — decide by priority

An if ladder reads like a list of priorities: "if the most important condition holds, do this; otherwise if the next holds, do that; otherwise the default." The hardware mirrors that ordering — earlier conditions override later ones, exactly like the when/else priority mux from Module 4, but now written as ordered statements inside a process. So when you write an if, you are describing a precedence network, and the order you write the branches is that precedence.

2. Formal explanation — structure and the latch rule

if_form.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
if cond1 then
  -- statements (highest priority)
elsif cond2 then
  -- statements
else
  -- default statements
end if;

Conditions are boolean and tested in order; the first true branch executes and the rest are skipped. Two rules matter. For combinational logic, every output must be assigned on every path — omit an else (or a default) and some path leaves an output unassigned, which the execution model holds at its old value: a latch (lesson 6.3). For clocked logic, an if without an else is normal and correct — it means "update the register only when the condition holds; otherwise it keeps its value" (a register naturally holds).

3. Production RTL — priority logic and registers

if_patterns.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
 
-- (A) Combinational priority: fault beats warn beats normal. Default-then-override = latch-free.
prio : process (all)
begin
  level <= NORMAL;                 -- default assignment covers all paths
  if fault = '1' then level <= CRIT;
  elsif warn = '1' then level <= HIGH;
  end if;                          -- no else needed: default already drove 'level'
end process;
 
-- (B) Clocked register with enable and synchronous reset (nested if; no else = holds).
reg : process (clk)
begin
  if rising_edge(clk) then         -- the clock guard is itself an if
    if rst = '1' then     q <= (others => '0');
    elsif en = '1' then   q <= d;            -- update only when enabled
    end if;                                   -- else omitted → q holds (a register)
  end if;
end process;

What hardware does this become? (A) a priority multiplexer driving level, latch-free because the default assigns it on every path; (B) a register with a clock enable and synchronous reset — the inner if with no else correctly infers "hold when not enabled," which is what a flip-flop does.

4. Hardware interpretation — a priority mux

if/elsif/else as a priority multiplexer chainlowerprioritycond1 ? branch1highest prioritymux (cond1)branch1 if cond1 else downmux (cond2)branch2 if cond2 else downelse / defaultlowest priorityoutputfirst true branch wins12
A combinational if/elsif/else synthesises to a priority multiplexer: cond1 selects branch1 over everything below it; if false, cond2 selects branch2 over the rest; the else (or a top-of-process default) feeds the lowest priority. Because earlier conditions override later ones, reordering the branches changes the precedence — and therefore the hardware. In a clocked process the same structure instead gates a register update.

5. Simulation interpretation — branches in order

By the anchor's execution model, when the process wakes it evaluates the conditions top to bottom, takes the first true branch, runs its (zero-time) statements, and ignores the rest. Signal assignments inside the chosen branch are scheduled and take effect after the process suspends.

if statement branch evaluation order inside a processif nothing matchesProcess wakesevaluate conditions inorderFirst true branchrun its statements (zerotime)Skip the restlower branches ignoredNone true, no elseoutput unassigned → holds(latch risk)12
Branch selection inside the process. On wake, the conditions are tested in order; the first true one's statements run (in zero time, signals scheduled), and the remaining branches are skipped. If no condition is true and there is no else, no assignment is made on that path — which, for a combinational output, means it holds its old value (a latch).

Combinational priority (fault beats warn) and a clocked enable register

8 cycles
Combinational priority (fault beats warn) and a clocked enable registerfault and warn both set → fault wins (priority): CRITfault and warn both se…clocked q updates only on edges where en=1; otherwise holdsclocked q updates only…clkfault00110000warn01101100levelNORMHIGHCRITCRITHIGHHIGHNORMNORMen01100110q00555588t0t1t2t3t4t5t6t7
The combinational if makes 'level' a priority output — fault overrides warn, so order is precedence. The clocked if updates 'q' only on a rising edge with en=1 and otherwise holds it, which is exactly a register with a clock enable. Both behaviours come straight from the execution model.

6. Debugging example — the missing-else latch

Expected: combinational logic. Observed: synthesis infers a latch on the output, and gate simulation shows it holding stale values. Root cause: a combinational if left a path with the output unassigned (no else, no default), so the execution model holds the old value — memory. Fix: add a top-of-process default assignment (preferred) or a full else so every path drives the output. Engineering takeaway: in a combinational process, an inferred latch almost always means an if with an unassigned path — default-assign every output at the top, then override.

latch_then_fixed.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- BUG: combinational if with no else → y unassigned when sel /= '1' → latch.
process (all) begin
  if sel = '1' then y <= a; end if;        -- no else → y holds → latch
end process;
-- FIX: default-then-override (latch-free).
process (all) begin
  y <= b;                                   -- default
  if sel = '1' then y <= a; end if;         -- override → pure 2:1 mux
end process;

7. Common mistakes & what to watch for

  • Combinational if with an unassigned path. Infers a latch. Default-assign outputs at the top, or provide a full else.
  • Confusing if-priority with parallel selection. if/elsif is ordered precedence; for a balanced, value-based choice use case (lesson 5.5).
  • Adding an unnecessary else in a clocked register. A clocked if with no else correctly means "hold"; forcing an else can accidentally clear the register.
  • Deeply nested ifs that hide intent. Long priority ladders are hard to read; a case or a refactor is often clearer.
  • Reading a signal assigned in a branch later in the same wake-up. It is still the old value (use a variable for immediate intermediates — anchor lesson).

8. Engineering insight

The if statement is priority made executable: branch order is precedence, and that single fact tells you what mux network you are building. Combined with the discipline of default-then-override, it gives concise, latch-free combinational logic; combined with a rising_edge(clk) guard, it expresses every enabled/reset register you will write. Reach for if when the decision is naturally prioritised (error-over-status, enable/reset gating) and for case when it is a balanced decode of one value — the two cover all of process-based control logic.

9. Summary

The sequential if/elsif/else selects by priority — first true branch wins — synthesising to a priority multiplexer (combinational) or a conditional register update (clocked). Branch order is hardware precedence. A combinational if must assign every output on every path or it infers a latch (use default-then-override); a clocked if without an else correctly holds the register.

10. Learning continuity

if selects by priority. When the decision is instead a balanced choice among the values of a single expression, the right construct is the case statement — the next lesson — which synthesises to a balanced multiplexer/decoder, requires exhaustive coverage with when others, and is the natural way to write opcode decoders and, later, finite state machines.