Multiplexers

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:

  1. Conditional operatorassign y = sel ? b : a; reads exactly like the hardware: "if sel, take b, else a". Ideal for 2:1.
  2. 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.
  3. Indexingassign 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

abysel01

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.

6 12 18 24 30 36 42 48 54 t (ns) y_idx y4 y2 a b in4[3:0] A 5 sel sel4[1:0] 0 1 2 3

Open this lesson in the playground →