Skip to content

AXI VIP DMA CDMA BRAM AXI4_IP综合验证(DMA,CDMA,StreamIP, BRAM大位宽)

minichao9901 edited this page Apr 11, 2024 · 4 revisions

配置

  • 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

image 说明:由于bram的位宽已经是128了,我们的task仍然是以32位对其进行读写。所以读出的数据,地址必须每隔128,数据才会变化一次。在128以内的4个子地址,读出的结果都是相同的。因为bram是一次读出128位的数据。

DMA执行Bram<-->AXI stream ip的拷贝波形(data witdh=128)

image dma:axi_mm2s的波形,这是读bram的接口。可见,当增加了max busrt size后,一次即可传输完成,不用分2次。传输的size=32,与代码的设置值一样,符合预期。

image dma:axis_mm2s的波形,这是往stream_fifo发数据的接口。也是一次busrt传输完成。

image stream data fifo:写fifo的波形和读fifo的波形。可见,axi stream的协议非常简单,只有3个控制信号tvalid/tready/tlast

CDMA执行Bram<-->Bram的拷贝波形(data witdh=128)

image bram:wdata/rdata部分。可以看到,发起了1次传输,每次长度=0x1f(对应32),这个与cdma的burst长度是一样的,因为位宽都是64。

CDMA执行Bram<-->AXI full ip的拷贝波形(data witdh=128)

image image axi_full_ip:写入burst_size=128,位宽是32。写入数据是正确的。

image bram:读的波形,一次读出128bits。注意到刚开始的时候读的快,每个cycle读一个128bits。后面读的满。怀疑是内置的fifo发生了满/空,产生了流控。

image bram_ctrl:axi4的波形,注意valid/ready,确实发生了流控。

image image axi_full_ip:读burst_size=128,位宽是32。读出数据是正确的。

image 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
Clone this wiki locally