最近在关注的问题是怎么样从ps端丢数据到ram,
然后用ip核进行处理后再输送到ram,ps端可以读取。
参考文献:【OpenHW参赛手记】AXI-Stream接口开发详细流程
首先按照作者的探索思路在 VIVADO 2013.4 下实践了一下AXI-Stream-FIFO
bd:
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:
address:
暂时只是把博主的ip核复制过来测试,文件列表如下
顶层文件:
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; }
测试结果如下:
下一步修改博主的逻辑到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
测试结果如下:
第二次则:
对于以下程序段的理解:
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
理解(图):
重点:经过测试发现,只有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代码段中声明的寄存器值可以一直保留。