Files
IPA/tb/data_cache/tb_data_cache.v

451 lines
15 KiB
Coq
Raw Permalink Normal View History

2025-08-26 16:53:22 +08:00
`timescale 1ns/1ps
module tb_data_cache();
// -------------------------- 参数定义 --------------------------
parameter ASYNC_FIFO_DEPTH = 1024;
parameter ASYNC_FIFO_DATA_W = 27;
parameter SYNC_FIFO_DEPTH = 2048;
parameter SYNC_FIFO_DATA_W = 256;
parameter HIST_RAM_DEPTH = 256;
parameter HIST_RAM_DATA_W = 1;
parameter AXI_ID_W = 8;
parameter AXI_ADDR_W = 32;
parameter AXI_DATA_W = 256;
parameter AXI_STRB_W = AXI_DATA_W / 8;
// 测试用图像参数
parameter IMAGE_WIDTH = 32; // 图像宽度32像素便于拼接256bit
parameter IMAGE_HEIGHT = 16; // 图像高度
parameter HIST_LOW_NUM = 1; // 直方图低位数量
parameter HIST_HIGH_NUM = 1; // 直方图高位数量
// 时钟周期定义
parameter SYS_CLK_PERIOD = 10; // 系统时钟周期(10ns=100MHz)
parameter IR_CLK_PERIOD = 5; // IR时钟周期(8ns=125MHz)
// -------------------------- 信号定义 --------------------------
// 系统时钟与复位
reg sys_clk;
reg ir_clk;
reg rst_n;
// 配置信号
reg ipa_en;
reg update_src_trig;
reg input_pixel_type;
reg [15:0] src_pixel_height;
reg [15:0] src_pixel_width;
reg [15:0] histogram_low_num;
reg [15:0] histogram_high_num;
wire src_image_cache_done;
// 与Windowed模块接口
wire [7:0] dwidth_conv_min_ch0;
wire [7:0] dwidth_conv_max_ch0;
wire [7:0] dwidth_conv_min_ch1;
wire [7:0] dwidth_conv_max_ch1;
wire [7:0] dwidth_conv_min_ch2;
wire [7:0] dwidth_conv_max_ch2;
// IR图像输入
reg ir_valid;
reg ir_vs;
reg ir_hs;
reg [7:0] ir_ch0;
reg [7:0] ir_ch1;
reg [7:0] ir_ch2;
// AXI写总线
wire [AXI_ID_W-1:0] axi_m_awid;
wire [AXI_ADDR_W-1:0] axi_m_awaddr;
wire [3:0] axi_m_awlen;
wire [2:0] axi_m_awsize;
wire [1:0] axi_m_awburst;
wire axi_m_awlock;
wire [3:0] axi_m_awcache;
wire [2:0] axi_m_awprot;
wire [3:0] axi_m_awqos;
wire axi_m_awvalid;
reg axi_m_awready;
wire [AXI_ID_W-1:0] axi_m_wid;
wire [AXI_DATA_W-1:0] axi_m_wdata;
wire [AXI_STRB_W-1:0] axi_m_wstrb;
wire axi_m_wlast;
wire axi_m_wvalid;
reg axi_m_wready;
reg [AXI_ID_W-1:0] axi_m_bid;
reg [1:0] axi_m_bresp;
reg axi_m_bvalid;
wire axi_m_bready;
// 内部测试信号
reg [15:0] frame_cnt; // 帧计数器
reg [15:0] ir_row_cnt; // IR行计数器
reg [15:0] ir_col_cnt; // IR列计数器
reg [7:0] golden_min_ch0; // 预期CH0最小值
reg [7:0] golden_max_ch0; // 预期CH0最大值
reg [7:0] golden_min_ch1; // 预期CH1最小值
reg [7:0] golden_max_ch1; // 预期CH1最大值
reg [7:0] golden_min_ch2; // 预期CH2最小值
reg [7:0] golden_max_ch2; // 预期CH2最大值
// -------------------------- 时钟生成 --------------------------
initial begin
sys_clk = 1'b0;
forever #(SYS_CLK_PERIOD/2) sys_clk = ~sys_clk;
end
initial begin
ir_clk = 1'b0;
forever #(IR_CLK_PERIOD/2) ir_clk = ~ir_clk;
end
// -------------------------- 实例化DUT --------------------------
data_cache #(
.ASYNC_FIFO_DEPTH(ASYNC_FIFO_DEPTH),
.ASYNC_FIFO_DATA_W(ASYNC_FIFO_DATA_W),
.SYNC_FIFO_DEPTH(SYNC_FIFO_DEPTH),
.SYNC_FIFO_DATA_W(SYNC_FIFO_DATA_W),
.HIST_RAM_DEPTH(HIST_RAM_DEPTH),
.HIST_RAM_DATA_W(HIST_RAM_DATA_W),
.AXI_ID_W(AXI_ID_W),
.AXI_ADDR_W(AXI_ADDR_W),
.AXI_DATA_W(AXI_DATA_W),
.AXI_STRB_W(AXI_STRB_W)
) u_data_cache (
.clk(sys_clk),
.rst_n(rst_n),
.ipa_en(ipa_en),
.update_src_trig(update_src_trig),
.input_pixel_type(input_pixel_type),
.src_pixel_height(src_pixel_height),
.src_pixel_width(src_pixel_width),
.histogram_low_num(histogram_low_num),
.histogram_high_num(histogram_high_num),
.src_image_cache_done(src_image_cache_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),
.ir_clk(ir_clk),
.ir_valid(ir_valid),
.ir_vs(ir_vs),
.ir_hs(ir_hs),
.ir_ch0(ir_ch0),
.ir_ch1(ir_ch1),
.ir_ch2(ir_ch2),
.axi_m_awid(axi_m_awid),
.axi_m_awaddr(axi_m_awaddr),
.axi_m_awlen(axi_m_awlen),
.axi_m_awsize(axi_m_awsize),
.axi_m_awburst(axi_m_awburst),
.axi_m_awlock(axi_m_awlock),
.axi_m_awcache(axi_m_awcache),
.axi_m_awprot(axi_m_awprot),
.axi_m_awqos(axi_m_awqos),
.axi_m_awvalid(axi_m_awvalid),
.axi_m_awready(axi_m_awready),
.axi_m_wid(axi_m_wid),
.axi_m_wdata(axi_m_wdata),
.axi_m_wstrb(axi_m_wstrb),
.axi_m_wlast(axi_m_wlast),
.axi_m_wvalid(axi_m_wvalid),
.axi_m_wready(axi_m_wready),
.axi_m_bid(axi_m_bid),
.axi_m_bresp(axi_m_bresp),
.axi_m_bvalid(axi_m_bvalid),
.axi_m_bready(axi_m_bready)
);
// -------------------------- 生成FSDB波形 --------------------------
initial begin
$fsdbDumpfile("tb.fsdb");
$fsdbDumpvars(0, tb_data_cache);
$fsdbDumpMDA(0, tb_data_cache); // 记录内存和内部信号
end
// -------------------------- AXI从机模拟 --------------------------
// AW通道响应
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
axi_m_awready <= 1'b0;
end else if (axi_m_awvalid) begin
// 随机延迟响应模拟真实从机
axi_m_awready <= ($random % 2) ? 1'b1 : 1'b0;
if (!axi_m_awready) begin
axi_m_awready <= #(SYS_CLK_PERIOD) 1'b1;
end
end else begin
axi_m_awready <= 1'b0;
end
end
// W通道响应
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
axi_m_wready <= 1'b0;
end else if (axi_m_wvalid) begin
axi_m_wready <= ($random % 2) ? 1'b1 : 1'b0;
if (!axi_m_wready) begin
axi_m_wready <= #(SYS_CLK_PERIOD) 1'b1;
end
end else begin
axi_m_wready <= 1'b0;
end
end
// B通道响应
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
axi_m_bvalid <= 1'b0;
axi_m_bid <= 8'd0;
axi_m_bresp <= 2'd0; // 0=OKAY
end else if (axi_m_wvalid && axi_m_wready) begin
// W通道传输完成后延迟1周期发送响应
axi_m_bvalid <= #(SYS_CLK_PERIOD) 1'b1;
axi_m_bid <= axi_m_wid;
end else if (axi_m_bvalid && axi_m_bready) begin
axi_m_bvalid <= 1'b0;
end
end
// -------------------------- 生成测试图像数据 --------------------------
task generate_ir_data;
input integer frame_num;
input integer is_rgb;
begin
// 初始化计数器
ir_row_cnt = 0;
ir_col_cnt = 0;
ir_vs = 1'b0;
ir_hs = 1'b0;
ir_valid = 1'b0;
ir_ch0 = 8'd0;
ir_ch1 = 8'd0;
ir_ch2 = 8'd0;
// 发送帧起始信号ir_vs至少持续2个ir_clk周期确保被FIFO捕获
@(posedge ir_clk);
ir_vs = 1'b1;
ir_valid = 1'b1; // 强制置1配合DUT的async_fifo_wr_en逻辑
@(posedge ir_clk);
@(posedge ir_clk); // 持续2个周期避免单周期漏采
ir_vs = 1'b0;
ir_valid = 1'b0;
// 计算预期的min/max值
if (is_rgb) begin
golden_min_ch0 = 8'd32 + frame_num * 16;
golden_max_ch0 = 8'd96 + frame_num * 16;
golden_min_ch1 = 8'd64 + frame_num * 16;
golden_max_ch1 = 8'd128 + frame_num * 16;
golden_min_ch2 = 8'd96 + frame_num * 16;
golden_max_ch2 = 8'd160 + frame_num * 16;
end else begin
golden_min_ch0 = 8'd32 + frame_num * 16;
golden_max_ch0 = 8'd192 + frame_num * 16;
golden_min_ch1 = 8'd0;
golden_max_ch1 = 8'd0;
golden_min_ch2 = 8'd0;
golden_max_ch2 = 8'd0;
end
// 逐行发送数据
while (ir_row_cnt < IMAGE_HEIGHT) begin
// 行起始信号
ir_hs = 1'b1;
@(posedge ir_clk);
ir_hs = 1'b0;
// 逐像素发送数据
ir_col_cnt = 0;
while (ir_col_cnt < IMAGE_WIDTH) begin
ir_valid = 1'b1;
// 生成有规律的数据便于验证
if (is_rgb) begin
// RGB模式三个通道不同范围
ir_ch0 = golden_min_ch0 + (ir_row_cnt % (golden_max_ch0 - golden_min_ch0 + 1));
ir_ch1 = golden_min_ch1 + (ir_col_cnt % (golden_max_ch1 - golden_min_ch1 + 1));
ir_ch2 = golden_min_ch2 + ((ir_row_cnt + ir_col_cnt) % (golden_max_ch2 - golden_min_ch2 + 1));
end else begin
// 灰度模式仅CH0有效
ir_ch0 = golden_min_ch0 + ((ir_row_cnt * IMAGE_WIDTH + ir_col_cnt) %
(golden_max_ch0 - golden_min_ch0 + 1));
ir_ch1 = 8'd0;
ir_ch2 = 8'd0;
end
@(posedge ir_clk);
ir_col_cnt = ir_col_cnt + 1;
end
// 行结束
ir_valid = 1'b0;
ir_row_cnt = ir_row_cnt + 1;
// 行间隙
repeat(2) @(posedge ir_clk);
end
// 帧结束
ir_valid = 1'b0;
// 帧间隙
repeat(5) @(posedge ir_clk);
end
endtask
// -------------------------- 核心测试流程 --------------------------
initial begin
// 初始化
rst_n = 1'b0;
ipa_en = 1'b0;
update_src_trig = 1'b0;
input_pixel_type = 1'b0; // 默认灰度模式
src_pixel_height = IMAGE_HEIGHT;
src_pixel_width = IMAGE_WIDTH;
histogram_low_num = HIST_LOW_NUM;
histogram_high_num = HIST_HIGH_NUM;
frame_cnt = 16'd0;
axi_m_bid = 8'd0;
axi_m_bresp = 2'd0;
axi_m_bvalid = 1'b0;
// 复位
#(SYS_CLK_PERIOD * 10);
rst_n = 1'b1;
#(SYS_CLK_PERIOD * 5);
// 测试1灰度模式单帧测试
$display("[%0t] Test 1: Gray scale single frame test", $time);
input_pixel_type = 1'b0; // 灰度模式
ipa_en = 1'b1;
#(SYS_CLK_PERIOD * 2);
// 发送一帧灰度图像
generate_ir_data(frame_cnt, 0);
frame_cnt = frame_cnt + 1;
// 等待缓存完成
wait(src_image_cache_done == 1'b1);
#(SYS_CLK_PERIOD * 10);
// 验证直方图结果
$display("[%0t] Test 1 Histogram Check: CH0 min=%h (exp=%h), max=%h (exp=%h)",
$time, dwidth_conv_min_ch0, golden_min_ch0,
dwidth_conv_max_ch0, golden_max_ch0);
if (dwidth_conv_min_ch0 != golden_min_ch0 || dwidth_conv_max_ch0 != golden_max_ch0) begin
$display("[%0t] Test 1 Histogram Check FAILED!", $time);
end else begin
$display("[%0t] Test 1 Histogram Check PASSED!", $time);
end
#(SYS_CLK_PERIOD * 5);
// 测试2RGB模式单帧测试
$display("[%0t] Test 2: RGB single frame test", $time);
update_src_trig = 1'b1; // 触发更新
#(SYS_CLK_PERIOD * 2);
update_src_trig = 1'b0;
input_pixel_type = 1'b1; // RGB模式
#(SYS_CLK_PERIOD * 2);
// 发送一帧RGB图像
generate_ir_data(frame_cnt, 1);
frame_cnt = frame_cnt + 1;
// 等待缓存完成
wait(src_image_cache_done == 1'b1);
#(SYS_CLK_PERIOD * 10);
// 验证直方图结果
$display("[%0t] Test 2 Histogram Check: CH0 min=%h (exp=%h), max=%h (exp=%h)",
$time, dwidth_conv_min_ch0, golden_min_ch0,
dwidth_conv_max_ch0, golden_max_ch0);
$display("[%0t] Test 2 Histogram Check: CH1 min=%h (exp=%h), max=%h (exp=%h)",
$time, dwidth_conv_min_ch1, golden_min_ch1,
dwidth_conv_max_ch1, golden_max_ch1);
$display("[%0t] Test 2 Histogram Check: CH2 min=%h (exp=%h), max=%h (exp=%h)",
$time, dwidth_conv_min_ch2, golden_min_ch2,
dwidth_conv_max_ch2, golden_max_ch2);
if (dwidth_conv_min_ch0 != golden_min_ch0 || dwidth_conv_max_ch0 != golden_max_ch0 ||
dwidth_conv_min_ch1 != golden_min_ch1 || dwidth_conv_max_ch1 != golden_max_ch1 ||
dwidth_conv_min_ch2 != golden_min_ch2 || dwidth_conv_max_ch2 != golden_max_ch2) begin
$display("[%0t] Test 2 Histogram Check FAILED!", $time);
end else begin
$display("[%0t] Test 2 Histogram Check PASSED!", $time);
end
#(SYS_CLK_PERIOD * 5);
// 测试3连续两帧测试验证FIFO和AXI写连续性
$display("[%0t] Test 3: Continuous frame test", $time);
update_src_trig = 1'b1;
#(SYS_CLK_PERIOD * 2);
update_src_trig = 1'b0;
#(SYS_CLK_PERIOD * 2);
// 发送第3帧灰度
input_pixel_type = 1'b0;
generate_ir_data(frame_cnt, 0);
frame_cnt = frame_cnt + 1;
wait(src_image_cache_done == 1'b1);
#(SYS_CLK_PERIOD * 5);
// 发送第4帧RGB
input_pixel_type = 1'b1;
generate_ir_data(frame_cnt, 1);
frame_cnt = frame_cnt + 1;
wait(src_image_cache_done == 1'b1);
#(SYS_CLK_PERIOD * 10);
// 测试4更新触发测试验证中途更新配置
$display("[%0t] Test 4: Update trigger test", $time);
input_pixel_type = 1'b0;
generate_ir_data(frame_cnt, 0);
frame_cnt = frame_cnt + 1;
// 中途发送更新触发
#(SYS_CLK_PERIOD * 20);
update_src_trig = 1'b1;
#(SYS_CLK_PERIOD * 5);
update_src_trig = 1'b0;
#(SYS_CLK_PERIOD * 10);
// 所有测试完成
$display("[%0t] All tests completed!", $time);
$finish;
end
// -------------------------- 监控AXI写事务 --------------------------
always @(posedge sys_clk) begin
if (axi_m_awvalid && axi_m_awready) begin
$display("[%0t] AXI Write Transaction: Address=0x%08h, Length=%d",
$time, axi_m_awaddr, axi_m_awlen);
end
if (axi_m_wvalid && axi_m_wready) begin
$display("[%0t] AXI Write Data: ID=%d, Data[31:0]=0x%08h, Last=%b",
$time, axi_m_wid, axi_m_wdata[31:0], axi_m_wlast);
end
end
// -------------------------- 监控状态转换 --------------------------
reg [2:0] prev_state;
always @(posedge sys_clk) begin
prev_state <= u_data_cache.curr_state;
if (prev_state != u_data_cache.curr_state) begin
case (u_data_cache.curr_state)
3'b000: $display("[%0t] Data Cache State: IDLE", $time);
3'b001: $display("[%0t] Data Cache State: WAIT_VS", $time);
3'b010: $display("[%0t] Data Cache State: RECEIVE_DATA", $time);
3'b011: $display("[%0t] Data Cache State: WRITE_FIFO", $time);
3'b100: $display("[%0t] Data Cache State: WAIT_AXI", $time);
3'b101: $display("[%0t] Data Cache State: FRAME_DONE", $time);
endcase
end
end
endmodule