Parameters make a module scalable. generate stamps hardware in a loop. Both are elaborated at compile time — they are not runtime software loops.
flowchart TB p["parameter WIDTH=8"] --> m0[slice_0] p --> m1[slice_1] p --> mN[slice_N]
parameter vs localparam
| Kind | Override from parent | Use |
|---|---|---|
parameter |
Yes (#(.WIDTH(16))) |
Widths, depths, instance options |
localparam |
No | Internal derived constants |
module counter #(parameter WIDTH = 8) (
input logic clk,
output logic [WIDTH-1:0] cnt
);
localparam MAX = {WIDTH{1'b1}};
endmodule
generate-for
genvar i;
generate
for (i = 0; i < N; i++) begin : g_bit
assign y[i] = a[i] ^ b[i];
end
endgenerate
Name the begin : g_bit block so hierarchy (g_bit[3].…) stays readable in waves.
Wrong vs right
Wrong — a runtime for that waits on a clock inside synthesizable combo (sim-only):
always_comb
for (int i = 0; i < n_live; i++) @(posedge clk);
Right — bound the loop with a constant/parameter and assign hardware, or use generate.