原理
FIFO: first in first out
FIFO分为 signal
单时钟常被用于片内数据的收发,而双时钟则常用在接收异步数据,因为收发速率不同,可能会产生亚稳态等一系列问题。
单时钟和双时钟FIFO结构如下:

wrreq: 写入使能信号
rdreq:读出使能信号
full: FIFO写满信号
almost_full: 可配置参数,在写入数据>X的时候电平拉高,表示FIFO快写满
empty: FIFO清空信号
almost_empty: 可配置参数,在写入数据<X的时候电平拉高,标志着FIFO中数据快要读取完
usedw: 表示FIFO中有多少个存储的有效信号。
Quartus ii实现
SCFIFO
点击TOOLS打开 IP Catalog 然后找到FIFO,然后对其进行以下配置,其余默认,构建一个能存储256个8位数据的FIFO。

生成相应的vhdl代码之后搭建testbench如下:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity fifo_tb is
end entity;
architecture beh of fifo_tb is
component fifo IS --- 生成的FIFO VHDL代码
PORT
(
clock : IN STD_LOGIC ;
data : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
rdreq : IN STD_LOGIC ;
sclr : IN STD_LOGIC ;
wrreq : IN STD_LOGIC ;
almost_empty : OUT STD_LOGIC ;
almost_full : OUT STD_LOGIC ;
empty : OUT STD_LOGIC ;
full : OUT STD_LOGIC ;
q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
usedw : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
);
END component;
------------------------signal declaration-------------------
signal clock : std_logic:='1';
signal data : std_logic_VECTOR (7 DOWNTO 0);
signal rdreq : std_logic;
signal sclr : std_logic;
signal wrreq : std_logic;
signal almost_empty : std_logic;
signal almost_full : std_logic;
signal empty : std_logic;
signal full : std_logic;
signal q : std_logic_VECTOR (7 DOWNTO 0);
signal usedw : STD_LOGIC_VECTOR (7 DOWNTO 0);
begin
scfifo_com: component fifo -- component 调用
PORT map
(
clock => clock,
data => data,
rdreq => rdreq,
sclr => sclr,
wrreq => wrreq,
almost_empty => almost_empty,
almost_full => almost_full,
empty => empty,
full => full,
q => q,
usedw => usedw
);
clock<= not clock after 10 ns;
sclr<='0';
process
begin
data<=X"00"; --- 数据初始化
rdreq<='0';
wrreq<='0';
wait for 201 ns;
for i in 0 to 255 loop -- 执行写操作,写入256个数据
wrreq<='1';
data<= conv_std_logic_vector(i, 8);
wait for 20 ns;
end loop;
wrreq<='0'; -- 停止写入
wait for 200 ns;
for i in 0 to 255 loop -- 执行读操作,读取256个数据
rdreq<='1';
wait for 20 ns;
end loop;
rdreq<='0'; -- 停止读操作
wait for 200 ns;
wait; --仿真结束
end process;
end beh;
仿真结果
如下图所示是SCFIFO的写入操作,当时钟上升沿检测到wrreq写入使能信号有效时,立刻写入数据,usedw立刻+1,empty立即拉低。

如下图所示是SCFIFO读取的操作,当时钟上升沿检测到rdreq有效时,立即输出数据到q,并且usedw的有效个数立刻改变。
(PS: 因为usedw为8位,范围从0-255,因此当输入256个数据时,usedw会从255跳变到0)

DCFIFO
调用FIFO ip核,设置参数如下图所示,其余设置默认。产生一个混合位宽的双时钟FIFO。输入16位,输出8位。输出的时候,先输出低八位,再输出高八位。


生成相应的vhdl代码之后设置testbench仿真脚本部分如下:
rdclk<= not rdclk after 5 ns;
wrclk<= not wrclk after 10 ns;
process
begin
data<=X"0000";
rdreq<='0';
wrreq<='0';
wait for 201 ns;
for i in 0 to 255 loop
wrreq<='1';
data<= conv_std_logic_vector(i+1024, 16); --- +1024 是为了观察输出高八位的值
wait for 20 ns;
end loop;
wrreq<='0';
wait for 200 ns;
for i in 0 to 255 loop
rdreq<='1';
wait for 20 ns;
end loop;
rdreq<='0';
wait for 200 ns;
wait;
end process;
仿真结果
写入数据:
当时钟上升沿检测到wrreq有效之后的下一个时钟上升沿才开始写入第一个数据,rdempty也从写入第一个数据之后的下一个时钟上升沿拉低

读取数据:
当时钟上升沿检测到rdreq有效时,立刻输出数据(先输出低八位,再高八位),但是下一个时钟上升沿rdusedw信号改变

本文介绍了FIFO的工作原理,包括单时钟和双时钟FIFO,并详细阐述了如何在Quartus II中配置和使用SCFIFO与DCFIFO。通过设置IP Catalog生成VHDL代码,并展示了SCFIFO和DCFIFO的仿真结果,说明了数据写入和读取的过程及信号变化。
1246

被折叠的 条评论
为什么被折叠?



