Multiplexers and Decoders
Imagine a memory chip with billions of storage cells. It has only one narrow data bus to read them out. Something must select exactly one cell's data for that bus. Something else must translate a numeric address into "activate this one wire." This means picking one wire out of billions. Two jobs matter here. First, selecting one signal among many. Second, turning a binary code into one active line among many. These jobs are so fundamental that all of digital computing rests on them. The building blocks that do this are the multiplexer (mux) and the decoder. Every register file uses a mux or a decoder somewhere in its critical path. So does every memory array, instruction-decode stage, and ALU control path. A multiplexer is the hardware realization of an `if/else` or `switch` statement acting on data. A decoder is the hardware realization of turning an index into a one-hot activation signal. This is exactly what happens when a CPU reads an opcode field. It then decides which functional unit to enable. Without these two circuits, a processor could not route data. It could not move data between registers, memory, and execution units. It also could not translate encoded instructions into concrete actions. This article builds both circuits from techniques you already know. These come from Logic Gates and Combinational Logic Design: truth tables, sum-of-products expressions, and gate networks. We derive the standard 2-to-1 and N-to-1 multiplexer, and the AND-based decoder. We show how the two are structural duals. A decoder plus a set of AND-OR data paths is a demultiplexer. Cascading small muxes builds bigger ones. We verify every truth table, every gate count, and every complexity claim. We do this from first principles rather than asserting them. By the end, you will be able to design an N-input mux from scratch. You will also design an N-output decoder from scratch. You can compute exact gate and delay costs. You can trace a full worked circuit. You will see how these primitives directly foreshadow other logic. This includes the selection logic inside Arithmetic Logic Units. It also includes the read/write port logic inside Registers and Register Files.
- A multiplexer (mux) selects one of N data inputs to route to a single output, using ⌈log₂N⌉ select lines.
- A decoder converts an n-bit binary code into one active output line among 2ⁿ outputs (one-hot).
- Both are built directly from AND, OR, and NOT gates using a sum-of-products construction derived from truth tables.
- A mux implements `output = Σ (select_pattern_i AND input_i)`; a decoder implements `output_i = AND of literals matching code i`.
- Complexity: an N-to-1 mux uses O(N) gates and O(log N) gate delay when built as a balanced tree of 2-to-1 muxes.
- Muxes and decoders are dual circuits — combined with logic they form data selection paths in ALUs and address decoding in memories.
A multiplexer routes data by binary selection; a decoder converts a binary code into a single active line — together they let a fixed set of wires implement any addressable choice.
The idea
A multiplexer (mux) is a combinational circuit with data inputs , select inputs , and a single output . The select lines encode an index in binary, and the circuit behaves as . It is the hardware analogue of an array-indexing expression `Y = D[S]`. When is a power of two, exactly select lines are needed and every select pattern is used; this is the common, "clean" case this article focuses on. A decoder is the structural inverse. It takes input lines encoding a binary number and produces output lines, exactly one of which is asserted (driven to 1) for each input combination — a one-hot output. A decoder with enable input adds one more control: when the enable is deasserted, all outputs are forced to 0 regardless of the code, allowing multiple decoders to be composed (as in the row/column decoders of a memory array) or turning the decoder into a true demultiplexer, which routes a single data input to one of outputs. Both circuits are two faces of the same underlying idea: a binary code names one of a finite set of choices. In a mux the "choice" selects which input reaches the output; in a decoder the "choice" selects which output gets activated. This is why a decoder followed by AND gates driven from a shared data line implements a demultiplexer, and a decoder feeding an OR gate over the true-input lines implements a multiplexer — the two circuits share a truth-table skeleton, only the direction of data flow differs.
How it works
Deriving the 2-to-1 mux. With one select bit and two data inputs , the truth table is:
| S | D0 | D1 | Y |
|---|---|---|---|
| 0 | 0 | * | 0 |
| 0 | 1 | * | 1 |
| 1 | * | 0 | 0 |
| 1 | * | 1 | 1 |
Reading off the behavior directly (rather than expanding a full 8-row truth table) gives the sum-of-products form:
This is the canonical 2-to-1 mux equation. It needs 2 AND gates, 1 OR gate, and 1 inverter — 4 gates total, and 2 levels of gate delay (AND then OR) after the inverter.
Building an N-to-1 mux from the general rule. For inputs and select lines , define the minterm as the AND of literals that is 1 exactly when the select lines encode integer (e.g., for , … care with bit order, so let's fix meaning , giving ). Then:
Each minterm activates exactly one AND gate among , gating through exactly one data input; the final OR gate merges these (only one is ever nonzero) into . This is a direct generalization of the 2-to-1 case and is provably correct because the minterms are mutually exclusive and exhaustive over — for any fixed select code, exactly one is 1 and all others are 0, so collapses to exactly .
Building a decoder. An -to- decoder simply outputs the minterms directly instead of ANDing them with data:
Adding an enable multiplies every minterm by : . When all outputs go to 0; when exactly one output fires, selected by .
Building larger muxes/decoders from smaller ones. Large muxes are almost never built as one giant OR of AND gates in practice — instead they are built as trees of small (2-to-1) muxes, which keeps fan-in bounded and delay logarithmic. An 8-to-1 mux, for example, is built from seven 2-to-1 muxes in a 3-level binary tree: 4 muxes select pairs using the low select bit, 2 muxes combine those using the middle bit, and 1 final mux combines using the high bit. Similarly, large decoders can be built hierarchically: a large decoder is split into a coarse decoder (selecting a group) and a fine decoder within the group, with AND gates combining a coarse-select line and a fine-select line — this is exactly the row/column addressing scheme used inside memory arrays. ```pseudocode // N-to-1 MULTIPLEXER, N = 2^n, built as a balanced binary tree of 2:1 muxes function MUX_TREE(D[0..N-1], S[0..n-1]): level = D // start with the N data inputs for bit in 0 .. n-1: next_level = empty list for pair_index in 0 .. length(level)/2 - 1: d0 = level[2pair_index] d1 = level[2pair_index + 1] // 2:1 mux primitive: Y = (NOT S)d0 + Sd1 y = MUX2(d0, d1, S[bit]) next_level.append(y) level = next_level return level[0] // the single surviving wire is the output function MUX2(d0, d1, s): return (NOT s AND d0) OR (s AND d1)
// n-to-2^n DECODER with enable function DECODER(S[0..n-1], enable): outputs = array of size 2^n, all initialized to 0 if enable == 0: return outputs // all lines deasserted k = binary_value(S) // integer encoded by select lines outputs[k] = 1 return outputs
// DEMULTIPLEXER: route one data line to one of 2^n outputs function DEMUX(data_in, S[0..n-1]): sel = DECODER(S, enable = 1) outputs = array of size 2^n for i in 0 .. 2^n - 1: outputs[i] = data_in AND sel[i] return outputs ``` The pseudocode is faithful to real hardware: `MUX2` is literally the gate-level equation derived above, `MUX_TREE` is literally how wide multiplexers are laid out on silicon (a balanced binary tree, not a flat OR), and `DECODER`/`DEMUX` show the duality — a demultiplexer is a decoder whose one-hot outputs are ANDed with a shared data wire.
Complexity & correctness
Gate count. A flat -to-1 mux built directly from the sum-of-products form uses:
- AND gates, each with fan-in (the select literals plus the data input), where ,
- 1 OR gate with fan-in ,
- inverters (to produce complemented select lines),
for a total of gates. If gates are restricted to bounded fan-in (e.g., 2-input gates only, as in real cell libraries), each -input AND/OR must itself be built as a tree of 2-input gates, costing additional gates and additional depth — so the asymptotic gate count stays , but constants grow.
Depth (delay). The flat design has depth for producing the fan-in- AND (if built from 2-input gates) plus for the fan-in- OR — dominated by . The tree-of-2:1-muxes design (as in the pseudocode) is simpler to reason about: it has exactly levels, each level being one 2:1 mux with constant depth (2 gates), giving depth and gate count as well, since level (counting from the data inputs) has muxes and total 2:1 muxes, each a constant number of gates. Both designs are asymptotically equivalent; the tree form is preferred in real layouts for uniform fan-in and simpler routing.
Decoder cost. An -to- decoder needs AND gates (one per output), each of fan-in (n select literals + enable), plus inverters — gates, depth per AND gate if built from 2-input gates (constant depth if the AND is allowed fan-in directly). Since , this is gates for outputs, matching the mux's linear cost — expected, since they are dual circuits over the same -element index space.
Correctness argument (mux). The correctness of follows from two facts about the minterms : 1. Exhaustiveness: for every possible assignment of the select bits , some makes (namely = the integer encoded by ), because is defined as the conjunction of literals matching the binary digits of . 2. Mutual exclusivity: for , , because and differ in at least one literal, and that literal is set to disagree with for at least one term in the AND, forcing it to 0. Given these two facts, the sum has exactly one nonzero term () and all other terms are 0, so the whole OR evaluates to — precisely the specified mux behavior . This is a direct instance of the general canonical sum-of-products theorem: any Boolean function equals the OR of the minterms for which it outputs 1, and here the function's value at minterm is defined to be .
Correctness argument (decoder). Identical reasoning: is 1 exactly for the unique encoding , by exhaustiveness and exclusivity of minterms, so the output vector is one-hot with the hot bit at position .
Correctness of the tree mux (induction on ). Base case : `MUX2` implements directly by definition — correct by inspection of its two rows. Inductive step: assume a tree of depth correctly selects among inputs using the low select bits. The final level combines two such -trees (rooted at and ) using the top bit in one more `MUX2`. By the correctness of that final mux, the output equals whichever half's correctly-selected value the top bit points to — which is exactly . This completes the induction.
Tradeoffs. The flat sum-of-products mux minimizes logical depth at the cost of very wide gates (fan-in ), which in real CMOS is slow and area-hungry since wide gates need transistor stacking or extra buffering. The tree-of-2:1-muxes design uses only constant-fan-in gates uniformly, which is friendlier to standard-cell libraries, at the (mild) cost of a -deep critical path instead of a theoretically flatter but practically slower wide-gate path. Real designs (e.g., a 32-to-1 mux in a register file read port) almost universally use the tree form, sometimes with pass-transistor-logic muxes instead of gate-logic muxes for further speed and area savings — a circuit-level optimization built on the same logical correctness argument above.
Worked example
Consider a 4-to-1 mux used to pick one of four ALU result sources — say, register file, adder, shifter, memory-load — feeding the write-back stage of a simple pipeline, with (adder=1, shifter=1, others 0) and select (meaning "select index 2, the shifter").
Step 1 — minterms. With , the four minterms are:
Step 2 — evaluate minterms at .
| minterm | formula | value at S1=1, S0=0 |
|---|---|---|
Exactly , confirming exclusivity/exhaustiveness on this concrete input.
Step 3 — compute Y.
Wait — check the data assignment: we said , i.e. . Selecting index 2 should return . Indeed — matching "shifter result happens to be logic 0 on this bit," which is a perfectly valid (if unglamorous) trace: the mux correctly forwarded , not the more visually tempting or , demonstrating the selection genuinely depends on and not on which input "looks like the answer."
Step 4 — trace through the tree implementation instead (sanity check). Using `MUX_TREE`:
- Level 0 (`bit=0`, using ): . .
- Level 1 (`bit=1`, using ): .
Output , agreeing exactly with the sum-of-products computation — a second, structurally independent derivation confirming the answer, exactly as the induction proof guarantees.
Decoder companion example. Suppose this mux's select lines are themselves generated by a 2-to-4 decoder reading a 2-bit "source ID" field from an instruction, with enable tied to "write-back stage active." For source ID and enable : , all other outputs 0 — that one-hot line is precisely what would gate "shifter result valid" onto the write-back bus in a real datapath, tying the decoder and mux into one coherent control path.
Common pitfalls & traps
| Pitfall | Why it happens | Fix |
|---|---|---|
| Off-by-one in select-line count | Using instead of , or forgetting must be a power of 2 for "clean" muxes | For non-power-of-2 , use select bits and tie unused input slots to a safe default (e.g., 0) |
| Confusing decoder output width with input width | Thinking an -input decoder has outputs | Remember: inputs → outputs, exponential blow-up |
| Forgetting the enable line | Treating decoder outputs as always "live," causing multiple decoders on a shared bus to fight | Always gate decoder outputs with enable; only one decoder module active at a time on shared address lines |
| Assuming don't-care data bits are irrelevant everywhere | Believing a mux truth table's "*" entries mean the bit never matters, even outside its own row | Don't-cares are local to each row; verify the full minterm expansion rather than eyeballing the table |
| Flat wide-gate mux assumed as fast as a tree | Believing "fewer logical levels" always means "faster" | In real CMOS, wide fan-in gates are slower than a chain of small gates; compare tree vs. flat including physical delay, not just gate-level depth |
Pioneers & history
The mux/decoder abstraction descends from the mathematics of Boolean algebra and the switching-circuit theory that translated logical propositions into physical relay and gate networks — the theoretical foundation that made "select one of N" and "activate exactly one of N" expressible as gate equations at all.
Origins · 1 minClaude Elwood Shannon and how this was discovered
Shannon's 1937 master's thesis proved that Boolean algebra could exactly describe relay and switching circuits, giving engineers the first rigorous language for combinational logic — the sum-of-products and minterm techniques used to derive mux and decoder equations trace directly back to this work.
Where this matters
Multiplexers select data paths throughout a CPU datapath: choosing between the PC+4 and a branch target, selecting an ALU operand source, or picking which register-file read port feeds an execution unit — all directly foreshadow the selection logic detailed in Arithmetic Logic Units. Register files use decoders to translate a register-number field from an instruction into the one-hot write-enable signal for the correct storage cell, a mechanism developed further in Registers and Register Files. Memory chips (SRAM/DRAM) use row and column decoders — hierarchical decoders exactly like the ones described here — to activate a single word line out of millions, while a wide output mux (or sense-amp selection network) picks the correct bit line data to drive onto the data bus. Instruction decoders in a CPU's control unit are literally decoders in this technical sense: an opcode field becomes a one-hot signal enabling a specific control path. Bus arbitration and I/O address decoding on a system bus use decoders to ensure exactly one peripheral responds to a given address range. Multiplexed displays, time-division multiplexing in networking, and even simple debouncing/selection circuits in embedded systems reuse the identical logical construction.
Ask the tutor: How would you design a 16-to-1 multiplexer using only 2-to-1 mux building blocks, and what is its exact gate delay in levels?
What is the difference between a multiplexer and a decoder?
A multiplexer routes one of several data inputs to a single output, controlled by select lines — it answers "which input's value do I want?" A decoder converts a binary code into a one-hot set of output lines — it answers "which single location does this code name?" Structurally they share the same minterm machinery: a mux ANDs each minterm with a data bit and ORs the results, while a decoder simply outputs the minterms directly. In practice, muxes move data through a circuit (e.g., picking an ALU operand source), while decoders activate exactly one destination (e.g., one memory row, one register write-enable) so that only the intended location responds.
Why do decoders need exponentially many outputs for a linear number of inputs?
A decoder must produce one output line per distinct binary code, and an -bit code has distinct values — there's no way around this if every code must map to a physically distinct, individually addressable wire. This exponential blow-up is intrinsic to any one-hot addressing scheme, not a design flaw. It is exactly why memory addressing is hierarchical: a flat decoder for a 32-bit address would need output wires, which is infeasible, so real memories split the address into row and column fields, decode each separately with much smaller decoders, and combine results — trading one giant decoder for two small ones plus an AND per cell.
Why is the tree-of-2:1-muxes design preferred over a single wide sum-of-products mux in real hardware?
A flat mux needs one -input OR gate and gates of fan-in . Real CMOS gates get slower and larger as fan-in grows, because wide gates require long series/parallel transistor stacks or extra buffering stages, which increases both delay and area nonlinearly. A tree of 2-to-1 muxes uses only constant-size building blocks at every level, so each stage has predictable, small delay and area, and the total depth is a clean stages. This makes timing analysis, layout, and cell-library reuse far simpler, which is why virtually every wide mux in a real datapath is built as a tree rather than as one flat gate network.
Can a multiplexer implement arbitrary Boolean functions, not just data selection?
Yes — this is a classic and practically useful trick. Because a -to-1 mux's minterm structure already contains every possible AND-combination of select variables, tying the data inputs to constants 0 or 1 (or to a smaller set of remaining variables) lets the mux implement any -variable (or -variable) Boolean function without any separate gates. This is called mux-based function implementation or "using a mux as a universal logic element," and it is a real technique in FPGA lookup tables (LUTs), which are literally multiplexers whose data inputs are configuration-memory bits encoding the desired truth table.
How does an enable line change a decoder into a demultiplexer?
A basic decoder has select/address inputs and produces a one-hot output determined purely by those inputs. A demultiplexer additionally has a data input: instead of asserting a constant 1 on the selected output, it forwards the data input's value to the selected output line while all other outputs stay at 0. Structurally, replace the decoder's implicit enable constant with the data signal — `outputs[i] = data_in AND minterm_i(S)` — so the demux is a decoder generalized to pass an arbitrary signal (not just logic 1) through to exactly one destination, chosen by the select lines.
Why are muxes and decoders described as "dual" circuits?
Both are built from the identical set of minterms over the select/address lines — Boolean AND-terms that are mutually exclusive and exhaustive. A decoder outputs these minterms directly as its one-hot result. A multiplexer instead ANDs each minterm with a corresponding data bit and ORs all the products together, using the same minterms to choose which data value passes through rather than to signal which location is active. Because they share this common minterm skeleton, understanding one construction (the sum-of-products derivation) automatically gives you the other, and it explains why a decoder plus AND-gated data lines directly reconstructs multiplexer/demultiplexer behavior.
What role do muxes and decoders play inside a CPU's register file?
A register file needs to (a) select which register's stored value appears on a read port, and (b) determine which single register's storage cell should be overwritten on a write. The read side is a multiplexer: the register-number field selects among all stored register values to produce the read-port output. The write side is a decoder: the register-number field is decoded into a one-hot write-enable vector, so that only the addressed register's storage cell actually latches the new value while all others hold their previous contents unchanged — a mechanism detailed further in Registers and Register Files.