315 lines
9.7 KiB
Coq
315 lines
9.7 KiB
Coq
![]() |
`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. 实例化DUT(AXI写控制器) --------------------------
|
|||
|
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);
|
|||
|
|
|||
|
// 测试3:FIFO空阻塞
|
|||
|
$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);
|
|||
|
|
|||
|
// 测试4:AXI握手延迟
|
|||
|
$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
|