27. Board-Clock Configuration using Parameter Pass-Through

Loading...

Testbench Code

`timescale 1ns/1ps
module tb_board_blink_dual;
  reg clk;
  reg rst;

  wire led_fixed;
  wire led_cfg;

  wire expected_led_fixed;
  wire expected_led_cfg;

  wire mismatch;

  // Top parameters under test: fixed = (3,6); cfg = (CW=3, EVERY=4)
  localparam integer TB_CW    = 3;
  localparam integer TB_EVERY = 4;

  board_blink_dual #(.CW(TB_CW), .EVERY(TB_EVERY)) dut (
    .clk(clk), .rst(rst), .led_fixed(led_fixed), .led_cfg(led_cfg)
  );

  // Golden models
  reg [2:0] exp_cnt_fixed;
  reg       exp_led_fixed_q;
  assign expected_led_fixed = exp_led_fixed_q;

  reg [TB_CW-1:0] exp_cnt_cfg;
  reg             exp_led_cfg_q;
  assign expected_led_cfg = exp_led_cfg_q;

  always @(posedge clk) begin
    if (rst) begin
      exp_led_fixed_q <= 1'b0;
      exp_cnt_fixed   <= 3'd0;
    end else begin
      if (exp_cnt_fixed == 6-1) begin
        exp_led_fixed_q <= ~exp_led_fixed_q;
        exp_cnt_fixed   <= 3'd0;
      end else begin
        exp_cnt_fixed   <= exp_cnt_fixed + 3'd1;
      end
    end
  end

  always @(posedge clk) begin
    if (rst) begin
      exp_led_cfg_q <= 1'b0;
      exp_cnt_cfg   <= {TB_CW{1'b0}};
    end else begin
      if (exp_cnt_cfg == TB_EVERY-1) begin
        exp_led_cfg_q <= ~exp_led_cfg_q;
        exp_cnt_cfg   <= {TB_CW{1'b0}};
      end else begin
        exp_cnt_cfg   <= exp_cnt_cfg + {{(TB_CW-1){1'b0}},1'b1};
      end
    end
  end

  wire mm_fixed = (led_fixed !== expected_led_fixed);
  wire mm_cfg   = (led_cfg   !== expected_led_cfg);
  assign mismatch = mm_fixed | mm_cfg;

  // Clock
  initial begin
    clk = 1'b0;
    forever #5 clk = ~clk;
  end

  // VCD: Inputs → Outputs → Expected → Mismatch
  initial begin
    @(posedge clk);
    $dumpfile("tb_board_blink_dual.vcd");
    $dumpvars(0,
      clk, rst,                   // 1) Inputs
      led_fixed, led_cfg,         // 2) Outputs
      expected_led_fixed, expected_led_cfg, // 3) Expected Outputs
      mismatch                    // 4) Mismatch
    );
  end

  // Helpers
  task apply_cycles; input integer n; integer i; begin for (i=0;i<n;i=i+1) @(posedge clk); end endtask

  integer TOTAL_TEST_CASES, TOTAL_PASSED_TEST_CASES, TOTAL_FAILED_TEST_CASES;

  // Run a window, count expected toggles for both LEDs
  task run_window;
    input integer cycles;
    input [8*48-1:0] name;
    integer i;
    reg case_failed;
    integer tog_fixed, tog_cfg;
    reg prev_fixed, prev_cfg;
    begin
      case_failed = 0;
      tog_fixed = 0; tog_cfg = 0;
      prev_fixed = expected_led_fixed; prev_cfg = expected_led_cfg;
      for (i=0; i<cycles; i=i+1) begin
        @(posedge clk);
        if (mismatch) case_failed = 1;
        if (expected_led_fixed !== prev_fixed) tog_fixed = tog_fixed + 1;
        if (expected_led_cfg   !== prev_cfg)   tog_cfg   = tog_cfg   + 1;
        prev_fixed = expected_led_fixed; prev_cfg = expected_led_cfg;
      end
      $display("CASE=%s : toggles_fixed=%0d toggles_cfg=%0d %s",
               name, tog_fixed, tog_cfg, case_failed ? "MISMATCH" : "OK");
      TOTAL_TEST_CASES = TOTAL_TEST_CASES + 1;
      if (!case_failed) TOTAL_PASSED_TEST_CASES = TOTAL_PASSED_TEST_CASES + 1;
      else TOTAL_FAILED_TEST_CASES = TOTAL_FAILED_TEST_CASES + 1;
      apply_cycles(1);
    end
  endtask

  // Stimulus: show 4 reset cycles, then several short windows
  initial begin
    rst = 1'b1;
    exp_cnt_fixed = 0; exp_led_fixed_q = 0;
    exp_cnt_cfg   = 0; exp_led_cfg_q   = 0;

    apply_cycles(4);
    @(negedge clk) rst = 1'b0;

    TOTAL_TEST_CASES = 0; TOTAL_PASSED_TEST_CASES = 0; TOTAL_FAILED_TEST_CASES = 0;

    run_window(3,  "pre_first_toggle");          // no toggle yet for either
    run_window(1,  "cfg_first_toggle");          // cfg toggles at 4th edge
    run_window(2,  "gap_until_fixed_toggle");
    run_window(1,  "fixed_first_toggle");        // fixed toggles at 6th edge

    run_window(4,  "one_cfg_period");            // cfg toggles once more
    run_window(6,  "one_fixed_period");          // fixed toggles once more

    @(negedge clk) rst = 1'b1; apply_cycles(2); @(negedge clk) rst = 1'b0;
    run_window(4,  "post_reset_cfg_first_toggle");
    run_window(6,  "post_reset_fixed_first_toggle");

    $display("TOTAL_TEST_CASES=%0d",        TOTAL_TEST_CASES);
    $display("TOTAL_PASSED_TEST_CASES=%0d", TOTAL_PASSED_TEST_CASES);
    $display("TOTAL_FAILED_TEST_CASES=%0d", TOTAL_FAILED_TEST_CASES);
    $display("ALL_TEST_CASES_PASSED=%s",    (TOTAL_FAILED_TEST_CASES==0) ? "true" : "false");
    $finish;
  end
endmodule