Digital Design / Module 2: Combinational building blocks
6. Multiplexers
Use the mux as hardware's if-else.
See it move
The idea
A multiplexer is hardware's if-else. Select lines choose which input appears at the output. A 2^N-to-1 mux has N select lines, so a 4:1 mux has two.
In software, an if runs only one branch. In hardware, both inputs exist and are computed all the time, and the mux just chooses between them. Picture this every time you write a conditional in RTL.
assign y = sel ? a : b; // 2:1 mux
always @(*) begin // 4:1 mux
case (s)
2'b00: y = d0;
2'b01: y = d1;
2'b10: y = d2;
default: y = d3;
endcase
endA mux can implement any function
Connect the select lines to the function's inputs, then tie each data pin to that row's truth-table output. A 2^N-to-1 mux therefore implements any N-input function. If one input goes on the data pins, you can use a mux half that size. FPGAs rely on this idea: their look-up tables are essentially muxes selecting from stored bits.
Worked example: XOR with one 2:1 mux
When A = 0, the output should equal B. When A = 1, it should equal B'. So use A as the select, B on the 0 input, and an inverted B on the 1 input.
Common mistake
Writing long if / else if chains when the conditions are mutually exclusive. Each else if can add a level of priority logic, making the last branch the slowest. A case statement over one select signal usually gives a flatter, faster mux.
Key ideas
- A 2^N-to-1 mux has N select lines.
- Any N-input function fits on a 2^N-to-1 mux, or 2^(N-1)-to-1 with an input on the data pins.
- Long priority chains add delay; a case-style mux is flatter.
Your exercise
Find the bug
This code has one deliberate bug. Read the symptom, then click the line you think is wrong.
The fix
assign lo = s[0] ? d[1] : d[0];
Why it failed
In sel ? x : y, x is chosen when sel is 1. The lower mux had its two inputs the wrong way round, so s[0] picked the opposite input. The upper mux was right, so only half the codes were wrong, which is easy to miss if you test only a few values.
Interview questions
coreBuild a 4:1 mux from 2:1 muxes.
Three 2:1 muxes: two on the first select, one on the second.
basicA 32:1 mux needs how many select lines? If you build it from 2:1 muxes, how many do you need?
It needs 5 select lines, since 2^5 = 32. Built as a tree of 2:1 muxes, each mux removes one candidate, so going from 32 inputs to 1 output takes 31 muxes: 16 + 8 + 4 + 2 + 1. The tree has 5 levels, one per select bit.
basicIn assign y = sel ? a : b;, which input reaches y when sel is 0? Is the logic that produces the other input switched off?
When sel is 0, y follows b. The logic driving a is not switched off; it keeps computing all the time and simply is not chosen. That is the key difference from a software if, where the untaken branch never runs.
coreImplement the 3-input majority function using one 4:1 mux, with A and B on the select lines.
List what the output must be for each AB pair. For AB = 00 the majority is 0 whatever C is. For 01 or 10 the result equals C. For 11 it is 1. So the data inputs are 0, C, C and 1. Putting one variable on the data pins is what lets a 4:1 mux handle a 3-input function.
coreMake an AND gate and an OR gate, each from a single 2:1 mux.
For AND, use A as the select, 0 on the 0 input and B on the 1 input: when A is 0 the output is 0, otherwise it is B. For OR, keep A as the select, put B on the 0 input and 1 on the 1 input. Each is a one-row-at-a-time reading of the truth table.
coreThis block is meant to be a 3:1 mux. What hardware does it really describe, and how would you fix it?
always @(*) begin if (s == 2'd0) y = d0; else if (s == 2'd1) y = d1; else if (s == 2'd2) y = d2; end
When s is 3, no branch assigns y, so it must keep its old value and synthesis builds a latch. The chain of else-ifs also describes priority rather than a flat choice, though tools often flatten a chain this simple. Add a final else (or a default in a case) giving y a value, for example else y = 1'b0;.
coreIn simulation, sel is x. What does y = sel ? a : b give when a = 1100 and b = 1010?
reg sel = 1'bx; reg [3:0] a = 4'b1100, b = 4'b1010; wire [3:0] y = sel ? a : b;
Verilog compares the two candidates bit by bit. Where they agree, the result is that bit; where they differ, it is x. Here bits 3 and 0 agree, so y is 1xx0. If a and b were equal, y would be fully known even with sel unknown. An if statement behaves differently: an x condition takes the else branch.
advancedAn FPGA look-up table with 6 inputs is essentially a mux choosing among stored bits. How many configuration bits does it hold, and how many different functions can it implement?
The six inputs act as select lines, so it chooses among 2^6 = 64 stored bits. Each bit is one row of the truth table, and the bits can be set freely, so it can implement 2^64 different 6-input functions. That is why any 6-input logic costs the same in one LUT, however complex it looks.
advancedHere is a mux whose select oh is one-hot. Why is this form attractive, and what happens if two select bits are high?
// oh is one-hot
assign y = ({4{oh[0]}} & m0) |
({4{oh[1]}} & m1) |
({4{oh[2]}} & m2);Each input is ANDed with its own select bit and the results are ORed, so there is no decoding of a binary select and every input passes through the same short path. If two select bits are high, the output is the bitwise OR of both inputs: with oh = 011 here it gives 0011 | 0101 = 0111. The design relies on the one-hot guarantee, so it is often paired with an assertion that checks it.