上面三个图为交互过程的TVALID和TREADY的顺序不同时,数据流INFORMATION随始终ACLK的传输过程。需要注意的点如下:
首先关注我们的主机接口
// 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
注意看到关键握手信号即可。
// 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, once // the counter reaches C_M_START_COUNT count, // the state machine changes state to SEND_STREAM SEND_STREAM = 2'b10; // In this state the // stream data is output through M_AXIS_TDATA
再次是状态机的转移。分为原始状态,发送计数状态,发送状态。
// 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
注意到这个过程非常简单。进入计数状态后只要计数未结束就进入发送状态。
最后关注接口提到的flag信号和发送的数据信号即可。
flag信号:
//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);
数据信号:
//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; end end
即发送数据为我们的read_pointer指针依次往后计数到last为止。
2. 从设备关键源码分析
依旧先关注接口信号
// 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
注意到TVALID和TREADY的方向问题。
从设备的状态机定义如下:
// 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
其转移关系为:当TVALID拉高时,即可往FIFO中写入数据。
// 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
最后当FIFO收到主设备发送的数据的数量时,表示写入完成。
// 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)); always@(posedge S_AXIS_ACLK) begin if(!S_AXIS_ARESETN) begin write_pointer <= 0; writes_done <= 1'b0; end else if (write_pointer <= NUMBER_OF_INPUT_WORDS-1) begin if (fifo_wren) begin // 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). writes_done <= 1'b1; end end end
注意到我们只需要进行复位和置位操作即可开启此次传输。
主要激励代码:
initial begin sys_clk_i = 0; sys_rst_n = 0; #40 sys_rst_n = 1; end
波形图如下,当复位之后,进行数据1到8的传输,到第八个数据时TLAST拉高一次:
到此,我们完成了对AXI-Stream源码的一个初步了解。想进一步了解学习参见ARM
官方协议资料。(直接复制全名称百度即可获得)