Files
IPA/tb/data_cache/tb_axi_write_ctrl.v
Core_kingdom 79dee10db1 cache module
2025-08-26 16:53:22 +08:00

315 lines
9.7 KiB
Verilog
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

`timescale 1ns/1ps
module tb_axi_write_ctrl();
// -------------------------- 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 CLK_PERIOD = 10;
parameter FIFO_DEPTH = 4;
// -------------------------- 2. 信号定义 --------------------------
// 系统时钟/复位
reg clk;
reg rst_n;
// 控制与数据输入
reg start_en;
reg [AXI_ADDR_W-1:0] sram_base_addr;
wire [AXI_DATA_W-1:0] fifo_rd_data;
wire fifo_empty;
wire fifo_rd_en_dut; // DUT输出的读使能仅由DUT驱动
// Testbench控制的FIFO读使能用于清空FIFO
reg tb_fifo_rd_en;
// 合并后的FIFO读使能仅驱动FIFO避免直接驱动DUT输出
wire fifo_rd_en = tb_fifo_rd_en | fifo_rd_en_dut;
// AXI AW通道
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 [4:0] axi_m_awcache;
wire [2:0] axi_m_awprot;
wire [4:0] axi_m_awqos;
wire axi_m_awvalid;
reg axi_m_awready;
// AXI W通道
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;
// AXI B通道
reg [AXI_ID_W-1:0] axi_m_bid;
reg [1:0] axi_m_bresp;
reg axi_m_bvalid;
wire axi_m_bready;
// DUT状态输出
wire axi_busy;
wire axi_done;
// FIFO相关控制信号
reg fifo_wr_en;
reg [AXI_DATA_W-1:0] fifo_wr_data;
wire fifo_full;
reg [$clog2(FIFO_DEPTH)-1:0] fifo_wr_ptr;
// -------------------------- 3. 生成系统时钟 --------------------------
initial begin
clk = 1'b0;
forever #(CLK_PERIOD/2) clk = ~clk;
end
// -------------------------- 4. 实例化DUTAXI写控制器 --------------------------
axi_write_ctrl #(
.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_axi_write_ctrl (
.clk (clk),
.rst_n (rst_n),
.start_en (start_en),
.sram_base_addr (sram_base_addr),
.fifo_rd_data (fifo_rd_data),
.fifo_empty (fifo_empty),
.fifo_rd_en (fifo_rd_en_dut), // DUT输出单独命名避免冲突
.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),
.axi_busy (axi_busy),
.axi_done (axi_done)
);
// -------------------------- 5. 实例化sync_fifo模块 --------------------------
sync_fifo #(
.DATA_WIDTH (AXI_DATA_W),
.FIFO_DEPTH (FIFO_DEPTH)
) u_sync_fifo (
.clk (clk),
.rst_n (rst_n),
.wr_en (fifo_wr_en),
.wr_data (fifo_wr_data),
.full (fifo_full),
.rd_en (fifo_rd_en), // 使用合并后的读使能
.rd_data (fifo_rd_data),
.empty (fifo_empty)
);
// -------------------------- 6. 生成FSDB波形文件 --------------------------
initial begin
$fsdbDumpfile("tb.fsdb");
$fsdbDumpvars(0, tb_axi_write_ctrl);
$fsdbDumpMDA(0, tb_axi_write_ctrl);
end
// -------------------------- 7. FIFO初始化与数据写入 --------------------------
reg [AXI_DATA_W-1:0] fifo_init_data[FIFO_DEPTH-1:0];
initial begin
fifo_init_data[0] = 256'h00010203_04050607_08090a0b_0c0d0e0f_10111213_14151617_18191a1b_1c1d1e1f;
fifo_init_data[1] = 256'h20212223_24252627_28292a2b_2c2d2e2f_30313233_34353637_38393a3b_3c3d3e3f;
fifo_init_data[2] = 256'h40414243_44454647_48494a4b_4c4d4e4f_50515253_54555657_58595a5b_5c5d5e5f;
fifo_init_data[3] = 256'h60616263_64656667_68696a6b_6c6d6e6f_70717273_74757677_78797a7b_7c7d7e7f;
end
task fill_fifo;
input integer count;
begin
fifo_wr_en = 1'b1;
repeat(count) begin
@(posedge clk);
if (!fifo_full) begin
fifo_wr_data = fifo_init_data[fifo_wr_ptr];
fifo_wr_ptr = fifo_wr_ptr + 1'b1;
if (fifo_wr_ptr >= FIFO_DEPTH) fifo_wr_ptr = 0;
end
end
fifo_wr_en = 1'b0;
@(posedge clk);
end
endtask
// -------------------------- 8. 模拟AXI从机 --------------------------
always @(posedge 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 && axi_m_awvalid) begin
axi_m_awready <= #(CLK_PERIOD) 1'b1;
end
end else begin
axi_m_awready <= 1'b0;
end
end
always @(posedge 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 && axi_m_wvalid) begin
axi_m_wready <= #(CLK_PERIOD) 1'b1;
end
end else begin
axi_m_wready <= 1'b0;
end
end
always @(posedge 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;
end else if (axi_m_wvalid && axi_m_wready) begin
axi_m_bvalid <= #(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
// -------------------------- 9. 核心测试场景 --------------------------
initial begin
rst_n = 1'b0;
start_en = 1'b0;
sram_base_addr = 32'h1000_0000;
fifo_wr_en = 1'b0;
fifo_wr_data = {AXI_DATA_W{1'b0}};
fifo_wr_ptr = 0;
tb_fifo_rd_en = 1'b0;
axi_m_bid = 8'd0;
axi_m_bresp = 2'd0;
axi_m_bvalid = 1'b0;
#(CLK_PERIOD * 5);
rst_n = 1'b1;
#(CLK_PERIOD * 2);
// 测试1单事务写
$display("[%0t] Test 1: Single AXI Write Transaction", $time);
fill_fifo(FIFO_DEPTH);
start_en = 1'b1;
#(CLK_PERIOD);
start_en = 1'b0;
wait(axi_done == 1'b1);
#(CLK_PERIOD);
$display("[%0t] Test 1 Result: AWAddr=0x%08h (Expected:0x10000000), WData Match=%b",
$time, axi_m_awaddr, (axi_m_wdata == fifo_init_data[0]));
#(CLK_PERIOD * 2);
// 测试2连续事务写
$display("[%0t] Test 2: Continuous AXI Write Transactions", $time);
fill_fifo(FIFO_DEPTH);
#(CLK_PERIOD);
start_en = 1'b1;
#(CLK_PERIOD);
start_en = 1'b0;
wait(axi_done == 1'b1);
#(CLK_PERIOD);
$display("[%0t] Test 2 Trans1: AWAddr=0x%08h (Expected:0x10000020), WData Match=%b",
$time, axi_m_awaddr, (axi_m_wdata == fifo_init_data[1]));
fill_fifo(FIFO_DEPTH);
#(CLK_PERIOD);
start_en = 1'b1;
#(CLK_PERIOD);
start_en = 1'b0;
wait(axi_done == 1'b1);
#(CLK_PERIOD);
$display("[%0t] Test 2 Trans2: AWAddr=0x%08h (Expected:0x10000040), WData Match=%b",
$time, axi_m_awaddr, (axi_m_wdata == fifo_init_data[2]));
#(CLK_PERIOD * 2);
// 测试3FIFO空阻塞
$display("[%0t] Test 3: FIFO Empty Block Test", $time);
tb_fifo_rd_en = 1'b1; // 使用Testbench读使能清空FIFO
while (!fifo_empty) begin
@(posedge clk);
end
tb_fifo_rd_en = 1'b0;
#(CLK_PERIOD);
start_en = 1'b1;
#(CLK_PERIOD * 3);
start_en = 1'b0;
$display("[%0t] Test 3 Result: AXI Busy=%b (Expected:0), AWValid=%b (Expected:0)",
$time, axi_busy, axi_m_awvalid);
#(CLK_PERIOD * 2);
// 测试4AXI握手延迟
$display("[%0t] Test 4: AXI Handshake Delay Test", $time);
fill_fifo(FIFO_DEPTH);
#(CLK_PERIOD);
axi_m_awready <= 1'b0;
axi_m_wready <= 1'b0;
start_en = 1'b1;
#(CLK_PERIOD);
start_en = 1'b0;
#(CLK_PERIOD * 2);
axi_m_awready <= 1'b1;
#(CLK_PERIOD);
axi_m_wready <= 1'b1;
wait(axi_done == 1'b1);
#(CLK_PERIOD);
$display("[%0t] Test 4 Result: WData Match=%b (Expected:1), Done=%b (Expected:1)",
$time, (axi_m_wdata == fifo_init_data[3]), axi_done);
#(CLK_PERIOD * 2);
$display("[%0t] All Tests Completed!", $time);
$finish;
end
// -------------------------- 10. 状态监控 --------------------------
reg [1:0] axi_state;
always @(posedge clk) begin
axi_state = u_axi_write_ctrl.axi_state;
end
always @(posedge clk) begin
case (axi_state)
2'd0: $display("[%0t] AXI State: IDLE", $time);
2'd1: $display("[%0t] AXI State: AW (Address Channel)", $time);
2'd2: $display("[%0t] AXI State: W (Data Channel)", $time);
2'd3: $display("[%0t] AXI State: B (Response Channel)", $time);
endcase
end
endmodule