A named override sets parameters where the instance is built. Names keep order irrelevant and review local.
Pass the same constants down each level of hierarchy. The testbench below wires two identical fifos and one wide fifo from shared localparams.
defparam assigns a parameter by hierarchical path, after instantiation. It can retarget deep hierarchy far from the instance site.
The value hides from the instantiation, so review misses it. This course bans it:
// snippet
// Avoid: the value hides far from the instance it changes.
// defparam u_a.DEPTH = 64;
// Preferred: named override at the instantiation site.
fifo #(.DEPTH(8), .WIDTH(8)) u_a (
.clk(clk), .rst_n(rst_n), .wr(wr_a), .rd(rd_a),
.din(din_a), .dout(dout_a), .full(full_a), .empty(empty_a)
);u_a has DEPTH 8. After how many writes must full assert, and what evidence checks its data bits?After exactly 8 accepted writes. A0..A7 checks only those words: bit 3 never goes high. The additional walking-one and walking-zero round trips drive each configured bit both ways; this is finite digital sensitivity evidence, not proof for all histories or exact resource mapping.
defparam in another file changes DEPTH. Why is the bug hard to find?No instantiation site shows the value. The search must cover the whole hierarchy instead of one line.
A small parameterizable fifo, two identical instances for equivalence, one wide instance, and a fill-and-drain testbench.
module fifo #(
parameter int DEPTH = 16,
parameter int WIDTH = 8
) (
input logic clk,
input logic rst_n,
input logic wr,
input logic rd,
input logic [WIDTH-1:0] din,
output logic [WIDTH-1:0] dout,
output logic full,
output logic empty
);
// Derived widths stay local: only DEPTH and WIDTH are overridable.
localparam int AW = (DEPTH > 1) ? $clog2(DEPTH) : 1;
localparam int CW = $clog2(DEPTH + 1);
logic [WIDTH-1:0] mem [DEPTH];
logic [AW-1:0] wptr, rptr;
logic [CW-1:0] count;
assign empty = (count == 0);
assign full = (count == DEPTH);
assign dout = mem[rptr];
always_ff @(posedge clk) begin
if (!rst_n) begin
wptr <= '0;
rptr <= '0;
count <= '0;
end else begin
if (wr && !full) begin
mem[wptr] <= din;
wptr <= (wptr == (DEPTH - 1)) ? '0 : (wptr + 1'b1);
end
if (rd && !empty) begin
rptr <= (rptr == (DEPTH - 1)) ? '0 : (rptr + 1'b1);
end
case ({wr && !full, rd && !empty})
2'b10: count <= count + 1'b1;
2'b01: count <= count - 1'b1;
default: count <= count;
endcase
end
end
endmodule
Testbench run with Icarus Verilog 13.0 (2026-10-16): prints PASS. The walking-one and walking-zero round trips are finite digital sensitivity checks, not proof for all histories or for exact resource mapping.