`timescale 1ns/1ps // 直方图控制模块Testbench(修复标识符未声明问题) module tb_histogram_ctrl(); // -------------------------- 1. 参数定义(与待测试模块匹配) -------------------------- parameter HIST_RAM_DEPTH = 256; // 直方图RAM深度(像素值0~255) parameter HIST_RAM_DATA_W = 1; // 直方图RAM数据位宽(1bit标记像素存在) parameter CLK_PERIOD = 10; // 时钟周期(10ns = 100MHz) parameter RAM_CLEAR_CYCLES = 256; // 直方图复位需遍历256个地址(256个时钟周期) // -------------------------- 2. 信号定义(仅含模块接口信号,无内部信号引用) -------------------------- reg clk; // 时钟 reg rst_n; // 全局复位(低有效) reg hist_rst; // 直方图复位 reg input_pixel_type; // 像素类型(0=Gray,1=RGB) // CH0 写信号(Gray模式有效/RGB模式R通道) reg hist_wr_en_ch0; // CH0写使能 reg [7:0] hist_wr_addr_ch0; // CH0写地址(像素值0~255) // CH1 写信号(仅RGB模式G通道) reg hist_wr_en_ch1; // CH1写使能 reg [7:0] hist_wr_addr_ch1; // CH1写地址 // CH2 写信号(仅RGB模式B通道) reg hist_wr_en_ch2; // CH2写使能 reg [7:0] hist_wr_addr_ch2; // CH2写地址 // min/max计算配置 reg [15:0] histogram_low_num; // 低位数(第N个有效像素作为min) reg [15:0] histogram_high_num; // 高位数(第N个有效像素作为max) reg calc_en; // 计算使能 // 输出信号 wire calc_done; // 计算完成 wire [7:0] dwidth_conv_min_ch0;// CH0 min结果 wire [7:0] dwidth_conv_max_ch0;// CH0 max结果 wire [7:0] dwidth_conv_min_ch1;// CH1 min结果 wire [7:0] dwidth_conv_max_ch1;// CH1 max结果 wire [7:0] dwidth_conv_min_ch2;// CH2 min结果 wire [7:0] dwidth_conv_max_ch2;// CH2 max结果 // -------------------------- 3. 生成时钟 -------------------------- initial begin clk = 1'b0; forever #(CLK_PERIOD/2) clk = ~clk; // 5ns翻转,100MHz时钟 end // -------------------------- 4. 实例化待测试模块 -------------------------- histogram_ctrl #( .HIST_RAM_DEPTH (HIST_RAM_DEPTH), .HIST_RAM_DATA_W (HIST_RAM_DATA_W) ) u_histogram_ctrl ( .clk (clk), .rst_n (rst_n), .hist_rst (hist_rst), .input_pixel_type (input_pixel_type), .hist_wr_en_ch0 (hist_wr_en_ch0), .hist_wr_addr_ch0 (hist_wr_addr_ch0), .hist_wr_en_ch1 (hist_wr_en_ch1), .hist_wr_addr_ch1 (hist_wr_addr_ch1), .hist_wr_en_ch2 (hist_wr_en_ch2), .hist_wr_addr_ch2 (hist_wr_addr_ch2), .histogram_low_num (histogram_low_num), .histogram_high_num (histogram_high_num), .calc_en (calc_en), .calc_done (calc_done), .dwidth_conv_min_ch0 (dwidth_conv_min_ch0), .dwidth_conv_max_ch0 (dwidth_conv_max_ch0), .dwidth_conv_min_ch1 (dwidth_conv_min_ch1), .dwidth_conv_max_ch1 (dwidth_conv_max_ch1), .dwidth_conv_min_ch2 (dwidth_conv_min_ch2), .dwidth_conv_max_ch2 (dwidth_conv_max_ch2) ); // -------------------------- 5. 生成FSDB波形文件(Verdi可查看) -------------------------- initial begin $fsdbDumpfile("tb.fsdb"); // 波形文件命名为tb.fsdb $fsdbDumpvars(0, tb_histogram_ctrl); // Dump顶层及所有子模块信号 $fsdbDumpMDA(0, tb_histogram_ctrl); // Dump内部RAM(hist_ram_ch0/1/2)内容 end // -------------------------- 6. 核心测试场景(无内部信号引用) -------------------------- initial begin // --------------- 步骤1:初始复位(清除不定态) --------------- rst_n = 1'b0; hist_rst = 1'b0; input_pixel_type = 1'b0; hist_wr_en_ch0 = 1'b0; hist_wr_addr_ch0 = 8'd0; hist_wr_en_ch1 = 1'b0; hist_wr_addr_ch1 = 8'd0; hist_wr_en_ch2 = 1'b0; hist_wr_addr_ch2 = 8'd0; histogram_low_num = 16'd2; // 找第2个有效像素作为min(跳过1个噪声点) histogram_high_num = 16'd2; // 找第2个有效像素作为max(跳过1个噪声点) calc_en = 1'b0; #(CLK_PERIOD * 5); // 复位保持5个时钟周期 rst_n = 1'b1; // 释放全局复位 #(CLK_PERIOD * 2); // 等待稳定 // --------------- 步骤2:测试直方图复位(替代原状态判断) --------------- $display("[%0t] Test 1: Histogram Reset", $time); hist_rst = 1'b1; // 触发直方图复位 #(CLK_PERIOD); // 保持1个时钟周期确保状态切换 hist_rst = 1'b0; // 释放复位 #(CLK_PERIOD * RAM_CLEAR_CYCLES); // 等待复位完成(遍历256个地址) #(CLK_PERIOD * 2); // 额外等待2个周期稳定 $display("[%0t] Test 1 Done: Histogram RAM Cleared", $time); // --------------- 步骤3:灰度模式(Gray)写入与min/max计算 --------------- $display("[%0t] Test 2: Gray Mode (Write + Calc min/max)", $time); input_pixel_type = 1'b0; // 切换为Gray模式(仅CH0有效) // 3.1 写入Gray数据(有效像素值:10、20、30、40、50) hist_wr_en_ch0 = 1'b1;#(CLK_PERIOD); hist_wr_addr_ch0 = 8'd10; #(CLK_PERIOD); hist_wr_addr_ch0 = 8'd20; #(CLK_PERIOD); hist_wr_addr_ch0 = 8'd30; #(CLK_PERIOD); hist_wr_addr_ch0 = 8'd40; #(CLK_PERIOD); hist_wr_addr_ch0 = 8'd50; #(CLK_PERIOD); hist_wr_en_ch0 = 1'b0; // 关闭写使能 #(CLK_PERIOD * 2); // 3.2 触发min/max计算(找第2个min=20,第2个max=40) calc_en = 1'b1; #(CLK_PERIOD); calc_en = 1'b0; // 释放计算使能 wait(calc_done == 1'b1); // 用输出信号判断计算完成(无需内部状态) #(CLK_PERIOD); // 打印结果(预期:min_ch0=20,max_ch0=40) $display("[%0t] Gray Mode Result: min_ch0=%0d, max_ch0=%0d (Expected: 20, 40)", $time, dwidth_conv_min_ch0, dwidth_conv_max_ch0); #(CLK_PERIOD * 2); // --------------- 步骤4:RGB模式写入与min/max计算 --------------- $display("[%0t] Test 3: RGB Mode (Write + Calc min/max)", $time); // 直方图复位(用时间等待替代状态判断) hist_rst = 1'b1; #(CLK_PERIOD); hist_rst = 1'b0; #(CLK_PERIOD * RAM_CLEAR_CYCLES); // 等待复位完成 input_pixel_type = 1'b1; // 切换为RGB模式(CH0=R,CH1=G,CH2=B) #(CLK_PERIOD * 2); // 4.1 写入RGB数据(R:15、25、35;G:45、55、65;B:75、85、95) // 写R通道(CH0) hist_wr_en_ch0 = 1'b1;#(CLK_PERIOD); hist_wr_addr_ch0 = 8'd15; #(CLK_PERIOD); hist_wr_addr_ch0 = 8'd25; #(CLK_PERIOD); hist_wr_addr_ch0 = 8'd35; #(CLK_PERIOD); hist_wr_en_ch0 = 1'b0; // 写G通道(CH1) hist_wr_en_ch1 = 1'b1;#(CLK_PERIOD); hist_wr_addr_ch1 = 8'd45; #(CLK_PERIOD); hist_wr_addr_ch1 = 8'd55; #(CLK_PERIOD); hist_wr_addr_ch1 = 8'd65; #(CLK_PERIOD); hist_wr_en_ch1 = 1'b0; // 写B通道(CH2) hist_wr_en_ch2 = 1'b1;#(CLK_PERIOD); hist_wr_addr_ch2 = 8'd75; #(CLK_PERIOD); hist_wr_addr_ch2 = 8'd85; #(CLK_PERIOD); hist_wr_addr_ch2 = 8'd95; #(CLK_PERIOD); hist_wr_en_ch2 = 1'b0; #(CLK_PERIOD * 2); // 4.2 触发RGB模式计算(预期:R=25/25,G=55/55,B=85/85) calc_en = 1'b1; #(CLK_PERIOD); calc_en = 1'b0; wait(calc_done == 1'b1); // 用输出信号判断完成 #(CLK_PERIOD); // 打印RGB结果 $display("[%0t] RGB Mode Result: R(min=%0d, max=%0d), G(min=%0d, max=%0d), B(min=%0d, max=%0d) (Expected: R=25/25, G=55/55, B=85/85)", $time, dwidth_conv_min_ch0, dwidth_conv_max_ch0, dwidth_conv_min_ch1, dwidth_conv_max_ch1, dwidth_conv_min_ch2, dwidth_conv_max_ch2); #(CLK_PERIOD * 2); // --------------- 步骤5:测试“写+计算”并行触发 --------------- $display("[%0t] Test 4: Trigger Write and Calc Simultaneously", $time); // 直方图复位 hist_rst = 1'b1; #(CLK_PERIOD); hist_rst = 1'b0; #(CLK_PERIOD * RAM_CLEAR_CYCLES); input_pixel_type = 1'b0; // 回到Gray模式 #(CLK_PERIOD * 2); // 先写1个数据,再并行触发“写+计算” hist_wr_en_ch0 = 1'b1; hist_wr_addr_ch0 = 8'd5; #(CLK_PERIOD); calc_en = 1'b1; // 同时触发计算 hist_wr_addr_ch0 = 8'd15; #(CLK_PERIOD); hist_wr_en_ch0 = 1'b0; calc_en = 1'b0; wait(calc_done == 1'b1); // 用输出信号判断完成 #(CLK_PERIOD); $display("[%0t] Test 4 Done: Simultaneous Trigger OK", $time); // --------------- 步骤6:测试完成,结束仿真 --------------- #(CLK_PERIOD * 5); $display("[%0t] All Tests Completed!", $time); $finish; // 结束仿真 end endmodule