AXI-Stream协议细读
简要说明
- 不同于AXI和AXI-lite协议,AXI-Stream协议不是基于地址的数据交互协议,如其名,数据流协议。
- 支持多个主从端之间通过同一个通路进行交互。
- 支持常规数据流,位置数据流,以及填充数据流的传输。
交互握手过程简述
上面三个图为交互过程的TVALID和TREADY的顺序不同时,数据流INFORMATION随始终ACLK的传输过程。需要注意的点如下:
- 注意TVALID是Master设备发出的信号,当TVALID拉高时,数据流必须保持不变。等待从设备的TREADY信号拉高,表示从设备已经可以接受数据流了。注意我们的数据是跟随TVALID来表示当前数据有效的。
源码分析
- 主设备关键源码分析
首先关注我们的主机接口
// 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
TestBench测试
注意到我们只需要进行复位和置位操作即可开启此次传输。
主要激励代码:
initial begin
sys_clk_i = 0;
sys_rst_n = 0;
#40 sys_rst_n = 1;
end
波形图如下,当复位之后,进行数据1到8的传输,到第八个数据时TLAST拉高一次:
写在最后
到此,我们完成了对AXI-Stream源码的一个初步了解。想进一步了解学习参见ARM
官方协议资料。(直接复制全名称百度即可获得)
参考资料
- IHI0051A_amba4_axi4_stream_v1_0_protocol_spec.pdf