Parameterized and Reusable RTL
Parameterize widths and types, protect corner cases, and generate hardware without making a module opaque.
Value parameters
A parameter adapts a module at instantiation time. Its type states which values are accepted.
module delay_line #(
parameter int unsigned WIDTH = 16,
parameter int unsigned DEPTH = 4
) (
input logic i_clk,
input logic [WIDTH-1:0] i_data,
output logic [WIDTH-1:0] o_data
);
logic [WIDTH-1:0] stages [0:DEPTH-1];
always_ff @(posedge i_clk) begin
stages[0] <= i_data;
for (int unsigned i = 1; i < DEPTH; i++)
stages[i] <= stages[i-1];
end
assign o_data = stages[DEPTH-1];
endmoduleThis module assumes DEPTH >= 1. A reusable module should state that contract and, when possible, check it during elaboration or at the beginning of simulation.
initial begin
assert (DEPTH >= 1)
else $fatal(1, "DEPTH must be at least 1");
endThis check helps simulation and some elaboration tools. It does not replace a sensible default or clear documentation.
Local parameters
localparam defines an internal constant that an instance cannot override.
localparam int unsigned COUNT_WIDTH = (DEPTH <= 1) ? 1 : $clog2(DEPTH);Protecting the DEPTH <= 1 case avoids a zero width. Derived parameters should be calculated once and named after their purpose.
Type parameters
SystemVerilog can parameterize the transported type:
module register_t #(
parameter type T = logic [7:0]
) (
input logic i_clk,
input T i_d,
output T o_q
);
always_ff @(posedge i_clk)
o_q <= i_d;
endmoduleThis style works well in internal libraries when tools support it. For IP delivered to several environments, conventional width parameters can be easier to integrate.
Conditional generation
generate selects hardware during elaboration. It is not a run-time condition evaluated every cycle.
if (REGISTER_OUTPUT) begin : g_registered
always_ff @(posedge i_clk)
o_data <= result;
end else begin : g_comb
always_comb
o_data = result;
endThe named blocks g_registered and g_comb provide stable hierarchical paths. Avoid a large number of parameters that create too many combinations to verify properly.
Key points
- A typed parameter defines a module contract more clearly.
- Invalid values should be documented and checked.
localparamprotects internal derived constants.- A type parameter can make a block very general, depending on tool support.
generateselects a hardware structure at elaboration time.
📝 Test your knowledge - Chapter quiz