AXI VIP DMA CDMA BRAM AXI4_IP综合验证(DMA,CDMA,StreamIP, BRAM大位宽) - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
配置
- DMA位宽128,burst=64
- CDMA位宽128,burst=64
- BRAM位宽128
- StreamIP位宽128
task init_bram;
byte start_val;
reg [31:0] curr_val;
base_addr = 32'hc0000000;
start_val=1;
for(int i=0; i<128*4; i+=4) begin
if(i>=256) start_val=17;
curr_val[7:0]=start_val+i;
curr_val[15:8]=start_val+i+1;
curr_val[23:16]=start_val+i+2;
curr_val[31:24]=start_val+i+3;
//$display("%x",curr_val);
master_agent.AXI4LITE_WRITE_BURST(base_addr + i,0,curr_val,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
说明:由于bram的位宽已经是128了,我们的task仍然是以32位对其进行读写。所以读出的数据,地址必须每隔128,数据才会变化一次。在128以内的4个子地址,读出的结果都是相同的。因为bram是一次读出128位的数据。
DMA执行Bram<-->AXI stream ip的拷贝波形(data witdh=128)
dma:axi_mm2s的波形,这是读bram的接口。可见,当增加了max busrt size后,一次即可传输完成,不用分2次。传输的size=32,与代码的设置值一样,符合预期。
dma:axis_mm2s的波形,这是往stream_fifo发数据的接口。也是一次busrt传输完成。
stream data fifo:写fifo的波形和读fifo的波形。可见,axi stream的协议非常简单,只有3个控制信号tvalid/tready/tlast
CDMA执行Bram<-->Bram的拷贝波形(data witdh=128)
bram:wdata/rdata部分。可以看到,发起了1次传输,每次长度=0x1f(对应32),这个与cdma的burst长度是一样的,因为位宽都是64。
CDMA执行Bram<-->AXI full ip的拷贝波形(data witdh=128)
axi_full_ip:写入burst_size=128,位宽是32。写入数据是正确的。
bram:读的波形,一次读出128bits。注意到刚开始的时候读的快,每个cycle读一个128bits。后面读的满。怀疑是内置的fifo发生了满/空,产生了流控。
bram_ctrl:axi4的波形,注意valid/ready,确实发生了流控。
axi_full_ip:读burst_size=128,位宽是32。读出数据是正确的。
bram:写的波形,一次写入128bits,需要8个cycles。为什么是8个cycles?因为axi_full_ip每读一个数据,需要2个cycles。而bram位宽128,axi_full_ip位宽32,是4:1的关系,因此需要4x2=8个cycles。
总结
不管是bram/dma/cdma/stream_ip等都可以设置为128位宽,与cpu平台无关。哪怕cpu是32bits的也是可以的。只不过是cpu需要多次填满一行数据。
附录:vip程序备份
`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
(
.clk(sys_clk),
.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;
// #40us;
// test_axi4_stream_ip;
// #40us;
// test_cdma_bram2bram;
#40us;
test_cdma_bram2axi_full;
// #40us;
// test_cdma_bram2axi_lite;
end
task init_bram;
byte start_val;
reg [31:0] curr_val;
base_addr = 32'hc0000000;
start_val=1;
for(int i=0; i<128*4; i+=4) begin
if(i>=256) start_val=17;
curr_val[7:0]=start_val+i;
curr_val[15:8]=start_val+i+1;
curr_val[23:16]=start_val+i+2;
curr_val[31:24]=start_val+i+3;
//$display("%x",curr_val);
master_agent.AXI4LITE_WRITE_BURST(base_addr + i,0,curr_val,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_ip;
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 = 16*32; //配置传输长度,以byte为单位
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
endtask
task test_cdma_bram2bram;
base_addr = 32'h41000000;
addr = 32'h18; data = 32'hC000_0000; //配置源地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h20; data = 32'hC000_1000; //配置目的地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h28; data = 16*32; //配置传输长度,以byte为单位
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
endtask
task test_cdma_bram2axi_full;
base_addr = 32'h41000000;
//write burst
addr = 32'h18; data = 32'hC000_0000; //配置源地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h20; data = 32'h4200_0000; //配置目的地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h28; data = 16*32; //配置传输长度,以byte为单位
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
//read burst
#40us
addr = 32'h18; data = 32'h4200_0000; //配置源地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h20; data = 32'hC000_1000; //配置目的地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h28; data = 16*32; //配置传输长度,以byte为单位
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
endtask
task test_cdma_bram2axi_lite;
base_addr = 32'h41000000;
//fill axi_lite_ip regs
addr = 32'h18; data = 32'hC000_0000; //配置源地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h20; data = 32'h4300_0000; //配置目的地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h28; data = 32'd32; //配置传输长度,以byte为单位
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
//write burst with fixed reg
#10us
addr = 32'h00; data = 32'h0000_0020; //key_hole_wr=1
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'h20; data = 32'h4300_0000; //配置目的地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h28; data = 32'd128*4; //配置传输长度,以byte为单位
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
//read burst with fixed reg
#10us
addr = 32'h00; data = 32'h0000_0010; //key_hole_rd=1
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h18; data = 32'h4300_0000; //配置源地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h20; data = 32'hC000_1000; //配置目的地址
master_agent.AXI4LITE_WRITE_BURST(base_addr + addr,0,data,resp);
addr = 32'h28; data = 32'd128*4; //配置传输长度,以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