Modeling Multiplexers

Using if-else, case, assign statements.

Darshan N
Updated: 19 March 2026
12 min read

Multiplexers are the most fundamental combinational building blocks in digital design, serving as data selectors, bus arbiters, and routing elements. In Verilog, a multiplexer can be modeled using three different coding styles — if-else, case, and assign with the ternary operator — each of which has implications for readability, synthesizability, and the type of hardware inferred by synthesis tools.

MUX4-to-1I0I1I2I3Y (output)sel [1:0]sel=00: Y=I0sel=01: Y=I1sel=10: Y=I2sel=11: Y=I3Figure: 4-to-1 MUX symbol with select encoding and data input/output routing
Figure 1: 4-to-1 MUX — select signal determines which input is routed to the output

Core Concept: Data Selection Based on Select Signal

A multiplexer selects one of N input signals and routes it to a single output based on a binary select signal. For a 2^n-to-1 MUX, the select signal is n bits wide. The fundamental behavior is purely combinational: there is no memory, no clock, and the output changes immediately when any input or the select signal changes. This makes a MUX a purely combinational circuit, which must be modeled in Verilog using either a combinational always block or continuous assignment.

In Verilog, three constructs are available for modeling combinational MUX behavior. The assign statement with ternary operator is concise and directly maps to a 2-to-1 MUX: assign y = sel ? i1 : i0;. For larger MUXes, an if-else chain inside an always @(*) block or a case statement inside always @(*) are the preferred approaches, as they are more readable and synthesize cleanly.

Three Coding Styles for MUX in Verilog

The if-else style uses a cascaded if-else inside an always @(*) block. The sensitivity list @(*) is the recommended wildcard that includes all signals read inside the block, ensuring that the always block re-evaluates whenever any input changes. For a 4-to-1 MUX, four conditions check each combination of sel, and the corresponding input is assigned to y. If any condition is missed, a latch is accidentally inferred — so all cases must be covered or a default must be provided.

The case style is the cleanest approach for larger MUXes. A case(sel) block lists each possible value of the select signal and assigns the corresponding input to the output. A default clause at the end handles any uncovered binary combinations (such as don't-care states), preventing latch inference. Case statements synthesize to efficient priority-free mux trees in most synthesis tools.

The assign with ternary operator is ideal for 2-to-1 MUX: assign y = (sel==2'b00) ? i0 : (sel==2'b01) ? i1 : (sel==2'b10) ? i2 : i3;. Chained ternary operators can model any size MUX in a single assign statement, though readability decreases for more than 3-4 levels. Synthesis tools handle all three styles equivalently for standard MUX sizes.

Mathematical Expression

For a 2-to-1 MUX, the Boolean expression for the output is: Y = S_bar.I0 + S.I1, where S is the select signal. For a 4-to-1 MUX with 2-bit select S[1:0]: Y = S1_bar.S0_bar.I0 + S1_bar.S0.I1 + S1.S0_bar.I2 + S1.S0.I3. This is the minterm expansion form and shows that the MUX output is the OR of each input gated by its corresponding select decode term. A 2^n-to-1 MUX can implement any n-variable Boolean function directly.

Practical Understanding

MUXes are everywhere in digital design. Bus multiplexing in processors routes data from multiple sources to a shared bus. ALU input selection chooses between operands. Clock MUXes select between different clock sources in clock management blocks. In FPGA architectures, the fundamental 4-to-1 MUX is built into every LUT (lookup table), making it the native primitive for implementing any 4-input Boolean function.

A critical synthesis concern is that in Verilog, if-else chains imply priority encoding, while case statements without priority imply a balanced parallel mux tree. For GATE, the key distinction is between a priority encoder (first matching condition wins) and a plain MUX (all conditions are mutually exclusive). In practice, synthesis tools optimize both to equivalent hardware when conditions are mutually exclusive, but the RTL intent should be clear.

Example
Given:
4-to-1 MUX with inputs I0=0, I1=1, I2=0, I3=1 and sel=2'b10

Why this formula applies:
Y = S1_bar.S0_bar.I0 + S1_bar.S0.I1 + S1.S0_bar.I2 + S1.S0.I3
sel=2'b10 means S1=1, S0=0

Formula:
Y = S1_bar.S0_bar.I0 + S1_bar.S0.I1 + S1.S0_bar.I2 + S1.S0.I3

Substitution:
S1=1, S0=0, I0=0, I1=1, I2=0, I3=1
Y = (0).(1).(0) + (0).(0).(1) + (1).(1).(0) + (1).(0).(1)

Calculation:
Y = 0 + 0 + 0 + 0 = 0

Final Answer:
Y = I2 = 0 (sel=2'b10 routes input I2 to output)
Exam Tip: A 2^n-to-1 MUX with n select lines can implement ANY Boolean function of n variables by connecting the function's truth table values to the data inputs. GATE frequently tests this MUX-as-function-generator property.

MUX Coding Style Comparison

MUX Coding Styles in Verilogif-else Stylealways @(*) begin if (sel==0) y=i0; else if (sel==1) y=i1; else if (sel==2) y=i2; else y=i3;endPriority impliedcase Stylealways @(*) begin case (sel) 2'b00: y=i0; 2'b01: y=i1; 2'b10: y=i2; default: y=i3;No latch, cleanassign Ternaryassign y =(sel==0) ? i0 :(sel==1) ? i1 :(sel==2) ? i2 : i3;Continuous assignKey Difference: Missing default in case without else = Latch inferredAll three styles synthesize to equivalent hardware when all conditions are coveredassign ternary: no always block needed — directly drives netFigure: Three Verilog coding styles for 4-to-1 MUX and their synthesis implications
Figure 2: Verilog MUX coding styles — if-else, case, and assign ternary with synthesis behavior
  • if-else style implies priority; all branches must be covered to avoid latch inference.
  • case style with default is the cleanest MUX model; no priority, parallel decode.
  • assign ternary is best for 2-to-1 MUX; chaining works for larger but reduces readability.
  • always @(*) ensures the sensitivity list automatically covers all inputs.
  • A 2^n-to-1 MUX can implement any n-variable Boolean function by loading truth table on data inputs.

Quick Revision

  • 2-to-1 MUX: Y = S_bar.I0 + S.I1 — Boolean expression for output.
  • assign style: assign y = sel ? i1 : i0; for 2-to-1.
  • case style: always @(*) with case(sel) and default clause — preferred for 4-to-1 and above.
  • if-else style: always @(*), cover all branches or use else at end to avoid latch.
  • A 2^n-to-1 MUX implements any Boolean function of n variables.
  • always @(*) is equivalent to listing all input signals in sensitivity list.
  • Exam trap: missing default in case or missing else in if-else inside always @(*) infers a latch, not combinational logic.

Multiplexer Modeling Quiz

Evaluate capabilities in behavioral and dataflow multiplexer logic.

Question 1 of 3

Q1.How many select lines are required to design a 16:1 multiplexer?