Files
IPA/tb/data_cache/tb_axi_write_ctrl.v

315 lines
9.7 KiB
Coq
Raw Normal View History

2025-08-26 16:53:22 +08:00
`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