A multiplexer selects one of several data inputs. A demultiplexer steers one input onto one of several outputs (often with one-hot enables).
Mux styles in RTL
Ternary (small):
assign y = sel ? a : b;
case (readable, scales):
always_comb begin
unique case (sel)
2'b00: y = d0;
2'b01: y = d1;
2'b10: y = d2;
default: y = d3;
endcase
end
Priority mux (if/else chain): earlier branches win. Use when selects are not mutually exclusive; otherwise prefer unique case / one-hot.
One-hot vs binary select
| Select | Pros | Cons |
|---|---|---|
| Binary | Compact control | Decode cost; illegal codes need default |
| One-hot | Fast mux in some libraries; clear enables | Wider select bus; must stay one-hot |
If software/firmware can send illegal sel, define a safe default (hold previous registered value, or a known idle).
Demux pattern
always_comb begin
y0 = '0; y1 = '0; y2 = '0; y3 = '0;
unique case (sel)
2'd0: y0 = din;
2'd1: y1 = din;
2'd2: y2 = din;
default: y3 = din;
endcase
end
Clearing all outputs first avoids latches when only one lane is driven.
Synthesis notes
- Nested ternaries become mux trees — fine, but watch timing on wide / deep selects.
- Don’t mix blocking and non-blocking in the same combo process.
- For registered outputs, mux in combo then flop:
always_ff @(posedge clk) q <= y_next;.