A multiplexer (mux) selects one of N inputs onto its output using a select
signal. It is the fundamental routing element — every if and case
you write in RTL becomes muxes in the fabric, and an FPGA lookup table can
implement a 2:1 mux with room to spare.
Three equivalent ways to describe a mux, all in the design below:
Conditional operator — assign y = sel ? b : a; reads exactly like
the hardware: "if sel, take b, else a". Ideal for 2:1.
case in an always block — scales to any width. Note the block is
always @* (combinational) and every path assigns the output —
this matters, as the next lesson on latches shows.
Indexing — assign y = inputs[sel]; when the inputs are packed
into a vector. Compact, and synthesizes to the same thing.
In the waveform, watch y4 follow a different input each time sel
changes: the mux is "wiring" a different source through, combinationally —
no clock involved anywhere.
Experiment: in the playground, remove the default from the case and
make the select 3 bits wide with only 5 cases — then read the synthesis
warning story in the latch lesson to see what you just risked.
Schematic
The design
Verilog — design.v
// Three styles of multiplexer.
module muxes (
input wire a, b, // 2:1 inputs
input wire [3:0] in4, // 4:1 packed inputs
input wire sel, // 2:1 select
input wire [1:0] sel4, // 4:1 select
output wire y2, // style 1: ?:
output reg y4, // style 2: case
output wire y_idx // style 3: indexing
);
// style 1: conditional operator
assign y2 = sel ? b : a;
// style 2: case in a combinational always block
always @* begin
case (sel4)
2'd0: y4 = in4[0];
2'd1: y4 = in4[1];
2'd2: y4 = in4[2];
default: y4 = in4[3];
endcase
end
// style 3: vector indexing
assign y_idx = in4[sel4];
endmodule
Show the VHDL version
VHDL — design.vhd
-- Three styles of multiplexer.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity muxes is
port (
a, b : in std_logic;
in4 : in std_logic_vector(3 downto 0);
sel : in std_logic;
sel4 : in std_logic_vector(1 downto 0);
y2 : out std_logic;
y4 : out std_logic;
y_idx : out std_logic
);
end entity;
architecture rtl of muxes is
begin
-- style 1: when/else
y2 <= b when sel = '1' else a;
-- style 2: with/select
with sel4 select y4 <=
in4(0) when "00",
in4(1) when "01",
in4(2) when "10",
in4(3) when others;
-- style 3: indexing
y_idx <= in4(to_integer(unsigned(sel4)));
end architecture;
The testbench
Verilog — tb.v
`timescale 1ns/1ns
module tb;
reg a = 0, b = 1;
reg [3:0] in4 = 4'b1010;
reg sel = 0;
reg [1:0] sel4 = 0;
wire y2, y4, y_idx;
muxes dut (.a(a), .b(b), .in4(in4), .sel(sel), .sel4(sel4),
.y2(y2), .y4(y4), .y_idx(y_idx));
initial begin
$dumpfile("wave.vcd"); $dumpvars(0, tb);
#10 sel = 1; // y2: a -> b
#10 sel4 = 2'd1; // walk the 4:1 inputs: 0,1,0,1
#10 sel4 = 2'd2;
#10 sel4 = 2'd3;
#10 in4 = 4'b0101; // change data under a fixed select
#10 $finish;
end
endmodule
Simulated waveform
This trace was produced by actually simulating the code
above with Icarus Verilog.