Skip to content
VLSI Mentor

VHDL · Chapter 6.5 · Combinational Logic Design

Multiplexers

The multiplexer is the workhorse of combinational logic. It selects one of several inputs and routes it to the output under the control of a select signal, and almost every datapath is built from muxes. VHDL gives you four natural ways to write one. The when-else and if forms build a priority mux, while the with-select and case forms build a balanced mux, and indexing an array by an integer gives a clean wide mux. This lesson maps each style to the hardware it builds, shows when priority versus balanced selection matters, and applies the default-then-override discipline so a mux never accidentally latches. Choosing the right width and selection shape is the only real design decision.

Foundation13 min readVHDLMultiplexerSelectionPriority MuxDatapathRTL

1. Engineering intuition — route one of many

A multiplexer is a switch: many inputs, one output, and a select that decides which input gets through. It is the basic act of choosing in hardware — feed a register from one of several sources, pick an ALU result, steer a bus. Because choosing is so common, VHDL offers several syntaxes for it, but they all describe the same primitive: a selection network from N inputs to one output. The only real design decisions are the width (N) and whether the selection is priority (ordered) or balanced (value-based).

2. Formal explanation — four ways, two shapes

mux_styles.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
 
-- PRIORITY mux (ordered conditions): when/else (concurrent) or if (process).
y1 <= a when s1 = '1' else b when s2 = '1' else c;           -- first true wins
 
-- BALANCED mux (one selector value): with/select (concurrent) or case (process).
with sel select
  y2 <= d0 when "00", d1 when "01", d2 when "10", d3 when others;
 
-- WIDE mux by ARRAY INDEX: index a vector-of-vectors with an integer (numeric_std).
y3 <= data_array(to_integer(unsigned(sel)));                  -- clean N:1 mux

when/else and if build a priority mux (a chain of 2:1 muxes, order = precedence); with/select and case build a balanced mux (a flat one-of-N decode). Indexing an array by an integer is the most concise wide mux. All are combinational; keep them latch-free (a final else / when others / complete index range, plus defaults in a process).

3. Production RTL — datapath source select

datapath_mux.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
-- 4:1 datapath mux feeding a register input, written as a balanced case in a process.
src_mux : process (all)
begin
  mux_out <= (others => '0');                 -- default → latch-free
  case src_sel is
    when "00" => mux_out <= alu_result;
    when "01" => mux_out <= mem_data;
    when "10" => mux_out <= imm_value;
    when others => mux_out <= reg_data;
  end case;
end process;

What hardware does this become? A 4:1 multiplexer selecting the register-input source — src_sel drives the mux select, and the four data sources are its inputs. The default plus full case coverage guarantees no latch. (Written as mux_out <= data_array(to_integer(unsigned(src_sel))) it is the same mux, more concisely, when the sources are collected into an array.)

4. Hardware interpretation — N:1 selection

N to 1 multiplexer selecting one input under a selectinputs d0..dN-1the N sourcesN:1 muxbalanced (flat) or priority(chain)selectvalue (balanced) /conditions (priority)outputthe selected inputcontrolsroutes one12
A multiplexer routes one of N inputs to the output under a select. A balanced mux (with/select, case, array index) is a flat one-of-N selection — the select value picks directly. A priority mux (when/else, if) is a chain of 2:1 muxes where earlier conditions outrank later ones, so it has more logic depth but expresses precedence. Choose balanced for value-based selection (the common case) and priority when the conditions are genuinely ranked.

5. Simulation interpretation — output follows the select

A mux is combinational, so its output continuously equals the currently-selected input — change the select or the selected input and the output follows after a delta.

A 4:1 mux: the select value routes the matching source to the output

8 cycles
A 4:1 mux: the select value routes the matching source to the outputsel=00 → ALU resultsel=00 → ALU resultsel=01 → MEM data (balanced: value selects directly)sel=01 → MEM data(balanced: value selectsdirectly)sel=11 → REG data (others)sel=11 → REG data (others)src_sel0000010110101111mux_outALUALUMEMMEMIMMIMMREGREGt0t1t2t3t4t5t6t7
The output is always the source named by src_sel — a pure function of the select and the inputs, with no memory. Reordering the case branches would not change anything (balanced selection). A priority mux would instead resolve overlapping conditions by order, which is the right tool only when the selectors are genuinely ranked.

6. Debugging example — priority where balanced was meant (and a latch)

Expected: a value-based 4:1 mux. Observed: either subtly wrong selection, or an inferred latch. Root cause: writing a value decode as an if/elsif ladder makes it a priority mux — fine if conditions are exclusive, but it adds depth and, if the final else is missing, leaves a path unassigned → latch. Fix: use case/with/select for value-based selection (balanced, exhaustive), or ensure the if ladder has a final else. Engineering takeaway: match the construct to the selection — case/with/select for value decode, when/else/if for ranked conditions — and always close it (default / else / others) so the mux cannot latch.

mux_fix.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- RISK: value decode as a priority ladder, missing final else → latch + extra depth.
-- y <= d0 when sel="00" else d1 when sel="01" else d2 when sel="10";   -- no else → latch
-- FIX: balanced, exhaustive selection.
with sel select
  y <= d0 when "00", d1 when "01", d2 when "10", d3 when others;        -- balanced, no latch

7. Common mistakes & what to watch for

  • Missing final else / when others. Leaves a path unassigned → latch. Always close the mux.
  • Using a priority style for value-based selection. case/with/select is balanced and clearer; reserve if/when/else for ranked conditions.
  • Index out of range on an array mux. data_array(to_integer(unsigned(sel))) must have sel cover exactly the array range; an out-of-range index is an error.
  • Forgetting defaults in a process-style mux. Default the output at the top to stay latch-free.
  • Very wide priority muxes. A long if ladder has deep logic; a balanced case/array index is faster and smaller for wide selection.

8. Engineering insight & continuity

The multiplexer is selection distilled, and writing one well is mostly about two choices: balanced versus priority, and keeping it latch-free. Use case/with/select (or an array index) for the common value-based mux, reserve priority styles for genuinely ranked conditions, and always close the selection so no path is unassigned. With muxes — the route-one-of-many primitive — in hand, the next lesson covers the complementary primitives that expand and compress encodings: Decoders and Encoders, where a binary value fans out to one-hot (decode) or a one-hot/priority input compresses to binary (encode).

Standards & specifications

Governing standard
IEEE Std 1076 (VHDL)(opens IEEE in a new tab)

Defines the VHDL language — types, the simulation cycle, and the semantics a conforming analyser and simulator must implement. Synthesis restrictions and vendor coding rules are tool behaviour, not language rules.

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 VHDL curriculum.