AXI DMA Stream_FIFO读写研究 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
目的
- 研究stream_fifo的读写行为
- 研究发现,dma内部其实是有一定容量的fifo的,深度是4
- 写200个,读300,其实只能读出200个来。
框图
axi stream位宽128 bram位宽32
测试代码
`timescale 1ns / 1ps
//此处import报错为vivado bug,不影响仿真
//Import two required packages: axi_vip_pkg and <component_name>_pkg.
//how to get component_name? use tcl command: get_ips *vip*
import axi_vip_pkg::*;
import system_axi_vip_0_0_pkg::*;
module my_sim_top;
bit sys_clk;
bit sys_rst_n;
system_wrapper system_wrapper_i
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n)
);
//AXI4-Lite signals
xil_axi_resp_t resp;
bit[31:0] addr, data, base_addr = 32'h40000000;
//创建时钟和复位信号
// Generate the clock : 50 MHz
initial sys_clk=0;
always #10ns sys_clk = ~sys_clk;
initial begin
//Assert the reset
sys_rst_n = 0;
#500ns
// Release the reset
sys_rst_n = 1;
end
//创建axi_vip的agent
//<component_name>_mst_t
system_axi_vip_0_0_mst_t master_agent;
initial begin
// Step 4 - Create a new agent
master_agent = new("master vip agent",system_wrapper_i.system_i.axi_vip_0.inst.IF);
// Step 5 - Start the agent
master_agent.start_master();
//Wait for the reset to be released
wait (sys_rst_n == 1'b1);
#40us;
init_bram;
#20us;
test_axi4_stream_wr(10);
//#20us;
//write_sr(32'h40000004,1<<12);
//test_axi4_stream_wr(20);
// #20us;
// write_sr(32'h40000004,1<<12);
// test_axi4_stream_wr(16*32);
// read_sr(32'h40000004);
#20us;
//write_sr(32'h40000004,1<<12);
test_axi4_stream_rd(20);
read_sr(32'h40000004);
end
task read_sr;
input [31:0] reg_addr;
repeat(20) begin
master_agent.AXI4LITE_READ_BURST(reg_addr,0,data,resp);
$display("read sr=%x", data);
end
endtask
task write_sr;
input [31:0] reg_addr;
input [31:0] reg_val;
master_agent.AXI4LITE_WRITE_BURST(reg_addr,0,reg_val,resp);
endtask
task init_bram;
byte start_val;
base_addr = 32'hc0000000;
start_val=1;
for(int i=0; i<128*4; i+=4) begin
data[7:0]=start_val+i;
data[15:8]=start_val+i+1;
data[23:16]=start_val+i+2;
data[31:24]=start_val+i+3;
//$display("%x",data);
master_agent.AXI4LITE_WRITE_BURST(base_addr + i,0,data,resp);
end
for(int i=0; i<128*4; i++) begin
master_agent.AXI4LITE_READ_BURST(base_addr + i,0,data,resp);
$display("%x",data);
end
endtask
task test_axi4_stream_wr;
input [31:0] length;
base_addr = 32'h40000000;
addr = 32'h00; data = 32'h0001_0003; //状态清除
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h30; data = 32'h0001_0003; //状态清除
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h18; data = 32'hC000_0000; //配置源地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h28; data = length; //配置传输长度,以byte为单位
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
endtask
task test_axi4_stream_rd;
input [31:0] length;
base_addr = 32'h40000000;
addr = 32'h00; data = 32'h0001_0003; //状态清除
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h30; data = 32'h0001_0003; //状态清除
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h48; data = 32'hC000_1000; //配置源地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h58; data = length; //配置传输长度,以byte为单位
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
endtask
// initial begin
// $monitor("Signal tx changed to %b at time %t", tx, $time);
// end
endmodule
波形(short wr/rd,写10个,读20个)
axi_stream_fifo接口波形。 可见接收后立即就发送了,原因是dma内部有fifo,可以允许接收stream_fifo的数据。
bram的接口波形。 可以看到先read,后write的过程。由于stream位宽128,因此对于bram的读写一次都是4个word。由于写入的数据实际位宽是10,因此注意到wea[3:0]信号, 这个其实就是byte_mask,第1次0xf,第2次0xf,第3次0x3,因此一共4+4+2=10个数据有效。符合预期。 虽然读20个,其实是没有意义的。其实只是读了4次,因为fifo的有效数据最大只有10 bytes。
波形(long wr/rd,写200个,读300个)
axi_stream_fifo接口波形。 可见接收后立即就发送了,原因是dma内部有fifo,可以允许接收stream_fifo的数据,但最多只能接收4个stream数据。这说明dma的内部fifo深度是4。
bram的接口波形。 可以看到先read,后write的过程。由于stream位宽128,因此对于bram的读写一次都是4个word。 虽然读300bytes,其实是没有意义的。其实只是读了50次,因为fifo的有效数据最大只有200bytes。