AXI4‐Full外设,用VIP仿真,并且修改memory大小 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki

创建AXI-Full的IP

默认位宽32bits,默认最大容量只能选择1024bytes。后面我们手动修改网表,让容量变为4096bytes。

打开ip,修改位宽。一共4个地方需要修改。

image

这里从10修改为12

image

这里也要从10修改为12

image

这里从7修改为9

image

这里从255修改为1023

修改完了后,用VIP仿真

testbench修改的部分, 我们增加了2次写,2次读。注意读/写的地址。 burst每次最大只能256。

task automatic S_AXI_TEST;  
begin   
#1; 
   for(int i = 0; i < 256; i++) begin 
     mtestWDataF[i*32+:32] = i+32'h11223344; 
   end 
   $display("Sequential write transfers example similar to  AXI BFM WRITE_BURST method starts"); 
   mtestID = 0; 
   mtestADDR = 0; 
   mtestBurstLength = 255; 
   mtestDataSize = xil_axi_size_t'(xil_clog2(32/8)); 
   mtestBurstType = XIL_AXI_BURST_TYPE_INCR;  
   mtestLOCK = XIL_AXI_ALOCK_NOLOCK;  
   mtestCacheType = 0;  
   mtestProtectionType = 0;  
   mtestRegion = 0; 
   mtestQOS = 0; 
   result_slave = 1; 
   for(int i = 0; i < 255;i++) begin 
     mtestWUSER = 'h0; 
   end  
   mst_agent_0.AXI4_WRITE_BURST( 
       mtestID, 
       mtestADDR, 
       mtestBurstLength, 
       mtestDataSize, 
       mtestBurstType, 
       mtestLOCK, 
       mtestCacheType, 
       mtestProtectionType, 
       mtestRegion, 
       mtestQOS, 
       mtestAWUSER, 
       mtestWDataF, 
       mtestWUSER, 
       mtestBresp 
     );  
 
   mtestADDR = 256*4;   
   for(int i = 0; i < 256; i++) begin 
     mtestWDataF[i*32+:32] = i+32'h55667788; 
   end      
   mst_agent_0.AXI4_WRITE_BURST( 
       mtestID, 
       mtestADDR, 
       mtestBurstLength, 
       mtestDataSize, 
       mtestBurstType, 
       mtestLOCK, 
       mtestCacheType, 
       mtestProtectionType, 
       mtestRegion, 
       mtestQOS, 
       mtestAWUSER, 
       mtestWDataF, 
       mtestWUSER, 
       mtestBresp 
     );         
     $display("Sequential write transfers example similar to  AXI BFM WRITE_BURST method completes"); 
     $display("Sequential read transfers example similar to  AXI BFM READ_BURST method starts"); 
     mtestID = 0; 
     mtestADDR = 0; 
     mtestBurstLength = 255; 
     mtestDataSize = xil_axi_size_t'(xil_clog2(32/8)); 
     mtestBurstType = XIL_AXI_BURST_TYPE_INCR;  
     mtestLOCK = XIL_AXI_ALOCK_NOLOCK;  
     mtestCacheType = 0;  
     mtestProtectionType = 0;  
     mtestRegion = 0; 
     mtestQOS = 0; 
     mst_agent_0.AXI4_READ_BURST ( 
       mtestID, 
       mtestADDR, 
       mtestBurstLength, 
       mtestDataSize, 
       mtestBurstType, 
       mtestLOCK, 
       mtestCacheType, 
       mtestProtectionType, 
       mtestRegion, 
       mtestQOS, 
       mtestARUSER, 
       mtestRDataF, 
       mtestRresp, 
       mtestRUSER 
       ); 
     
     mtestADDR=256*4;  
     mst_agent_0.AXI4_READ_BURST ( 
       mtestID, 
       mtestADDR, 
       mtestBurstLength, 
       mtestDataSize, 
       mtestBurstType, 
       mtestLOCK, 
       mtestCacheType, 
       mtestProtectionType, 
       mtestRegion, 
       mtestQOS, 
       mtestARUSER, 
       mtestRDataF, 
       mtestRresp, 
       mtestRUSER 
       );        
     $display("Sequential read transfers example similar to  AXI BFM READ_BURST method completes"); 
     COMPARE_DATA(mtestWDataF,mtestRDataF); 
     $display("Sequential read transfers example similar to  AXI VIP READ_BURST method completes"); 
     $display("---------------------------------------------------------"); 
     $display("EXAMPLE TEST S00_AXI: PTGEN_TEST_FINISHED!"); 
     if ( result_slave ) begin                    
       $display("PTGEN_TEST: PASSED!");                  
     end    else begin                                       
       $display("PTGEN_TEST: FAILED!");                  
     end                                
     $display("---------------------------------------------------------"); 
  end 
endtask

波形

image

可以看到,ip里面它是把1024x32的地址空间拆分为4个1024x8的地址空间。每个1024x8的地址空间用一个reg [7:0] mem [0:1023] 实现。 因此: {mem3[i], mem2[i], mem1[i], mem0[i]}=wdata; rdata={mem3[i], mem2[i], mem1[i], mem0[i]}

从下面的图可以看到 image

image

这个是mem3的数据写入。第一次写入的全是11,第二次写入的全是55。

AXI4-Full如何实现对外设的集成? 本质来说,就是如何实现硬件对byte_ram的读和写。

image

硬件的写入(例如这里的标志寄存器),通过 BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[0][0]这种方式,可以直接指定到某个byte_ram的某个指定位。

image

xfer_start的产生(当写入某个地址的时候产生)。硬件对byte_ram的读取,也使用BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[1]这种方式指定读取,甚至还可以拼接。虽然没有axi-lite那种方便,但也是完全可以的。

为了方便验证,我们还做了一个从xfer_start-->xfer_rdy/xfer_final的行为模型。 完整的代码如下:

// implement Block RAM(s)
	generate 
	  for(i=0; i<= USER_NUM_MEM-1; i=i+1)
	    begin:BRAM_GEN
	      wire mem_rden;
	      wire mem_wren;
	
	      assign mem_wren = axi_wready && S_AXI_WVALID ;
	
	      assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
	     
	      for(mem_byte_index=0; mem_byte_index<= (C_S_AXI_DATA_WIDTH/8-1); mem_byte_index=mem_byte_index+1)
	      begin:BYTE_BRAM_GEN
	        wire [8-1:0] data_in ;
	        wire [8-1:0] data_out;
	        reg  [8-1:0] byte_ram [0 : 1023];
	        integer  j;
	     
	        //assigning 8 bit data
	        assign data_in  = S_AXI_WDATA[(mem_byte_index*8+7) -: 8];
	        assign data_out = byte_ram[mem_address];
	     
	        always @( posedge S_AXI_ACLK )
	        begin
	          if(xfer_final)
	             BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[0][0]<=1;
	          if(xfer_rdy)
	             BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[0][1]<=1;	           
	        
	          if (mem_wren && S_AXI_WSTRB[mem_byte_index])
	            begin
	              byte_ram[mem_address] <= data_in;
	            end   
	        end    
	      
	        always @( posedge S_AXI_ACLK )
	        begin
	          if (mem_rden)
	            begin
	              mem_data_out[i][(mem_byte_index*8+7) -: 8] <= data_out;
	            end   
	        end    
	               
	    end
	  end       
	endgenerate
	//Output register or memory read data	

	always @( mem_data_out, axi_rvalid)
	begin
	  if (axi_rvalid) 
	    begin
	      // Read address mux
	      axi_rdata <= mem_data_out[0];
	    end   
	  else
	    begin
	      axi_rdata <= 32'h00000000;
	    end       
	end    

	// Add user logic here
	reg xfer_final;
	reg xfer_rdy;
	wire xfer_start;
	wire [7:0] data1;
	wire [15:0] data2;
		
    assign xfer_start=axi_wready && S_AXI_WVALID && (mem_address==0);   
    
    assign data1=BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[1];	
    assign data2={BRAM_GEN[0].BYTE_BRAM_GEN[1].byte_ram[2], BRAM_GEN[0].BYTE_BRAM_GEN[0].byte_ram[2]};			

    initial begin
        xfer_final=0;
        xfer_rdy=1;
        
        while(1) begin
            wait(xfer_start==1);
            #1 xfer_rdy=0;
            repeat(100)
                @( posedge S_AXI_ACLK );
            #1 xfer_final=1;
            xfer_rdy=1;
            @( posedge S_AXI_ACLK )
                #1 xfer_final=0;
        end 
    end

	// User logic ends

image

可以看到xfer_start和xfer_rdy/xfer_final正确产生。

image

可以看到xfer_rdy/xfer_final可以正确设置byte_ram的对应位。

image

data1和data2可以正确读取到byte_ram的对应内容。

关于burst_size的设置

范围是0--255,表示传输1-256个

   mst_agent_0.AXI4_WRITE_BURST( 
       mtestID, 
       0 /*mtestADDR*/, 
       0 /*mtestBurstLength*/, 
       mtestDataSize, 
       mtestBurstType, 
       mtestLOCK, 
       mtestCacheType, 
       mtestProtectionType, 
       mtestRegion, 
       mtestQOS,
       mtestAWUSER, 
       32'habcdef/*mtestWDataF*/, 
       mtestWUSER, 
       mtestBresp 
     );   

image

设置为0,最终的结果,只写入一个机器字长。

   mst_agent_0.AXI4_WRITE_BURST( 
       mtestID, 
       0 /*mtestADDR*/, 
       1 /*mtestBurstLength*/, 
       mtestDataSize, 
       mtestBurstType, 
       mtestLOCK, 
       mtestCacheType, 
       mtestProtectionType, 
       mtestRegion, 
       mtestQOS,
       mtestAWUSER, 
       64'h12345678_89abcdef/*mtestWDataF*/, 
       mtestWUSER, 
       mtestBresp 
     );

image image

设置为1,最终的结果,只写入2个机器字长。