`timescale 1ns / 1ps

module tb_pulse_cnt();

    // 参数定义
    localparam CLK_FREQ = 50_000_000;   // 50 MHz 时钟
    localparam CLK_PERIOD = 20ns;       // 1/50MHz = 20ns

    // 信号声明
    reg         clk;
    reg         rst_n;
    reg  [23:0] win_us;
    reg         sig_in;
    wire [23:0] cnt_out;
    wire        vld_out;

    // 实例化被测模块
    pulse_cnt #(
        .CLK_FREQ(CLK_FREQ)
    ) dut (
        .clk    (clk),
        .rst_n  (rst_n),
        .sig_in (sig_in),
        .win_us (win_us),
        .cnt_out(cnt_out),
        .vld_out(vld_out)
    );

    // 时钟生成
    initial begin
        clk = 0;
        forever #(CLK_PERIOD/2) clk = ~clk;
    end

    // 测试激励
    initial begin
        // 初始化
        rst_n   = 0;
        win_us  = 24'd1000;     // 默认窗口 1000 us = 1 ms
        sig_in  = 0;
        
        // 释放复位
        repeat(5) @(posedge clk);
        rst_n = 1;
        repeat(2) @(posedge clk);
        
        // --------------------------------------------------
        // 测试1：窗口内无脉冲
        // --------------------------------------------------
        $display("Test 1: No pulse, expect cnt_out = 0 after window");
        win_us = 24'd1000;      // 1 ms 窗口
        wait (vld_out);
        $display("  cnt_out = %0d (expected 0)", cnt_out);
        #(CLK_PERIOD*2);
        
        // --------------------------------------------------
        // 测试2：固定频率脉冲 50 kHz (周期 20 us)
        // --------------------------------------------------
        $display("Test 2: 50 kHz pulse, window = 1 ms -> expected 50 pulses");
        fork
            begin : pulse_gen
                forever begin
                    #10us sig_in = 1;
                    #10us sig_in = 0;
                end
            end
        join_none
        
        wait (vld_out);
        $display("  cnt_out = %0d (expected 50)", cnt_out);
        #(CLK_PERIOD*2);
        disable pulse_gen;
        
        // --------------------------------------------------
        // 测试3：脉冲频率 250 kHz (周期 2 us)，窗口 1 ms -> 250 个脉冲
        // --------------------------------------------------
        $display("Test 3: 250 kHz pulse, window = 1 ms -> expected 250 pulses");
        fork
            begin : pulse_gen2
                forever begin
                    #2us sig_in = 1;
                    #2us sig_in = 0;
                end
            end
        join_none
        
        wait (vld_out);
        $display("  cnt_out = %0d (expected 250)", cnt_out);
        #(CLK_PERIOD*2);
        disable pulse_gen2;
        
        // --------------------------------------------------
        // 测试4：动态改变窗口宽度 (2 ms)，脉冲频率 250 kHz
        // --------------------------------------------------
        $display("Test 4: 250 kHz pulse, window = 2 ms -> expected 500 pulses");
        win_us = 24'd2000;      // 2 ms

        // 重新启动一个脉冲生成进程
        fork
            begin : pulse_gen3
                forever begin
                    #2us sig_in = 1;   // 250 kHz -> 周期 4 us
                    #2us sig_in = 0;
                end
            end
        join_none

        wait (vld_out);
        $display("  cnt_out = %0d (expected 500)", cnt_out);
        #(CLK_PERIOD*2);
        disable pulse_gen3;
        // --------------------------------------------------
        // 测试5：边界情况 - 窗口极小 (1 us)
        // --------------------------------------------------
        $display("Test 5: 500 kHz pulse, window = 1 us -> expected 0.5? rounded to 0 or 1?");
        win_us = 24'd2;
        // 重新启动一个脉冲生成进程
        fork
            begin : pulse_gen4
                forever begin
                    #1us sig_in = 1;   
                    #1us sig_in = 0;
                end
            end
        join_none

        wait (vld_out);
        $display("  cnt_out = %0d (expected 500)", cnt_out);
        #(CLK_PERIOD*2);
        disable pulse_gen4;
        
        // --------------------------------------------------
        // 测试6：复位过程中行为
        // --------------------------------------------------
        $display("Test 6: Assert reset mid-window, check output goes to 0");
        win_us = 24'd1000;
        #(500us);               // 窗口中间复位
        rst_n = 0;
        repeat(5) @(posedge clk);
        rst_n = 1;
        wait (vld_out);
        $display("  cnt_out = %0d (should be fresh measurement)", cnt_out);
        
        #(10us);
        $display("Simulation finished.");
        $finish;
    end

    // 监控输出有效标志并打印结果
    always @(posedge vld_out) begin
        $display("[%t] vld_out asserted, cnt_out = %0d", $time, cnt_out);
    end

    // 可选：波形转储
    initial begin
        $dumpfile("tb_pulse_cnt.vcd");
        $dumpvars(0, tb_pulse_cnt);
    end

endmodule