AXI4-STREAM DATA FIFO学习
如图是该fifo的配置图,vivado版本2018.2.
General Options
Component Name
- 器件名字
FIFO depth
- FIFO的深度,可以在16到32768之间变化,具体情况视情况而定,但要是2的n次幂。
Enable packet mode
- 使能包模式:此项设定需要TLAST信号被使能。FIFO的操作在包模式下被修改为存储传送的数据,直到TLAST信号被响应。当TLAST信号被响应或者FIFO满了,存储的数据将被送至AXI4-Stream master interface.
Asynchronous Clocks
- 异步时钟:启用后S_AXIS_ACLK和M_AXIS_ACLK将会是异步时钟。
Synchronization Stages across Cross Clock Domain Logic
- 当启用异步时钟后,才会有该选项,其作用相当于跨时钟域时的打拍操作。一般默认即可。
ACLKEN Conversion Mode
-
此选项用来选择ACLKEN信号的转换模式。
-
None 没有和这个IP相关的ACLKEN 信号相关
-
S AXIS Only 有一个与S_AXIS_ACLKEN 相关联的 S_AXIS_ACLK信号,但没有M_AXIS_ACLKEN信号
-
M AXIS Only 有一个与M_AXIS_ACLKEN 相关联的 M_AXIS_ACLK信号,但没有S_AXIS_ACLKEN 信号
-
S AXIS & M AXIS 两个时钟都有与它们相关的ACLKEN信号。
Signal Properties
信号特性:可以看到,软件可以自动计算,当然我们也可以手动修改。
TDATA width (bytes)
- 参数指定axi4流上TData信号的宽度(以字节为单位接口。此参数是一个整数,可以从0到512不等。设置为0以忽略TDATA信号。如果省略了tdata信号,则tkeep和tstb信号也会省略。如图设置为4则可以看到位宽为32bit。
Enable TSTRB
- 是否使能TSTRB信号,只有当TData width(bytes)参数大于0时,才能启用此选项。
Enable TKEEP
- 是否使能TKEEP信号,只有当TData width(bytes)参数大于0时,才能启用此选项。
Enable TLAST
- 是否使能TKEEP信号,只有当TData width(bytes)参数大于0时,才能启用此选项。
TID width (bits)
- 用来指定TID信号的位宽,0为忽略,1~32为相应的位宽。
TDEST width (bits)
- 用来指定TDEST 信号的位宽,0为忽略,1~32为相应的位宽。
TUSER Width (bits)
- 用来指定TUSER 信号的位宽,0为忽略,1~32为相应的位宽。
关于这些信号的具体含义以及时序关系,可以通过仿真观察。
仿真
起始信号
初始化,复位以后,等待S_AXIS_tready信号的拉高,然后等待一个写周期,S_AXIS_tvalid拉高,这个时候,数据便开始写入FIFO。
在写入的时候给了两次S_AXIS_tlast信号,然后观察读出端的情况。
然后我们可以看到,S_AXIS_tlast被传递到读取端,这个时候将M_AXIS_tready拉低,我们可以看到,读取被禁止,同时继续写入数据,观察数据写满的情况。然后过一段时间后再将M_AXIS_tready拉高,可以看到,S_AXIS_tlast再次被传递。
从下图可以看出,当FIFO写满以后,S_AXIS_tready会被拉低,这个时候数据将不能写入,当M_AXIS_tready被拉高,读取段开始读取数据,这时FIFO非满,S_AXIS_tready又被拉高。
同时,我们将S_AXIS_tvalid拉低,可以看到,当数据读完以后,M_AXIS_tvalid被拉高。
通过仿真可以看出只有当 S_AXIS_tvalid和S_AXIS_tready同时为高时,数据才能写入,而S_AXIS_tready表示FIFO非满,S_AXIS_tvalid由用户控制。S_AXIS_tlast表示写入的最后一个数据,读取端同理,需要注意的是,S_AXIS_tkeep需要保持高电平。
读取端的控制信号同理。
参考资料:https://www.xilinx.com/support/documentation/ip_documentation/axis_interconnect/v1_1/pg035_axis_interconnect.pdf
以下是仿真代码
`timescale 1 us / 1 ps
module data_fifo_wrapper
(M_AXIS_tdata,
M_AXIS_tkeep,
M_AXIS_tlast,
M_AXIS_tvalid,
S_AXIS_tready,
axis_data_count,
axis_rd_data_count,
axis_wr_data_count
);
output [15:0]M_AXIS_tdata;
output [1:0]M_AXIS_tkeep;
output M_AXIS_tlast;
reg M_AXIS_tready;
output M_AXIS_tvalid;
output S_AXIS_tready;
output [31:0]axis_data_count;
output [31:0]axis_rd_data_count;
output [31:0]axis_wr_data_count;
wire [15:0]M_AXIS_tdata;
wire [1:0]M_AXIS_tkeep;
wire M_AXIS_tlast;
wire M_AXIS_tvalid;
reg [15:0]S_AXIS_tdata;
reg [1:0]S_AXIS_tkeep;
reg S_AXIS_tlast;
wire S_AXIS_tready;
reg S_AXIS_tvalid;
wire [31:0]axis_data_count;
wire [31:0]axis_rd_data_count;
wire [31:0]axis_wr_data_count;
reg m_axis_aclk;
reg m_axis_aresetn;
wire s_axis_aclk;
reg s_axis_aresetn;
initial begin
m_axis_aclk = 0;
M_AXIS_tready = 0;
m_axis_aresetn = 1;
s_axis_aresetn = 1;
S_AXIS_tdata = 0;
S_AXIS_tlast = 0;
S_AXIS_tvalid = 0;
S_AXIS_tkeep = 0;
end
always #5 m_axis_aclk = ~m_axis_aclk;
assign #2.5 s_axis_aclk = m_axis_aclk;//异步时钟
integer i;
initial begin
#100;
m_axis_aresetn = 0;
s_axis_aresetn = 0;
#100;
s_axis_aresetn = 1;
m_axis_aresetn = 1;
@(posedge S_AXIS_tready);//等待FIFO准备好
@(posedge s_axis_aclk);//对齐时钟
S_AXIS_tvalid = 1;//写有效
S_AXIS_tkeep = 2'b11;
for(i=0;i<512;i=i+1)//写512个数据
begin
@(posedge s_axis_aclk)
S_AXIS_tdata = S_AXIS_tdata + 1;
end
@(posedge s_axis_aclk)
S_AXIS_tlast = 1;//写最后一个数据
S_AXIS_tdata = S_AXIS_tdata + 1;
@(posedge s_axis_aclk)
S_AXIS_tlast = 0;
for(i=0;i<16;i=i+1)
begin
@(posedge s_axis_aclk)
S_AXIS_tdata = S_AXIS_tdata + 1;
end
@(posedge s_axis_aclk)
S_AXIS_tlast = 1;
@(posedge s_axis_aclk)
S_AXIS_tlast = 0;
#200;
@(posedge m_axis_aclk)
M_AXIS_tready = 1;//读数据
# (10*520);
M_AXIS_tready = 0;
for(i=0;i<600;i=i+1)
begin
@(posedge s_axis_aclk)
S_AXIS_tdata = S_AXIS_tdata + 1;
end
M_AXIS_tready = 1;
S_AXIS_tvalid = 0;
# (10*1024);
end
data_fifo data_fifo_i
(.M_AXIS_tdata(M_AXIS_tdata),
.M_AXIS_tkeep(M_AXIS_tkeep),
.M_AXIS_tlast(M_AXIS_tlast),
.M_AXIS_tready(M_AXIS_tready),
.M_AXIS_tvalid(M_AXIS_tvalid),
.S_AXIS_tdata(S_AXIS_tdata),
.S_AXIS_tkeep(S_AXIS_tkeep),
.S_AXIS_tlast(S_AXIS_tlast),
.S_AXIS_tready(S_AXIS_tready),
.S_AXIS_tvalid(S_AXIS_tvalid),
.axis_data_count(axis_data_count),
.axis_rd_data_count(axis_rd_data_count),
.axis_wr_data_count(axis_wr_data_count),
.m_axis_aclk(m_axis_aclk),
.m_axis_aresetn_0(m_axis_aresetn),
.s_axis_aclk(s_axis_aclk),
.s_axis_aresetn(s_axis_aresetn));
endmodule