Learn ZYNC (6)

最近在关注的问题是怎么样从ps端丢数据到ram,

然后用ip核进行处理后再输送到ram,ps端可以读取。

参考文献:【OpenHW参赛手记】AXI-Stream接口开发详细流程

首先按照作者的探索思路在 VIVADO 2013.4 下实践了一下AXI-Stream-FIFO

bd:

image

standalone test:

#include "xparameters.h"
#include "platform.h"
#include "xllfifo.h"   //包含AXI-FIFO-Stream控制接口头文件
#define r1 t1           //收发都是一个模块完成的,所以。。。
XLlFifo t1;                 //AXI-FIFO Stream控制模块
int sendram[8] = {1,2,3,4,5,6,7,8};   //发送缓冲区
int recvram[8] = {0,0,0,0,0,0,0,0};    //接收缓冲区



#define AXI_FIFO_BASE 0x7AA00000    //AXI-FIFO模块内存映射地址

//下面都是寄存器偏移量(按字计,不是字节,因为这里使用unsigned int指针)
#define ISR 0
#define IER 1
#define TDFR 2
#define TDFV 3
#define TDFD 4
#define TLF 5
#define RDFR 6
#define RDFO 7
#define RDFD 8
#define RLF 9
#define LLR 10

//用于调试,打印关键寄存器的值
void debug_register(unsigned int * p)
{
 printf("ISR = 0x%x
",*(p+ISR));
 if(*(p+ISR))
 {
  unsigned int t = *(p+ISR);
  *(p+ISR)=t&0xffffffff;
 }
 printf("ISR = 0x%x
",*(p+ISR));
 printf("IER = 0x%x
",*(p+IER));
 printf("TDFR = 0x%x
",*(p+TDFR));
 printf("TDFV = 0x%x
",*(p+TDFV));
 printf("TDFD = 0x%x
",*(p+TDFD));
 printf("TLF = 0x%x
",*(p+TLF));
 printf("RDFR = 0x%x
",*(p+RDFR));
 printf("RDFO = 0x%x
",*(p+RDFO));
// printf("RDFD = 0x%x
",*(p+RDFD));
// printf("RLF = 0x%x
",*(p+RLF));   //千万别轻易读这个,会复位的!
 printf("LLR = 0x%x
",*(p+LLR));
}
int main()
{

 int status=0;

 int rxlen;   //接收字节数
    init_platform();

    printf("Hello World

");

    debug_register((unsigned int *)AXI_FIFO_BASE);
    XLlFifo_Initialize(&t1,AXI_FIFO_BASE);//初始化AXI-FIFO模块
 //   XLlFifo_Initialize(&r1,0x74200000);//由于收发一体,故只需初始化一次
    XLlFifo_Write(&t1,sendram,8*4);//写发送缓冲区的内容到发送FIFO
    XLlFifo_TxSetLen(&r1,8*4);//启动发送过程

    print("Transmit begin!

");
//    debug_register((unsigned int *)AXI_FIFO_BASE);
    if(XLlFifo_RxOccupancy(&r1))   //如果接收FIFO中有内容
    {
     rxlen=XLlFifo_RxGetLen(&r1);//先获取其长度
     printf("Rcv Length:%d
",rxlen);
     XLlFifo_Read(&r1, recvram,rxlen);//读取接收内容
     int sum=0,i;
     for(i = 0;i<8;i++)
     {
      if(recvram[i]!=sendram[i])//如果接收不等于发送
      {
       printf("Error in index %d
",i);//那么就报错,并报告接收内容
       sum++;//错误计数
      }
     }
     if(sum==0)
     {
      printf("Success!
");//无错,则成功
     }
    }
    print("Transmit done!

");

    cleanup_platform();

    return 0;
}

然后把自己的ip核连接到axi-dma上去,实现STREAM到ps端的数据传输:

bd:

image

address:

image

暂时只是把博主的ip核复制过来测试,文件列表如下

image

顶层文件:

	module my_stream_ip_v1_0 #
	(
		// Users to add parameters here

		// User parameters ends
		// Do not modify the parameters beyond this line


		// Parameters of Axi Slave Bus Interface S01_AXIS
		parameter integer C_S01_AXIS_TDATA_WIDTH	= 32,

		// Parameters of Axi Master Bus Interface M00_AXIS
		parameter integer C_M00_AXIS_TDATA_WIDTH	= 32,
		parameter integer C_M00_AXIS_START_COUNT	= 32
	)
	(
		// Users to add ports here

		// User ports ends
		// Do not modify the ports beyond this line


		// Ports of Axi Slave Bus Interface S01_AXIS
		input wire  s01_axis_aclk,
		input wire  s01_axis_aresetn,
		output wire  s01_axis_tready,
		input wire [C_S01_AXIS_TDATA_WIDTH-1 : 0] s01_axis_tdata,
		input wire [(C_S01_AXIS_TDATA_WIDTH/8)-1 : 0] s01_axis_tstrb,
		input wire  s01_axis_tlast,
		input wire  s01_axis_tvalid,

		// Ports of Axi Master Bus Interface M00_AXIS
		input wire  m00_axis_aclk,
		input wire  m00_axis_aresetn,
		output wire  m00_axis_tvalid,
		output wire [C_M00_AXIS_TDATA_WIDTH-1 : 0] m00_axis_tdata,
		output wire [(C_M00_AXIS_TDATA_WIDTH/8)-1 : 0] m00_axis_tstrb,
		output wire  m00_axis_tlast,
		input wire  m00_axis_tready
	);
	
		my_stream_ip my_stream_ip_v1_0_S01_AXIS_inst (
    		.ACLK(s01_axis_aclk),
    		.ARESETN(s01_axis_aresetn),
    		.S_AXIS_TREADY(s01_axis_tready),
    		.S_AXIS_TDATA(s01_axis_tdata),
    		.S_AXIS_TLAST(s01_axis_tlast),
    		.S_AXIS_TVALID(s01_axis_tvalid),
    		.M_AXIS_TVALID(m00_axis_tvalid),
            .M_AXIS_TDATA(m00_axis_tdata),
            .M_AXIS_TLAST(m00_axis_tlast),
            .M_AXIS_TREADY(m00_axis_tready)
    	);	
// Instantiation of Axi Bus Interface S01_AXIS
//	my_stream_ip_v1_0_S01_AXIS # ( 
//		.C_S_AXIS_TDATA_WIDTH(C_S01_AXIS_TDATA_WIDTH)
//	) my_stream_ip_v1_0_S01_AXIS_inst (
//		.S_AXIS_ACLK(s01_axis_aclk),
//		.S_AXIS_ARESETN(s01_axis_aresetn),
//		.S_AXIS_TREADY(s01_axis_tready),
//		.S_AXIS_TDATA(s01_axis_tdata),
//		.S_AXIS_TSTRB(s01_axis_tstrb),
//		.S_AXIS_TLAST(s01_axis_tlast),
//		.S_AXIS_TVALID(s01_axis_tvalid)
//	);

// Instantiation of Axi Bus Interface M00_AXIS
//	my_stream_ip_v1_0_M00_AXIS # ( 
//		.C_M_AXIS_TDATA_WIDTH(C_M00_AXIS_TDATA_WIDTH),
//		.C_M_START_COUNT(C_M00_AXIS_START_COUNT)
//	) my_stream_ip_v1_0_M00_AXIS_inst (
//		.M_AXIS_ACLK(m00_axis_aclk),
//		.M_AXIS_ARESETN(m00_axis_aresetn),
//		.M_AXIS_TVALID(m00_axis_tvalid),
//		.M_AXIS_TDATA(m00_axis_tdata),
//		.M_AXIS_TSTRB(m00_axis_tstrb),
//		.M_AXIS_TLAST(m00_axis_tlast),
//		.M_AXIS_TREADY(m00_axis_tready)
//	);

	// Add user logic here

	// User logic ends

	endmodule

ip核单个文件:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 06/17/2014 04:46:15 PM
// Design Name: 
// Module Name: stream_ip
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module my_stream_ip  
 (  
  ACLK,  
  ARESETN,  
  S_AXIS_TREADY,  
  S_AXIS_TDATA,  
  S_AXIS_TLAST,  
  S_AXIS_TVALID,  
  M_AXIS_TVALID,  
  M_AXIS_TDATA,  
  M_AXIS_TLAST,  
  M_AXIS_TREADY,  

 );  
  
input                                    ACLK;  
input                                    ARESETN;  
output                                   S_AXIS_TREADY;  
input      [31 :0]                      S_AXIS_TDATA;  
input                                    S_AXIS_TLAST;  
input                                    S_AXIS_TVALID;  
output                                   M_AXIS_TVALID;  
output     [31 :0]                      M_AXIS_TDATA;  
output                                   M_AXIS_TLAST;  
input                                    M_AXIS_TREADY;  
 
  
   localparam NUMBER_OF_INPUT_WORDS  = 8;  
  
   localparam NUMBER_OF_OUTPUT_WORDS = 8;  
  
   localparam Idle  =3'b100;  
   localparam Read_Inputs = 3'b010;  
   localparam Write_Outputs  = 3'b001;  
  
   reg [2:0] state;  
  
   reg [31:0] sum;  
  
   reg [NUMBER_OF_INPUT_WORDS -1:0] nr_of_reads;  
   reg [NUMBER_OF_OUTPUT_WORDS - 1:0] nr_of_writes;  
  
   assign S_AXIS_TREADY  =(state == Read_Inputs);  
   assign M_AXIS_TVALID = (state == Write_Outputs);  
  
   assign M_AXIS_TDATA = sum;  
   assign M_AXIS_TLAST = (nr_of_writes == 1);  

   always @(posedge ACLK)  
   begin  // process The_SW_accelerator  
      if(!ARESETN)              // Synchronous reset (active low)  
        begin  
          state        <= Idle;  
           nr_of_reads <= 0;  
           nr_of_writes <=0;  
          sum          <= 0;  
        end  
      else  
        case (state)  
          Idle:  
            if (S_AXIS_TVALID== 1)  
            begin  
             state       <= Read_Inputs;  
             nr_of_reads <= NUMBER_OF_INPUT_WORDS - 1;  
             sum         <= 0;  
            end  
  
         Read_Inputs:  
            if(S_AXIS_TVALID == 1)  
            begin  
             sum         <= sum + S_AXIS_TDATA;  
             if (nr_of_reads == 0)  
               begin  
                 state        <= Write_Outputs;  
                 nr_of_writes <= NUMBER_OF_OUTPUT_WORDS - 1;  
               end  
             else  
               nr_of_reads <= nr_of_reads - 1;  
            end  
  
         Write_Outputs:  
            if(M_AXIS_TREADY == 1)  
            begin  
             if (nr_of_writes == 0)  
                state <= Idle;  
              else  
                nr_of_writes <= nr_of_writes - 1;  
            end  
        endcase  
   end  
  
endmodule  

完成,generate bit stream

sdk测试也是用的博主的测试文件:

    #include <stdio.h>
    #include <stdlib.h>
    #include "platform.h"
    #include "xil_cache.h"          //必须包含该头文件,实现cache操作

    #define sendram ((int *)0x10000000)          //发送缓冲区
    #define recvram ((int *)0x10001000)          //接收缓冲区
    #define sizeofbuffer 32

    void print(char *str);
    #define WITH_SG 0
    #define AXI_DMA_BASE 0x40400000

    #define MM2S_DMACR 0
    #define MM2S_DMASR 1
    #if WITH_SG
    #define MM2S_CURDESC 2
    #define MM2S_TAILDESC 4
    #else
    #define MM2S_SA 6
    #define MM2S_LENGTH 10
    #endif
    #define S2MM_DMACR 12
    #define S2MM_DMASR 13
    #if WITH_SG
    #define S2MM_CURDESC14
    #define S2MM_TAILDESC16
    #else
    #define S2MM_DA 18
    #define S2MM_LENGTH 22
    #endif

    void debug_axi_dma_register(unsigned int *p)
    {
     printf("MM2S_DMACR = 0x%x
",*(p+MM2S_DMACR));
     printf("MM2S_DMASR = 0x%x
",*(p+MM2S_DMASR));
    #if WITH_SG
     printf("MM2S_CURDESC = 0x%x
",*(p+MM2S_CURDESC));
     printf("MM2S_TAILDESC = 0x%x
",*(p+MM2S_TAILDESC));
    #else
     printf("MM2S_SA = 0x%x
",*(p+MM2S_SA));
     printf("MM2S_LENGTH = 0x%x
",*(p+MM2S_LENGTH));
    #endif
     printf("S2MM_DMACR =0x%x
",*(p+S2MM_DMACR));
     printf("S2MM_DMACSR =0x%x
",*(p+S2MM_DMASR));
    #if WITH_SG
     printf("S2MM_CURDESC =0x%x
",*(p+S2MM_CURDESC));
     printf("S2MM_TAILDESC= 0x%x
",*(p+S2MM_TAILDESC));
    #else
     printf("S2MM_DA =0x%x
",*(p+S2MM_DA));
     printf("S2MM_LENGTH =0x%x
",*(p+S2MM_LENGTH));
    #endif
    }
    void init_axi_dma_simple(unsigned int * p)
    {
     *(p+MM2S_DMACR) = 0x04;  //reset send axi dma
     while(*(p+MM2S_DMACR)&0x04);
     *(p+S2MM_DMACR) =0x04;  //reset send axi dma
     while(*(p+S2MM_DMACR)&0x04);
     *(p+MM2S_DMACR)=1;
     while((*(p+MM2S_DMASR)&0x01));
     *(p+S2MM_DMACR)=1;
     while((*(p+S2MM_DMASR)&0x01));
     *(p+MM2S_SA) = (unsigned int )sendram;
     *(p+S2MM_DA) =(unsigned int )recvram;
     Xil_DCacheFlushRange((u32)sendram,sizeofbuffer); //将cache内容同步到DDR2
     *(p+S2MM_LENGTH) =sizeofbuffer;//sizeof(recvram);
     *(p+MM2S_LENGTH) = sizeofbuffer;//sizeof(sendram);
     while(!(*(p+MM2S_DMASR)&0x1000)); //wait for send ok

    }
    void init_sendbuffer()
    {
     int i;
     for(i=0;i< sizeofbuffer/4;i++)
     {
      sendram[i]=i*2;
     }
    }
    void show_recvbuffer()
    {
     int i;
     printf("Recv contents are:
");
     for(i=0;i< sizeofbuffer/4;i++)
     {
      printf("%d	",recvram[i]);
     }
     printf("
");
    }
    void show_sendbuffer()
    {
     int i;
     printf("Send contents are:
");
     for(i=0;i< sizeofbuffer/4;i++)
     {
      printf("%d	",sendram[i]);
     }
     printf("
");
    }
    int main()
    {
     unsigned int status=0;

     int rxlen;
        init_platform();
        init_sendbuffer();

    init_axi_dma_simple((unsigned int *)AXI_DMA_BASE);
        printf("Hello World

Please input data:");
        while(1)
        {
         scanf("%x",&status);
         printf("Got 0x%x
",status);
         debug_axi_dma_register((unsigned int *)AXI_DMA_BASE);
         if(status==0)
         {
          break;
         }
        }
        show_sendbuffer();

    Xil_DCacheInvalidateRange((u32)recvram,sizeofbuffer);      //将DDR2内容同步到cache

        show_recvbuffer();
        cleanup_platform();

    return 0;
    }

测试结果如下:

image

下一步修改博主的逻辑到vivado自动生成的两个端口的verilog代码中。。。

ip核顶层文件my_stream_ip_v1_0.v

	module my_stream_ip_v1_0 #
	(
		// Users to add parameters here

		// User parameters ends
		// Do not modify the parameters beyond this line


		// Parameters of Axi Slave Bus Interface S00_AXIS
		parameter integer C_S00_AXIS_TDATA_WIDTH	= 32,

		// Parameters of Axi Master Bus Interface M00_AXIS
		parameter integer C_M00_AXIS_TDATA_WIDTH	= 32,
		parameter integer C_M00_AXIS_START_COUNT	= 32
	)
	(
		// Users to add ports here

		// User ports ends
		// Do not modify the ports beyond this line


		// Ports of Axi Slave Bus Interface S00_AXIS
		input wire  s00_axis_aclk,
		input wire  s00_axis_aresetn,
		output wire  s00_axis_tready,
		input wire [C_S00_AXIS_TDATA_WIDTH-1 : 0] s00_axis_tdata,
		input wire [(C_S00_AXIS_TDATA_WIDTH/8)-1 : 0] s00_axis_tstrb,
		input wire  s00_axis_tlast,
		input wire  s00_axis_tvalid,

		// Ports of Axi Master Bus Interface M00_AXIS
		input wire  m00_axis_aclk,
		input wire  m00_axis_aresetn,
		output wire  m00_axis_tvalid,
		output wire [C_M00_AXIS_TDATA_WIDTH-1 : 0] m00_axis_tdata,
		output wire [(C_M00_AXIS_TDATA_WIDTH/8)-1 : 0] m00_axis_tstrb,
		output wire  m00_axis_tlast,
		input wire  m00_axis_tready
	);
	
	wire [31 : 0] fifo_data;
	
// Instantiation of Axi Bus Interface S00_AXIS
	my_stream_ip_v1_0_S00_AXIS # ( 
		.C_S_AXIS_TDATA_WIDTH(C_S00_AXIS_TDATA_WIDTH)
	) my_stream_ip_v1_0_S00_AXIS_inst (
		.S_AXIS_ACLK(s00_axis_aclk),
		.S_AXIS_ARESETN(s00_axis_aresetn),
		.S_AXIS_TREADY(s00_axis_tready),
		.S_AXIS_TDATA(s00_axis_tdata),
		.S_AXIS_TSTRB(s00_axis_tstrb),
		.S_AXIS_TLAST(s00_axis_tlast),
		.S_AXIS_TVALID(s00_axis_tvalid),
		.fifo(fifo_data)
	);

// Instantiation of Axi Bus Interface M00_AXIS
	my_stream_ip_v1_0_M00_AXIS # ( 
		.C_M_AXIS_TDATA_WIDTH(C_M00_AXIS_TDATA_WIDTH),
		.C_M_START_COUNT(C_M00_AXIS_START_COUNT)
	) my_stream_ip_v1_0_M00_AXIS_inst (
		.M_AXIS_ACLK(m00_axis_aclk),
		.M_AXIS_ARESETN(m00_axis_aresetn),
		.M_AXIS_TVALID(m00_axis_tvalid),
		.M_AXIS_TDATA(m00_axis_tdata),
		.M_AXIS_TSTRB(m00_axis_tstrb),
		.M_AXIS_TLAST(m00_axis_tlast),
		.M_AXIS_TREADY(m00_axis_tready),
		.fifo(fifo_data)
	);

	// Add user logic here

	// User logic ends

	endmodule

ip核axi stream master口对应verilog文件my_stream_ip_v1_0_M00_AXIS.v

	module my_stream_ip_v1_0_M00_AXIS #
	(
		// Users to add parameters here

		// User parameters ends
		// Do not modify the parameters beyond this line

		// Width of S_AXIS address bus. The slave accepts the read and write addresses of width C_M_AXIS_TDATA_WIDTH.
		parameter integer C_M_AXIS_TDATA_WIDTH	= 32,
		// Start count is the numeber of clock cycles the master will wait before initiating/issuing any transaction.
		parameter integer C_M_START_COUNT	= 32
	)
	(
		// Users to add ports here

		// User ports ends
		// Do not modify the ports beyond this line

		// Global ports
		input wire  M_AXIS_ACLK,
		// 
		input wire  M_AXIS_ARESETN,
		// Master Stream Ports. TVALID indicates that the master is driving a valid transfer, A transfer takes place when both TVALID and TREADY are asserted. 
		output wire  M_AXIS_TVALID,
		// TDATA is the primary payload that is used to provide the data that is passing across the interface from the master.
		output wire [C_M_AXIS_TDATA_WIDTH-1 : 0] M_AXIS_TDATA,
		// TSTRB is the byte qualifier that indicates whether the content of the associated byte of TDATA is processed as a data byte or a position byte.
		output wire [(C_M_AXIS_TDATA_WIDTH/8)-1 : 0] M_AXIS_TSTRB,
		// TLAST indicates the boundary of a packet.
		output wire  M_AXIS_TLAST,
		// TREADY indicates that the slave can accept a transfer in the current cycle.
		input wire  M_AXIS_TREADY,
		
		wire [31:0] fifo
	);
	//Total number of output data.
	// Total number of output data                                                 
	localparam NUMBER_OF_OUTPUT_WORDS = 8;                                               
	                                                                                     
	// function called clogb2 that returns an integer which has the                      
	// value of the ceiling of the log base 2.                                           
	function integer clogb2 (input integer bit_depth);                                   
	  begin                                                                              
	    for(clogb2=0; bit_depth>0; clogb2=clogb2+1)                                      
	      bit_depth = bit_depth >> 1;                                                    
	  end                                                                                
	endfunction                                                                          
	                                                                                     
	// WAIT_COUNT_BITS is the width of the wait counter.                                 
	localparam integer WAIT_COUNT_BITS = clogb2(C_M_START_COUNT-1);                      
	                                                                                     
	// bit_num gives the minimum number of bits needed to address 'depth' size of FIFO.  
	localparam bit_num  = clogb2(NUMBER_OF_OUTPUT_WORDS);                                
	                                                                                     
	// Define the states of state machine                                                
	// The control state machine oversees the writing of input streaming data to the FIFO,
	// and outputs the streaming data from the FIFO                                      
	parameter [1:0] IDLE = 2'b00,        // This is the initial/idle state               
	                                                                                     
	                INIT_COUNTER  = 2'b01, // This state initializes the counter, ones   
	                                // the counter reaches C_M_START_COUNT count,        
	                                // the state machine changes state to INIT_WRITE     
	                SEND_STREAM   = 2'b10; // In this state the                          
	                                     // stream data is output through M_AXIS_TDATA   
	// State variable                                                                    
	reg [1:0] mst_exec_state;                                                            
	// Example design FIFO read pointer                                                  
	reg [bit_num-1:0] read_pointer;                                                      

	// AXI Stream internal signals
	//wait counter. The master waits for the user defined number of clock cycles before initiating a transfer.
	reg [WAIT_COUNT_BITS-1 : 0] 	count;
	//streaming data valid
	wire  	axis_tvalid;
	//streaming data valid delayed by one clock cycle
	reg  	axis_tvalid_delay;
	//Last of the streaming data 
	wire  	axis_tlast;
	//Last of the streaming data delayed by one clock cycle
	reg  	axis_tlast_delay;
	//FIFO implementation signals
	reg [C_M_AXIS_TDATA_WIDTH-1 : 0] 	stream_data_out;
	wire  	tx_en;
	//The master has issued all the streaming data stored in FIFO
	reg  	tx_done;


	// I/O Connections assignments

	assign M_AXIS_TVALID	= axis_tvalid_delay;
	assign M_AXIS_TDATA	= stream_data_out;
	assign M_AXIS_TLAST	= axis_tlast_delay;
	assign M_AXIS_TSTRB	= {(C_M_AXIS_TDATA_WIDTH/8){1'b1}};


	// Control state machine implementation                             
	always @(posedge M_AXIS_ACLK)                                             
	begin                                                                     
	  if (!M_AXIS_ARESETN)                                                    
	  // Synchronous reset (active low)                                       
	    begin                                                                 
	      mst_exec_state <= IDLE;                                             
	      count    <= 0;                                                      
	    end                                                                   
	  else                                                                    
	    case (mst_exec_state)                                                 
	      IDLE:                                                               
	        // The slave starts accepting tdata when                          
	        // there tvalid is asserted to mark the                           
	        // presence of valid streaming data                               
	        if ( count == 0 )                                                 
	          begin                                                           
	            mst_exec_state  <= INIT_COUNTER;                              
	          end                                                             
	        else                                                              
	          begin                                                           
	            mst_exec_state  <= IDLE;                                      
	          end                                                             
	                                                                          
	      INIT_COUNTER:                                                       
	        // The slave starts accepting tdata when                          
	        // there tvalid is asserted to mark the                           
	        // presence of valid streaming data                               
	        if ( count == C_M_START_COUNT - 1 )                               
	          begin                                                           
	            mst_exec_state  <= SEND_STREAM;                               
	          end                                                             
	        else                                                              
	          begin                                                           
	            count <= count + 1;                                           
	            mst_exec_state  <= INIT_COUNTER;                              
	          end                                                             
	                                                                          
	      SEND_STREAM:                                                        
	        // The example design streaming master functionality starts       
	        // when the master drives output tdata from the FIFO and the slave
	        // has finished storing the S_AXIS_TDATA                          
	        if (tx_done)                                                      
	          begin                                                           
	            mst_exec_state <= IDLE;                                       
	          end                                                             
	        else                                                              
	          begin                                                           
	            mst_exec_state <= SEND_STREAM;                                
	          end                                                             
	    endcase                                                               
	end                                                                       


	//tvalid generation
	//axis_tvalid is asserted when the control state machine's state is SEND_STREAM and
	//number of output streaming data is less than the NUMBER_OF_OUTPUT_WORDS.
	assign axis_tvalid = ((mst_exec_state == SEND_STREAM) && (read_pointer < NUMBER_OF_OUTPUT_WORDS));
	                                                                                               
	// AXI tlast generation                                                                        
	// axis_tlast is asserted number of output streaming data is NUMBER_OF_OUTPUT_WORDS-1          
	// (0 to NUMBER_OF_OUTPUT_WORDS-1)                                                             
	assign axis_tlast = (read_pointer == NUMBER_OF_OUTPUT_WORDS-1);                                
	                                                                                               
	                                                                                               
	// Delay the axis_tvalid and axis_tlast signal by one clock cycle                              
	// to match the latency of M_AXIS_TDATA                                                        
	always @(posedge M_AXIS_ACLK)                                                                  
	begin                                                                                          
	  if (!M_AXIS_ARESETN)                                                                         
	    begin                                                                                      
	      axis_tvalid_delay <= 1'b0;                                                               
	      axis_tlast_delay <= 1'b0;                                                                
	    end                                                                                        
	  else                                                                                         
	    begin                                                                                      
	      axis_tvalid_delay <= axis_tvalid;                                                        
	      axis_tlast_delay <= axis_tlast;                                                          
	    end                                                                                        
	end                                                                                            


	//read_pointer pointer

	always@(posedge M_AXIS_ACLK)                                               
	begin                                                                            
	  if(!M_AXIS_ARESETN)                                                            
	    begin                                                                        
	      read_pointer <= 0;                                                         
	      tx_done <= 1'b0;                                                           
	    end                                                                          
	  else                                                                           
	    if (read_pointer <= NUMBER_OF_OUTPUT_WORDS-1)                                
	      begin                                                                      
	        if (tx_en)                                                               
	          // read pointer is incremented after every read from the FIFO          
	          // when FIFO read signal is enabled.                                   
	          begin                                                                  
	            read_pointer <= read_pointer + 1;                                    
	            tx_done <= 1'b0;                                                     
	          end                                                                    
	      end                                                                        
	    else if (read_pointer == NUMBER_OF_OUTPUT_WORDS)                             
	      begin                                                                      
	        // tx_done is asserted when NUMBER_OF_OUTPUT_WORDS numbers of streaming data
	        // has been out.                                                         
	        tx_done <= 1'b1;                                                         
	      end                                                                        
	end                                                                              


	//FIFO read enable generation 

	assign tx_en = M_AXIS_TREADY && axis_tvalid;   
	                                                     
	    // Streaming output data is read from FIFO       
	    always @( posedge M_AXIS_ACLK )                  
	    begin                                            
	      if(!M_AXIS_ARESETN)                            
	        begin                                        
	          stream_data_out <= 1;                      
	        end                                          
	      else if (tx_en)// && M_AXIS_TSTRB[byte_index]  
	        begin                                        
//	          stream_data_out <= read_pointer + 32'b1;   
              stream_data_out <= fifo;
	        end                                          
	    end                                              

	// Add user logic here

	// User logic ends

	endmodule

ip核axi stream slave口对应的verilog文件my_stream_ip_v1_0_S00_AXIS.v

	module my_stream_ip_v1_0_S00_AXIS #
	(
		// Users to add parameters here

		// User parameters ends
		// Do not modify the parameters beyond this line

		// AXI4Stream sink: Data Width
		parameter integer C_S_AXIS_TDATA_WIDTH	= 32
	)
	(
		// Users to add ports here

		// User ports ends
		// Do not modify the ports beyond this line

		// AXI4Stream sink: Clock
		input wire  S_AXIS_ACLK,
		// AXI4Stream sink: Reset
		input wire  S_AXIS_ARESETN,
		// Ready to accept data in
		output wire  S_AXIS_TREADY,
		// Data in
		input wire [C_S_AXIS_TDATA_WIDTH-1 : 0] S_AXIS_TDATA,
		// Byte qualifier
		input wire [(C_S_AXIS_TDATA_WIDTH/8)-1 : 0] S_AXIS_TSTRB,
		// Indicates boundary of last packet
		input wire  S_AXIS_TLAST,
		// Data is in valid
		input wire  S_AXIS_TVALID,
		
		wire [31:0] fifo
	);
	// function called clogb2 that returns an integer which has the 
	// value of the ceiling of the log base 2.
	function integer clogb2 (input integer bit_depth);
	  begin
	    for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
	      bit_depth = bit_depth >> 1;
	  end
	endfunction

	// Total number of input data.
	localparam NUMBER_OF_INPUT_WORDS  = 8;
	// bit_num gives the minimum number of bits needed to address 'NUMBER_OF_INPUT_WORDS' size of FIFO.
	localparam bit_num  = clogb2(NUMBER_OF_INPUT_WORDS-1);
	// Define the states of state machine
	// The control state machine oversees the writing of input streaming data to the FIFO,
	// and outputs the streaming data from the FIFO
	parameter [1:0] IDLE = 1'b0,        // This is the initial/idle state 

	                WRITE_FIFO  = 1'b1; // In this state FIFO is written with the
	                                    // input stream data S_AXIS_TDATA 
	wire  	axis_tready;
	// State variable
	reg mst_exec_state;  
	// FIFO implementation signals
	genvar byte_index;     
	// FIFO write enable
	wire fifo_wren;
	// FIFO full flag
	reg fifo_full_flag;
	// FIFO write pointer
	reg [bit_num-1:0] write_pointer;
	// sink has accepted all the streaming data and stored in FIFO
	  reg writes_done;
	// I/O Connections assignments
	//**********  my  code   ***************************************************
    reg [31:0] sum;

	assign S_AXIS_TREADY	= axis_tready;
	// Control state machine implementation
	always @(posedge S_AXIS_ACLK) 
	begin  
	  if (!S_AXIS_ARESETN) 
	  // Synchronous reset (active low)
	    begin
	      mst_exec_state <= IDLE;
	    end  
	  else
	    case (mst_exec_state)
	      IDLE: 
	        // The sink starts accepting tdata when 
	        // there tvalid is asserted to mark the
	        // presence of valid streaming data 
	          if (S_AXIS_TVALID)
	            begin
	              mst_exec_state <= WRITE_FIFO;
	            end
	          else
	            begin
	              mst_exec_state <= IDLE;
	            end
	      WRITE_FIFO: 
	        // When the sink has accepted all the streaming input data,
	        // the interface swiches functionality to a streaming master
	        if (writes_done)
	          begin
	            mst_exec_state <= IDLE;
	          end
	        else
	          begin
	            // The sink accepts and stores tdata 
	            // into FIFO
	            mst_exec_state <= WRITE_FIFO;
	          end

	    endcase
	end
	// AXI Streaming Sink 
	// 
	// The example design sink is always ready to accept the S_AXIS_TDATA  until
	// the FIFO is not filled with NUMBER_OF_INPUT_WORDS number of input words.
	assign axis_tready = ((mst_exec_state == WRITE_FIFO) && (write_pointer <= NUMBER_OF_INPUT_WORDS-1));
	//********************   MY CODE HERE ************************************
//	reg  [31 : 0] fifo_data;
//    assign fifo = fifo_data;
	always@(posedge S_AXIS_ACLK)
	begin
	  if(!S_AXIS_ARESETN)
	    begin
	      write_pointer <= 0;
	      writes_done <= 1'b0;
//	      fifo_data <= 32'b0;
	      //********************   MY CODE HERE ************************************
//          sum <= 0;
	    end  
	  else
	    if (write_pointer <= NUMBER_OF_INPUT_WORDS-1)
	      begin
	        if (fifo_wren)
	          begin
	          	//******************************************************************
//                sum <= sum + S_AXIS_TDATA;
//                fifo_data <= sum;
	            // write pointer is incremented after every write to the FIFO
	            // when FIFO write signal is enabled.
	            write_pointer <= write_pointer + 1;
	            writes_done <= 1'b0;
	          end
	          if ((write_pointer == NUMBER_OF_INPUT_WORDS-1)|| S_AXIS_TLAST)
	            begin
	              // reads_done is asserted when NUMBER_OF_INPUT_WORDS numbers of streaming data 
	              // has been written to the FIFO which is also marked by S_AXIS_TLAST(kept for optional usage).
//	              fifo_data <= sum;
	              writes_done <= 1'b1;
	            end
	      end  
	end

	// FIFO write enable generation
	assign fifo_wren = S_AXIS_TVALID && axis_tready;
	
	// FIFO Implementation
	generate 
	   //开启3个线程,线程编号0~3,byte_index
	  for(byte_index=0; byte_index<= (C_S_AXIS_TDATA_WIDTH/8-1); byte_index=byte_index+1)
	  begin:FIFO_GEN
        //reg [7:0] stream_data_fifo [0:7]数组;
	    reg  [(C_S_AXIS_TDATA_WIDTH/4)-1:0] stream_data_fifo [0 : NUMBER_OF_INPUT_WORDS-1];
	    	reg  [31 : 0] fifo_data;
            assign fifo = fifo_data;
	    // Streaming input data is stored in FIFO

	    always @( posedge S_AXIS_ACLK )
	    begin
	      if (fifo_wren)// && S_AXIS_TSTRB[byte_index])
	        begin
//	          stream_data_fifo[write_pointer] <= S_AXIS_TDATA[(byte_index*8+7) -: 8];
//对于stream_data_fifo[i][8]的赋值,由write_pointer作为游标(在S_AXIS_ACLK和fifo_wren时递增1->8),
//取对于每个stream_data_fifo[write_pointer][8 down to 0]的赋值,取S_AXIS_TDATA的[(b_i*8+7):(b_i*8)]
              stream_data_fifo[write_pointer] <= S_AXIS_TDATA[(byte_index*8+7) -: 8];
              fifo_data <= fifo_data + S_AXIS_TDATA;
	        end  
	    end  
	  end		
	endgenerate

	// Add user logic here

	// User logic ends

	endmodule

测试结果如下:

test1

第二次则:

test2

对于以下程序段的理解:

      generate 
	  for(byte_index=0; byte_index<= (C_S_AXIS_TDATA_WIDTH/8-1); byte_index=byte_index+1)
	  begin:FIFO_GEN
	    reg  [(C_S_AXIS_TDATA_WIDTH/4)-1:0] stream_data_fifo [0 : NUMBER_OF_INPUT_WORDS-1];

	    // Streaming input data is stored in FIFO
	    always @( posedge S_AXIS_ACLK )
	    begin
	      if (fifo_wren)// && S_AXIS_TSTRB[byte_index])
	        begin
              stream_data_fifo[write_pointer] <= S_AXIS_TDATA[(byte_index*8+7) -: 8];
	        end  
	    end  
	  end		
	endgenerate

理解(图):

IMG_20140618_113109

重点:经过测试发现,只有generate 代码块中声明的reg才会将S_AXIS_TDATA的数据存好,并且在接到Master口中读取的时候才能够被读出,而如果将计算sum和存储改到如下段落,在Master端只能读到0:

	reg  [31 : 0] fifo_data;
    assign fifo = fifo_data;
	always@(posedge S_AXIS_ACLK)
	begin
	  if(!S_AXIS_ARESETN)
	    begin
	      write_pointer <= 0;
	      writes_done <= 1'b0;
//	      fifo_data <= 32'b0;
	      //********************   MY CODE HERE ************************************
          sum <= 0;
	    end  
	  else
	    if (write_pointer <= NUMBER_OF_INPUT_WORDS-1)
	      begin
	        if (fifo_wren)
	          begin
	          	//******************************************************************
                sum <= sum + S_AXIS_TDATA;
                fifo_data <= sum;
	            // write pointer is incremented after every write to the FIFO
	            // when FIFO write signal is enabled.
	            write_pointer <= write_pointer + 1;
	            writes_done <= 1'b0;
	          end
	          if ((write_pointer == NUMBER_OF_INPUT_WORDS-1)|| S_AXIS_TLAST)
	            begin
	              // reads_done is asserted when NUMBER_OF_INPUT_WORDS numbers of streaming data 
	              // has been written to the FIFO which is also marked by S_AXIS_TLAST(kept for optional usage).
	              fifo_data <= sum;
	              writes_done <= 1'b1;
	            end
	      end  
	end

而且,在generate代码段中声明的寄存器值可以一直保留。

原文地址:https://www.cnblogs.com/shenerguang/p/3793215.html