Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
    • Combinational Timing Overview
    • Muxes, Decoders and Encoders
      • Mux Theory and Design Patterns
      • A Parameterized Mux
      • Binary Decoder and One-Hot Enables
      • Priority Encoder
    • Arithmetic Blocks
    • Comparators and Shifters
    • Tri-State and Shared Buses
    • Latch Inference
    • Arithmetic Datapaths
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Muxes, Decoders and Encoders
  1. Topics
  2. RTL Design
  3. Combinational Design
  4. Muxes, Decoders and Encoders
  5. A Parameterized Mux

Part 2 · Combinational · Intermediate

A Parameterized Mux

One mux for any width and count, with out-of-range selects safely defined.

On this page

    Why this matters

    A mux with N inputs of W bits fails in odd corners: N = 1 makes a select of width [-1:0], and N = 5 leaves three invalid select values. Both must be decided in the RTL.

    After this lesson you can: write a parameterized mux on a packed vector, size its select with $clog2, and choose what invalid selects do.

    One vector for N inputs

    A parameterized mux takes N inputs of width W. The cleanest interface is one packed vector of N·W bits, with input i in bits [i*W +: W].

    The select width follows from N. An indexed part-select picks the chosen slice.

    The 40-bit vector d holds five 8-bit inputs, input 0 in the low bits. Select 2 starts at bit 2 x 8 = 16 and takes 8 bits: d[23:16].

    Read the bar from bit 39 on the left to bit 0 on the right; each box is one input. The hex values 8'h10 to 8'h50 are the ones the testbench below loads.

    • Start bit: sel * W. For select 2 that is 16.

    • Width: +: W always takes exactly 8 bits upward, so the slice width is constant even though the start moves.

    • Spare selects: a 3-bit select can name 5, 6 and 7, which have no box. The guard below returns 0 for them.

    N may be 1 (a single input, wired through): the select width is guarded as (N > 1) ? $clog2(N) : 1 because $clog2(1) is 0, which would give a [-1:0] select. N = 1 then takes a 1-bit select that is always 0.

    Out-of-range selects

    N = 5 needs a 3-bit select. That select can encode 8 values. Selects 5, 6 and 7 are invalid.

    Handling them here with an output of 0 keeps simulation free of x. That choice costs real logic for the invalid selects.

    If invalid selects are provably impossible, add an assertion to check legality. The assertion does not change the hardware: this RTL still returns 0. Treating invalid selects as don't-cares needs different RTL plus a flow-supported synthesis assumption.

    Design choices

    Choice

    Option

    Consequence

    Out-of-range select

    Return 0 / return a fixed value / assert

    A defined value avoids x; an assertion catches the bug at its source.

    Input packing

    One packed vector / unpacked array port

    Packed vector works in plain Verilog and every tool; arrays need SystemVerilog support.

    N is a power of two

    Select covers every value

    No out-of-range case exists, so the guard disappears.

    Tip

    Guard with sel < N rather than relying on the index to fail. In a power-of-two mux the comparison is always true and synthesis removes it, so the guard costs nothing.

    Interview check

    Check yourself N is 5 and sel reads 6. What does y read, and which line of the module decides it?

    y reads 0. The default y = '0 decides it, because the guard sel < N blocks the indexed pick.

    Check yourself What is $clog2(N) for N = 1, and what goes wrong with the declaration [$clog2(N)-1:0] sel?

    $clog2(1) is 0, so the declaration becomes [-1:0], a 2-bit-wide vector counting backwards. Parameterized blocks that may be instantiated with N = 1 need a special case (for example localparam SW = (N > 1) ? $clog2(N) : 1;).

    Check yourself N is exactly 8, a power of two. What happens to the sel < N guard in synthesis?

    It is always true, so synthesis removes it. The guard costs nothing, which is why it is safe to write it every time.

    Testbench

    The full parameterized mux plus a testbench that sweeps every select, valid or not.

    mux_n.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    module mux_n #(
      parameter int W = 8,                         // data width
      parameter int N = 5                          // number of inputs (need not be a power of two); N must be at least 1
    ) (
      input  logic [N*W-1:0]          d,           // d[i*W +: W] is input i
      // N = 1 guard: $clog2(1) is 0, so [$clog2(N)-1:0] would be [-1:0]
      input  logic [(N > 1 ? $clog2(N) : 1)-1:0] sel,
      output logic [W-1:0]            y
    );
      always_comb begin
        y = '0;                                    // default for out-of-range select
        if (32'(sel) < N) y = d[sel*W +: W];       // widen sel to compare with the 32-bit N
      end
    endmodule
    

    Remember

    • Pack the inputs into one NW vector and pick input i with the part-select [iW +: W].

    • Guard the select width for N = 1, because $clog2(1) is 0.

    • Guard with sel < N. For a power-of-two N the tool removes the guard for free.

    Rule of thumb: decide what an out-of-range select does, and write it down.

    Keep going

    • Practice: A parameterized-width multiplexer written to be testable

    • Interview: run a mock interview on this topic

    Related topics

    • Parameterized, type-safe design

    Previous

    41 / 350

    Next: Binary Decoder and One-Hot Enables

    Up next

    Up nextBinary Decoder and One-Hot Enables

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Priority Encoder