目录
1 复位类型
Xilinx FIFO Generator 提供了复位端口,用于复位计数器与输出寄存器。有两种复位的类型:同步复位(Synchronous Reset)和异步复位(Asynchronous Reset)。
对于同步复位方式,由于复位信号已经是同步的,因此无需设计额外的同步逻辑。
对于异步复位方式,复位信号会分别被同步到读/写时钟域,同步逻辑确保 FIFO 正确复位,避免“毛刺”或者亚稳态。
异步复位应遵循以下 2 个设计规则:
(1)复位必须在所有时钟有效时进行,否则 FIFO 的状态无法预测;
(2)复位信号的脉宽至少为 3 个慢时钟周期。
在复位期间,应避免对 fifo 进行读写操作,以防止数据丢失或损坏。在复位完成后,需要等待一段时间才能对 fifo 进行读写操作。
开启 Safety Circuit 的 FIFO,复位释放之后需至少等待 60 个慢时钟周期。
未开启 Safety Circuit 的 FIFO,复位释放之后需至少等待 30 个慢时钟周期。
2 异步 FIFO 的复位
打开 IP 核自带的 Example Design,参考激励文件异步 FIFO 的复位逻辑。
在 reset 释放之后 50 个写周期,释放 reset_ext 信号。reset 连接到 FIFO 的异步复位端口,reset_ext 则用于读/写控制逻辑的复位。
在 Example Design 的顶层文件中,将 reset_ext 信号分别同步到读/写时钟域。这里不知道是不是参考工程的错误,rst_async_rd1 ~ rst_async_rd3 使用了同步复位,异步释放的方式。
以下是根据参考工程,自己设计的异步 FIFO 的复位控制逻辑。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity eth_rx_adjust is
port(
-- System level
nRst : in std_logic;
sysclk : in std_logic;
-- GMII IN data port
--gmii_rxd_rxctl : in std_logic_vector(9 downto 0);
--gmii_rxc : in std_logic;
eth_phy_rxd : in std_logic_vector(7 downto 0);
eth_phy_rxdv : in std_logic;
eth_phy_rxc : in std_logic;
-- eth_rx data
eth_rxd_sys : out std_logic_vector(7 downto 0);
eth_rxdv_sys : out std_logic
);
end entity;
architecture behav of eth_rx_adjust is
-- internal component and signal declarations
component fifo_8bit_2048 is
port(
din : in std_logic_vector(7 downto 0);
wr_en : in std_logic;
wr_clk : in std_logic;
full : out std_logic;
dout : out std_logic_vector(7 downto 0);
rd_en : in std_logic;
rd_clk : in std_logic;
empty : out std_logic;
rst : in std_logic;
wr_data_count : out std_logic_vector(10 downto 0);
rd_data_count : out std_logic_vector(10 downto 0)
);
end component;
signal reset : std_logic := '1';
signal reset_cnt : std_logic_vector(5 downto 0) := (others => '0');
signal reset_ext_cnt : std_logic_vector(5 downto 0) := (others => '0');
signal RESET_EXT : std_logic := '1';
signal rst_async_wr1 : std_logic := '1';
signal rst_async_wr2 : std_logic := '1';
signal rst_async_wr3 : std_logic := '1';
signal rst_async_rd1 : std_logic := '1';
signal rst_async_rd2 : std_logic := '1';
signal rst_async_rd3 : std_logic := '1';
signal rst_int_wr : std_logic := '1';
signal rst_int_rd : std_logic := '1';
signal eth_fifo_wdata : std_logic_vector(7 downto 0);
signal eth_fifo_wrreq : std_logic;
signal eth_fifo_empty : std_logic;
signal eth_fifo_rcnt : std_logic_vector(10 downto 0);
signal eth_fifo_rdreq : std_logic;
signal eth_fifo_rdata : std_logic_vector(7 downto 0);
signal eth_fifo_rdvld : std_logic;
attribute ASYNC_REG: string;
attribute ASYNC_REG of rst_async_wr1: signal is "true";
attribute ASYNC_REG of rst_async_wr2: signal is "true";
attribute ASYNC_REG of rst_async_wr3: signal is "true";
attribute ASYNC_REG of rst_async_rd1: signal is "true";
attribute ASYNC_REG of rst_async_rd2: signal is "true";
attribute ASYNC_REG of rst_async_rd3: signal is "true";
---------------------------------------------------------
begin
---------------------------------------------------------
process(nRst,eth_phy_rxc)
begin
if nRst = '0' then
reset_cnt <= "000000";
elsif rising_edge(eth_phy_rxc) then
if reset_cnt < "001000" then
reset_cnt <= reset_cnt + '1';
else
reset_cnt <= reset_cnt;
end if;
end if;
end process;
process(nRst,eth_phy_rxc)
begin
if nRst = '0' then
reset <= '1';
elsif rising_edge(eth_phy_rxc) then
if reset_cnt < "001000" then
reset <= '1';
else
reset <= '0';
end if;
end if;
end process;
process(reset,eth_phy_rxc)
begin
if reset = '1' then
reset_ext_cnt <= "000000";
elsif rising_edge(eth_phy_rxc) then
if reset_ext_cnt < "110010" then
reset_ext_cnt <= reset_ext_cnt + '1';
else
reset_ext_cnt <= reset_ext_cnt;
end if;
end if;
end process;
process(reset,eth_phy_rxc)
begin
if reset = '1' then
RESET_EXT <= '1';
elsif rising_edge(eth_phy_rxc) then
if reset_ext_cnt < "110010" then
RESET_EXT <= '1';
else
RESET_EXT <= '0';
end if;
end if;
end process;
-- Asynchronous reset, synchronous release for rst_async_wr1, rst_async_wr2, rst_async_wr3
process(RESET_EXT,eth_phy_rxc)
begin
if RESET_EXT = '1' then
rst_async_wr1 <= '1';
rst_async_wr2 <= '1';
rst_async_wr3 <= '1';
elsif rising_edge(eth_phy_rxc) then
rst_async_wr1 <= RESET_EXT;
rst_async_wr2 <= rst_async_wr1;
rst_async_wr3 <= rst_async_wr2;
end if;
end process;
-- Asynchronous reset, synchronous release for rst_async_rd1, rst_async_rd2, rst_async_rd3
process(RESET_EXT,sysclk)
begin
if RESET_EXT = '1' then
rst_async_rd1 <= '1';
rst_async_rd2 <= '1';
rst_async_rd3 <= '1';
elsif rising_edge(sysclk) then
rst_async_rd1 <= RESET_EXT;
rst_async_rd2 <= rst_async_rd1;
rst_async_rd3 <= rst_async_rd2;
end if;
end process;
rst_int_wr <= rst_async_wr3;
rst_int_rd <= rst_async_rd3;
--===============================================================
-- eth_fifo_inst
eth_fifo_instx: component fifo_8bit_2048
port map(
din => eth_fifo_wdata , -- in std_logic_vector(7 downto 0)
wr_en => eth_fifo_wrreq , -- in std_logic
wr_clk => eth_phy_rxc , -- in std_logic
full => open , -- out std_logic
dout => eth_fifo_rdata , -- out std_logic_vector(7 downto 0)
rd_en => eth_fifo_rdreq , -- in std_logic
rd_clk => sysclk , -- in std_logic
empty => eth_fifo_empty , -- out std_logic
rst => reset , -- in std_logic
wr_data_count => open , -- out std_logic_vector(10 downto 0)
rd_data_count => eth_fifo_rcnt -- out std_logic_vector(10 downto 0)
);
process(rst_int_wr,eth_phy_rxc)
begin
if rst_int_wr = '1' then
eth_fifo_wdata <= (others => '0');
eth_fifo_wrreq <= '0';
elsif rising_edge(eth_phy_rxc) then
eth_fifo_wdata <= eth_phy_rxd;
eth_fifo_wrreq <= eth_phy_rxdv;
end if;
end process;
process(rst_int_rd,sysclk)
begin
if rst_int_rd = '1' then
eth_fifo_rdreq <= '0';
eth_fifo_rdvld <= '0';
elsif rising_edge(sysclk) then
if eth_fifo_rcnt > 6 then
eth_fifo_rdreq <= '1';
elsif eth_fifo_rcnt = 1 then
eth_fifo_rdreq <= '0';
end if;
eth_fifo_rdvld <= eth_fifo_rdreq;
end if;
end process;
process(rst_int_rd,sysclk)
begin
if rst_int_rd = '1' then
eth_rxd_sys <= (others => '0');
eth_rxdv_sys <= '0';
elsif rising_edge(sysclk) then
eth_rxd_sys <= eth_fifo_rdata;
eth_rxdv_sys <= eth_fifo_rdvld;
end if;
end process;
end architecture;