Skip to content

VHDL · Chapter 4.3 · Concurrent Statements

Conditional Signal Assignment (when/else)

The bare concurrent assignment computes one expression, but real logic usually has to choose, and the when-else form adds that. It lets a target take one value when the first condition holds, another when the second holds, and so on. The conditions are tested in order, and the first true one selects its value, so this is precisely a priority multiplexer. It is still a single concurrent statement, a single driver, and pure combinational logic. This lesson shows how the textual order becomes hardware priority, why you must end with a final else to avoid inferring a latch, and how to read the priority-mux network the construct describes.

Foundation14 min readVHDLwhen/elseConditional AssignmentPriority MuxLatchCombinational

1. Engineering intuition — choose by priority

Often a signal should take one of several values depending on conditions, and those conditions have a precedence: "if an error, show the error code; else if busy, show busy; else show idle." The when/else assignment captures that directly — it walks the conditions top to bottom and uses the first that is true. That ordering is not cosmetic: it is the priority of a real multiplexer network, where earlier conditions override later ones.

2. Formal explanation — first true condition wins

The conditional signal assignment has the form:

when_else_form.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
target <= expr1 when cond1 else
          expr2 when cond2 else
          expr3;                  -- final 'else' value (no condition) — REQUIRED for completeness

The conditions cond1, cond2, … are boolean and are evaluated in order; the first true one selects its expression. It remains a single concurrent statement — one driver, combinational (lesson 4.2) — re-evaluated whenever any signal in any condition or expression changes. The trailing else with no condition supplies the default; omit it and some input combinations leave the target unassigned.

3. Production-quality RTL — a priority encoder of behaviour

status_priority_mux.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
-- Priority: error beats busy beats normal. Order = precedence.
status <= ERR_CODE  when fault = '1'                       else
          BUSY_CODE when unsigned(pending) /= 0            else
          IDLE_CODE;
-- A simple 2:1 mux is the degenerate case:
y      <= a when sel = '1' else b;

What hardware does this become? The status line synthesises to a priority multiplexer: a chain of 2:1 muxes where fault selects at the top, then the pending /= 0 test, then the default — earlier conditions win. The y line is a single 2:1 mux. Comparisons use numeric_std so the pending /= 0 test is well-defined.

4. Hardware interpretation — a chain of priority muxes

priority multiplexer chain built from when/else conditionslower prioritypathselectedcond1 ? expr1highest prioritymux (cond1)expr1 if cond1 else ↓mux (cond2)expr2 if cond2 else ↓else expr3default (lowest priority)targetfirst true condition'svalue12
A when/else assignment builds a PRIORITY multiplexer: a chain of 2:1 muxes where the first condition has the highest priority. cond1 selects expr1 over everything below it; if false, cond2 selects expr2 over the rest; the final else feeds the bottom. Because earlier conditions override later ones, reordering the when-clauses changes the hardware's precedence. This is the structural meaning of 'first true wins.'

5. Simulation interpretation — re-evaluate, pick first true

Like any concurrent assignment, it is event-driven: a change on any signal in the conditions or expressions wakes it, it scans the conditions in order, and it schedules the first-true expression onto the target one delta later.

event flow evaluating conditions in order and selecting the first trueCondition/expr signalchangesimplicit sensitivity firesScan conditions inordercond1, then cond2, …Stop at first TRUEselect its expression(priority)Schedule targetonto its single driverDelta update + fanouttarget takes the value12
Event flow of a when/else assignment. Any change in a condition or selected expression wakes the statement; it evaluates the conditions top to bottom and stops at the first true one; that expression is scheduled onto the single driver; one delta later the target updates and its fanout wakes. The 'stop at first true' step is what makes the selection a priority, not a parallel, choice.

Priority in action: fault overrides busy, which overrides idle

8 cycles
Priority in action: fault overrides busy, which overrides idlefault=1 AND busy=1 → fault wins (highest priority): ERRfault=1 AND busy=1 → f…fault=0, busy=1 → BUSYfault=0, busy=1 → BUSYboth 0 → final else: IDLEboth 0 → final else: I…fault00110000busy01101100statusIDLEBUSYERRERRBUSYBUSYIDLEIDLEt0t1t2t3t4t5t6t7
When both fault and busy are asserted, the output is ERR because fault is tested first — the textual order is the priority. As conditions fall away, the next-priority value takes over, ending at the default IDLE. A balanced (non-priority) choice would need the with/select form instead (next lesson).

6. Debugging example — the missing else that becomes a latch

Expected: combinational output. Observed: synthesis reports an inferred latch, and in gate simulation the output unexpectedly holds a stale value for some input combinations. Root cause: the when/else had no final unconditional else, so when no condition was true the target was left unassigned — VHDL keeps its previous value, which is memory (a latch). Fix: always end with an unconditional else that supplies a default for every uncovered case. Engineering takeaway: an inferred latch from a conditional assignment almost always means an uncovered case — add the final else; never leave a combinational output undriven for any input.

latch_from_missing_else.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- WRONG: no final else → if sel is neither "00" nor "01", y holds (latch).
y <= a when sel = "00" else
     b when sel = "01";          -- uncovered cases leave y unassigned → latch
-- RIGHT: an unconditional else covers everything.
y <= a when sel = "00" else
     b when sel = "01" else
     (others => '0');            -- default for all other sel values → pure combinational

7. Common mistakes & what to watch for

  • Omitting the final else. Uncovered cases leave the target unassigned → latch. Always supply an unconditional default.
  • Wrong condition order. Order is priority; putting the broad condition first masks the specific one. Most-specific/highest-priority conditions go first.
  • Expecting parallel (non-priority) selection. when/else is a priority mux; for a balanced, mutually-exclusive decode by one selector, use with/select (next lesson).
  • Side-effect-free but overlapping conditions assumed exclusive. If two conditions can be true at once, the first wins — make sure that is the intent.
  • Comparing vectors without numeric_std for arithmetic intent. Use numeric_std for magnitude comparisons; plain =//= are fine for pattern matches.

8. Engineering insight

The when/else assignment is the concurrent way to say "choose by priority," and its single most important property is that textual order equals hardware precedence. That makes it perfect for naturally-prioritised logic (interrupts, error-over-status, default fallthrough) and a poor fit for balanced selection, where the priority chain wastes logic depth and obscures intent. Pair it with the discipline of always ending in an unconditional else, and it gives concise, latch-free combinational logic whose structure — a priority mux — you can read straight off the source.

9. Summary

target <= e1 when c1 else e2 when c2 else eN; is a concurrent, single-driver, combinational assignment that selects the first true condition's value — a priority multiplexer whose clause order is its precedence. A missing final unconditional else leaves some cases unassigned and infers a latch, so always provide the default.

10. Learning continuity

when/else selects by arbitrary conditions, with priority. The companion form selects by the value of a single expression, with no priority — every choice mutually exclusive. The next lesson, Selected Signal Assignment (with/select), builds that balanced, case-style multiplexer and contrasts it with the priority mux you just learned, so you can pick the right form for each kind of selection.