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
    • Digital Logic for RTL Engineers
    • Number Systems for RTL Engineers
    • Verilog Fundamentals
    • Verilog Operators and Types
      • Width Discipline
      • Bit Vectors and Slicing
      • Concatenation and Replication
      • Reduction and Logical Operators
      • Shift and Arithmetic Intent
      • Parameterized, Type-Safe Design
    • SystemVerilog for RTL
    • Simulation and Testbenches
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Verilog Operators and Types
  1. Topics
  2. RTL Design
  3. RTL Foundations
  4. Verilog Operators and Types
  5. Parameterized, Type-Safe Design

Part 1 · Foundations · Beginner

Parameterized, Type-Safe Design

Parameters, derived widths with clog2, and blocks that stay correct at any size.

On this page

    Why this matters

    $clog2(1) is 0, so an address width of $clog2(DEPTH) with DEPTH = 1 becomes [-1:0], an unintended two-bit range. Parameter bugs like this fail only in the configuration nobody tried.

    After this lesson you can: choose parameters and localparams, size an address with $clog2 safely, and reject illegal values at elaboration.

    Parameters make a block reusable

    A parameter is a constant you can override at each instance. A localparam is a constant derived inside the module that the instantiator cannot change.

    Use parameters for the true design choices, such as data width and depth. Derive everything else with localparams.

    Quantity

    Parameter or derived?

    Example

    Data width

    Parameter

    parameter DATA_W = 8

    FIFO depth

    Parameter

    parameter DEPTH = 16

    Address width

    Derived

    localparam ADDR_W = (DEPTH > 1) ? $clog2(DEPTH) : 1

    Maximum count value

    Derived

    localparam MAX = DEPTH - 1

    $clog2

    $clog2(n) is the number of bits needed to index n items: the ceiling of log₂ n. DEPTH must be at least 1: guard the width as localparam int ADDR_W = (DEPTH > 1) ? $clog2(DEPTH) : 1; because $clog2(1) is 0, so [ADDR_W-1:0] would become [-1:0], an unintended two-bit ascending range rather than an empty vector. DEPTH = 1 then gives a 1-bit address that is always 0, and a non-power-of-two depth still needs the rounded-up width.

    n

    $clog2(n)

    Why

    1

    0

    One location needs no address bits, so the ADDR_W guard keeps a 1-bit address that is always 0

    2

    1

    5

    3

    Needs 3 bits to address 0…4

    8

    3

    1000

    10

    2¹⁰ = 1024 ≥ 1000

    Make assumptions explicit

    • Check illegal parameter values at elaboration. In SystemVerilog, an if in a generate block that calls $error stops compilation with a clear message (for example “DEPTH must be at least 1”).

    • Do not hide magic numbers inside the module. If a width appears twice, derive it from one parameter.

    • Prefer parameter int (a typed parameter) over an untyped parameter, so the compiler can warn about a wrong-sized override.

    • Keep parameter lists small. A module with ten parameters is rarely used with more than one configuration.

    Common pitfall

    If you size a counter as $clog2(DEPTH) and then compare with DEPTH - 1, make sure the constant has the same width as the counter (as the cast ADDR_W'(DEPTH - 1) does). Otherwise a 32-bit constant widens the comparison and, for signed types, can change its meaning.

    Check yourself A FIFO has parameter DEPTH = 100. What address width does it need, and is DEPTH a power of two?

    $clog2(100) = 7 bits (2⁷ = 128 ≥ 100). It is not a power of two, so pointer-wrap logic cannot simply rely on natural overflow of the address register; it must compare against DEPTH - 1.

    Testbench

    The address generator rejects DEPTH below 1 and wraps at DEPTH minus 1. The testbench checks depths 1, 8 and 12 at every edge, including disabled holds and repeated wraps. An invalid DEPTH is a separate expected elaboration diagnostic, not a configuration that should produce PASS.

    addr_gen.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    module addr_gen #(
      parameter int DEPTH = 12,
      localparam int ADDR_W = (DEPTH > 1) ? $clog2(DEPTH) : 1
    ) (
      input  logic              clk, rst_n, inc,
      output logic [ADDR_W-1:0] addr
    );
      // Legal range: DEPTH >= 1. DEPTH = 1 gives a 1-bit address that is always 0.
      generate
        if (DEPTH < 1) begin : gen_bad_depth
          $error("DEPTH must be at least 1");
        end
      endgenerate
    
      always_ff @(posedge clk or negedge rst_n)
        if (!rst_n)                  addr <= '0;
        else if (inc)
          addr <= (addr == ADDR_W'(DEPTH - 1)) ? '0 : addr + 1'b1;   // wraps at DEPTH-1
    endmodule
    

    Remember

    • Parameters are the true design choices; derive everything else with localparams.

    • $clog2(n) is the ceiling of log2 n. Guard DEPTH = 1, and size constants to the counter width.

    • Check illegal values at elaboration with $error, and prefer typed parameters.

    Rule of thumb: derive each width from one parameter, never from a second copy of the number.

    Keep going

    • Practice: 2x1 multiplexer with parameterized width

    • Interview: run a mock interview on this topic

    Related topics

    • Generate and parameters in depth

    Previous

    24 / 350

    Next: SystemVerilog for RTL

    Up next

    Up nextSystemVerilog for RTL

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Width Discipline
    • Bit Vectors and Slicing
    • Concatenation and Replication