Prev Problem
Next Problem

32. Board-Clock Configuration using Parameter Pass-Through

module led_blinker #(
  parameter integer COUNTER_WIDTH = 8,
  parameter integer TOGGLE_EVERY  = 6
)(
  input  wire clk,
  input  wire rst,
  output reg  led
);
  reg [COUNTER_WIDTH-1:0] cnt;
  always @(posedge clk) begin
    if (rst) begin
      led <= 1'b0;
      cnt <= {COUNTER_WIDTH{1'b0}};
    end else begin
      if (cnt == TOGGLE_EVERY-1) begin
        led <= ~led;
        cnt <= {COUNTER_WIDTH{1'b0}};
      end else begin
        cnt <= cnt + {{(COUNTER_WIDTH-1){1'b0}},1'b1};
      end
    end
  end
endmodule

module board_blink_dual #(
  parameter integer CW    = 3,
  parameter integer EVERY = 4
)(
  input  wire clk,
  input  wire rst,
  output wire led_fixed,
  output wire led_cfg
);
  led_blinker #(.COUNTER_WIDTH(3), .TOGGLE_EVERY(6)) u_fixed (
    .clk(clk), .rst(rst), .led(led_fixed)
  );
  led_blinker #(.COUNTER_WIDTH(CW), .TOGGLE_EVERY(EVERY)) u_cfg (
    .clk(clk), .rst(rst), .led(led_cfg)
  );
endmodule

💡 Remember

  • Parameters are compile-time—each instance gets its own constant values. The same RTL can blink at two different rates just by overriding parameters at instantiation.
  • Named overrides (#(.P1(v1), .P2(v2))) are clearer and order-independent; positional overrides (#(v1, v2)) rely on declaration order.
  • Pass-through keeps the top flexible: make board_blink_dual parameterized, then feed those top parameters into the instance (.COUNTER_WIDTH(CW), .TOGGLE_EVERY(EVERY)).
  • Choose counter width so 2^COUNTER_WIDTH ≥ TOGGLE_EVERY; width doesn’t change the blink rate, it just makes counting possible.