FIFO 本质是由 RAM 加上读写逻辑构成的先入先出的数据缓冲器。与 RAM 的区别是 FIFO 没有外部读写地址线,顺序写入顺序读出数据,其数据地址是由内部读写指针自增完成,因此 FIFO 在读写时不需要考虑读写冲突的问题。
根据 FIFO 工作的时钟域,可以分为同步 FIFO 和异步 FIFO,同步 FIFO 的读时钟和写时钟是同一个时钟,常用于两边数据位宽不同的临时缓冲,异步 FIFO 的读时钟和写时钟不一致,常用于数据信号跨时钟域处理。
时序图
同步 fifo
初始状态 empty
信号是高电平,此时 fifo 为空,若此时对 fifo 发起读操作,则读取到的数据无效。当 wr_en
拉高后,开始向 fifo 内部写入数据,fifo 中有数据后,empty
信号就会拉低。后面同时发起读写操作后,因为是同步 fifo,所以标志位不会发生变化。
只写不读时,fifo 中存在两个及以上的数据,此时 almost empty
也会拉低。当 fifo 处于写满状态时,当 fifo 只能接受一次只写不读操作时,almost full
将会拉高,最后,在没有进行读操作的情况下,再进行了一次写操作,full
信号就会被拉高,说明此时的 FIFO 已经写满了,在发出读请求之前将无法再写入任何数据,如果此时再写入数据,数据就会丢失。
AXIS FIFO
时序图如下:
写入数据时,s_axis_tvalid
为高电平,同时 full
为低电平,取反后为 s_axis_tready
为高电平,此时才能写入数据。
读数据时同理,只有 valid
和 ready
信号同时拉高时才能读出数据。
m_axis_tvalid
对应 fifo
的 wr_en
信号,m_axis_tready
对应 fifo
的 full
信号取反,s_axis_tvalid
对应 fifo
的 empty
信号取反,s_axis_tready
对应 fifo
的 rd_en
。
AXIS fifo
Axis fifo 的 IP 核界面如下:
本次是学习 FIFO 的异步读写,因此将 independent clock
选为‘是’,并且不使能 packet 模式。Bd 框图如下:
其中 clk_wiz
的输出有两个,端口 1 的时钟速率为
100
M
H
z
100MHz
100MHz,端口 2 的时钟速率为
50
M
H
z
50MHz
50MHz,axis_data_source
和 axis_dest
的源代码如下:
module axis_data_source (
input s_axis_clk,
input s_axis_rstn,
input m_axis_tready,
output [7:0] m_axis_tdata,
output m_axis_tvalid
);
reg [7:0] cnt;
always @(posedge s_axis_clk or negedge s_axis_rstn) begin
if(!s_axis_rstn) begin
cnt<=0;
end
else begin
if(m_axis_tready) begin
if(cnt==255) begin
cnt<=0;
end
else begin
cnt<=cnt+1'b1;
end
end
end
end
assign m_axis_tdata=cnt;
assign m_axis_tvalid=1'b1;
endmodule
/*read fifo data*/
module axis_dest (
input s_axis_clk,
input s_axis_tvalid,
input [7:0] s_axis_tdata,
output s_axis_tready
);
assign s_axis_tready=1'b1;
endmodule
其中 data_source
以
100
M
H
z
100MHz
100MHz 的速率生成并输出
0
−
0
x
F
F
0-0xFF
0−0xFF,axis_dest
一直以
50
M
H
z
50MHz
50MHz 的速率读取数据。时序图如下:
可以看到开始时 FIFO 未被写满,此时写入和读出互不干扰,随着数据不断写入而不能被马上读出,在一段时间后 FIFO 的 full
信号拉高,对应 m_axis_tready
信号拉低,axis_data_source
不在生成新的数据,仿真图如下:
可以看到此时写入和读出的速率经过 valid 和 ready 信号的使能而同步。