VHDL · Chapter 4.4 · Concurrent Statements
Selected Signal Assignment (with/select)
The with-select concurrent assignment chooses a value by the single value of one selector expression, giving one result per selector value and closing the list with a when-others clause. The choices are mutually exclusive and there is no priority, so the hardware is a balanced, case-style multiplexer or decoder rather than a priority chain. Because the choices must cover every possible selector value, VHDL requires the list to be exhaustive, which is why the when-others clause is mandatory. This lesson builds that balanced multiplexer, contrasts it structurally with the priority multiplexer of the previous form, and shows how to choose between the two for decoders, lookup tables, and general selection logic.
Foundation14 min readVHDLwith/selectSelected AssignmentMultiplexerDecoderCombinational
1. Engineering intuition — choose by value, in parallel
Sometimes selection is not a priority chain but a clean lookup: "for selector value 00 use A, for
01 use B, for 10 use C." There is no precedence — exactly one selector value applies at a time, and
all the choices are equal-rank alternatives. The with/select assignment expresses that as a
balanced multiplexer: the selector picks one of N inputs in a single, flat decision rather than
a ladder of priority tests.
2. Formal explanation — exhaustive, mutually exclusive choices
The selected signal assignment has the form:
with selector select
target <= expr1 when choice1,
expr2 when choice2,
exprN when others; -- 'others' covers all remaining selector values — REQUIREDThe selector is evaluated once and compared against each choice; the matching choice supplies
the value. The choices must be mutually exclusive and cover every possible selector value —
VHDL enforces this, so a when others (or an explicit full enumeration) is mandatory; otherwise it
will not compile. It is still one concurrent statement, one driver, combinational (lesson 4.2).
3. Production-quality RTL — decoders and muxes
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
-- 4:1 multiplexer selected by a 2-bit code:
with sel select
y <= d0 when "00",
d1 when "01",
d2 when "10",
d3 when others; -- "11" (and any meta-values) → covered
-- a one-hot decoder from a 2-bit input:
with code select
onehot <= "0001" when "00",
"0010" when "01",
"0100" when "10",
"1000" when others;What hardware does this become? The first is a 4:1 multiplexer — sel drives the select lines
of a single balanced mux. The second is a 2-to-4 decoder. Neither has a priority chain; the
selector fans out to a flat selection network. when others also handles non-'0'/'1' selector
bits, keeping the logic defined for metavalues in simulation.
4. Hardware interpretation — a balanced mux, not a ladder
5. Simulation interpretation — match the selector, drive the target
In simulation it behaves like a concurrent assignment sensitive to the selector and the chosen expressions: when any changes, it matches the selector against the choices and schedules the matching expression onto the target one delta later.
A 4:1 mux: the selector value routes the matching input to y
8 cycles6. Debugging example — the incomplete coverage error
Expected: a clean decode compiles and synthesises to a mux. Observed: a compile error about
choices not covering all cases, or (in process-style code) an inferred latch for the uncovered
values. Root cause: the selector's full value space was not covered — a std_logic_vector(1 downto 0) has more than four cases once metavalues are considered, so without when others the
choices are incomplete. Fix: always close the list with when others. Engineering takeaway:
with/select demands exhaustive choices by design; when others both satisfies that and defines
behaviour for metavalues, keeping the logic latch-free and simulation-clean.
-- WRONG: only the four "expected" patterns — std_logic has more values, so this is incomplete.
with sel select
y <= d0 when "00", d1 when "01", d2 when "10", d3 when "11"; -- no 'others' → error/latch
-- RIGHT: 'when others' makes the choices exhaustive and defines metavalue behaviour.
with sel select
y <= d0 when "00", d1 when "01", d2 when "10", d3 when others;7. Common mistakes & what to watch for
- Forgetting
when others.std_logic_vectorselectors are never fully covered by the "expected" patterns alone; omitothersand it will not compile (or infers a latch in process form). - Using
with/selectwhere priority is needed. It is balanced — no precedence. For prioritised conditions usewhen/else(lesson 4.3). - Overlapping choices. Choices must be mutually exclusive; duplicate or overlapping values are an error.
- Selecting on multiple independent conditions.
with/selectkeys on one selector value; if the decision depends on several unrelated conditions,when/elsefits better. - Assuming choice order matters. It does not — only the selector value does.
8. Engineering insight
with/select and when/else are the two structured concurrent assignments, and choosing between
them is choosing the hardware: a balanced mux/decoder versus a priority mux. Reach for
with/select when the decision is "based on the value of this one thing" — opcode decode, mux
select, small ROM — because it is exhaustive by construction (no missing-case latch surprises) and
synthesises to a single, flat selection layer. Reach for when/else when the decision is a
prioritised set of conditions. Both stay concurrent, single-driver, and combinational; the form you
pick should mirror the structure you intend.
9. Summary
with selector select target <= … when choice, … when others; is a concurrent, single-driver,
combinational assignment that selects by the selector's value — a balanced multiplexer/decoder with
no priority and mutually exclusive choices. The choices must be exhaustive, so when others is
required; it also defines behaviour for metavalue selectors.
10. Learning continuity
You now have both structured concurrent assignments — priority (when/else) and balanced
(with/select). Both are built from expressions, and those expressions are made of operators. The
next lesson, Logical and Boolean Operators, covers the gate-level building blocks that fill these
assignments — and/or/xor/not, vector operations, relational operators, and the VHDL
precedence rule that forces parentheses — completing the toolkit for concurrent combinational logic.